All files / src/trpc/routers system.ts

30.76% Statements 8/26
37.5% Branches 6/16
50% Functions 3/6
34.78% Lines 8/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                        11x               11x                   11x                       11x       9x       9x                   10x       10x                                                                                            
/**
 * System Router — health, status, systemHealthCheck
 */
 
import { z } from 'zod';
import { join } from 'node:path';
import { access } from 'node:fs/promises';
import type { ProcedureBuilder } from '../trpc.js';
import { requireAccountRepository, requireProjectRepository } from './_helpers.js';
import { checkAccountHealth } from '../../agent/accounts/usage.js';
import { getProjectCloneDir } from '../../git/project-clones.js';
 
export const healthResponseSchema = z.object({
  status: z.literal('ok'),
  uptime: z.number().int().nonnegative(),
  processCount: z.number().int().nonnegative(),
});
 
export type HealthResponse = z.infer<typeof healthResponseSchema>;
 
export const processInfoSchema = z.object({
  id: z.string(),
  pid: z.number().int().positive(),
  command: z.string(),
  status: z.string(),
  startedAt: z.string(),
});
 
export type ProcessInfo = z.infer<typeof processInfoSchema>;
 
export const statusResponseSchema = z.object({
  server: z.object({
    startedAt: z.string(),
    uptime: z.number().int().nonnegative(),
    pid: z.number().int().positive(),
  }),
  processes: z.array(processInfoSchema),
});
 
export type StatusResponse = z.infer<typeof statusResponseSchema>;
 
export function systemProcedures(publicProcedure: ProcedureBuilder) {
  return {
    health: publicProcedure
      .output(healthResponseSchema)
      .query(({ ctx }): HealthResponse => {
        const uptime = ctx.serverStartedAt
          ? Math.floor((Date.now() - ctx.serverStartedAt.getTime()) / 1000)
          : 0;
 
        return {
          status: 'ok',
          uptime,
          processCount: ctx.processCount,
        };
      }),
 
    status: publicProcedure
      .output(statusResponseSchema)
      .query(({ ctx }): StatusResponse => {
        const uptime = ctx.serverStartedAt
          ? Math.floor((Date.now() - ctx.serverStartedAt.getTime()) / 1000)
          : 0;
 
        return {
          server: {
            startedAt: ctx.serverStartedAt?.toISOString() ?? '',
            uptime,
            pid: process.pid,
          },
          processes: [],
        };
      }),
 
    systemHealthCheck: publicProcedure
      .query(async ({ ctx }) => {
        const uptime = ctx.serverStartedAt
          ? Math.floor((Date.now() - ctx.serverStartedAt.getTime()) / 1000)
          : 0;
 
        const accountRepo = requireAccountRepository(ctx);
        const allAccounts = await accountRepo.findAll();
        const allAgents = ctx.agentManager ? await ctx.agentManager.list() : [];
 
        const accounts = await Promise.all(
          allAccounts.map(account => checkAccountHealth(account, allAgents, ctx.credentialManager, ctx.workspaceRoot ?? undefined))
        );
 
        const projectRepo = requireProjectRepository(ctx);
        const allProjects = await projectRepo.findAll();
 
        const projects = await Promise.all(
          allProjects.map(async project => {
            let repoExists = false;
            if (ctx.workspaceRoot) {
              const clonePath = join(ctx.workspaceRoot, getProjectCloneDir(project.name, project.id));
              try { await access(clonePath); repoExists = true; } catch { repoExists = false; }
            }
            return { id: project.id, name: project.name, url: project.url, repoExists };
          })
        );
 
        return {
          server: { status: 'ok' as const, uptime, startedAt: ctx.serverStartedAt?.toISOString() ?? null },
          accounts,
          projects,
        };
      }),
  };
}