Files
EJClaw/setup/verify-state.ts
2026-03-31 06:54:49 +09:00

134 lines
3.5 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import { Database } from 'bun:sqlite';
import { STORE_DIR } from '../src/config.js';
import { readEnvFile } from '../src/env.js';
import type { ServiceDef } from './service-defs.js';
import type { ServiceCheck } from './verify-services.js';
export type CredentialsStatus = 'configured' | 'missing';
export type VerifyStatus = 'success' | 'failed';
export interface RegisteredGroupsSummary {
registeredGroups: number;
groupsByAgent: Record<string, number>;
}
export interface VerifySummary extends RegisteredGroupsSummary {
status: VerifyStatus;
servicesSummary: Record<string, string>;
configuredChannels: string[];
channelAuth: Record<string, string>;
codexConfigured: boolean;
reviewConfigured: boolean;
}
export function detectCredentials(projectRoot: string): CredentialsStatus {
const envFile = path.join(projectRoot, '.env');
if (!fs.existsSync(envFile)) {
return 'missing';
}
const envContent = fs.readFileSync(envFile, 'utf-8');
return /^(CLAUDE_CODE_OAUTH_TOKEN|ANTHROPIC_API_KEY)=/m.test(envContent)
? 'configured'
: 'missing';
}
export function detectChannelAuth(
envVars = readEnvFile(['DISCORD_BOT_TOKEN']),
processEnv: NodeJS.ProcessEnv = process.env,
): Record<string, string> {
const channelAuth: Record<string, string> = {};
if (processEnv.DISCORD_BOT_TOKEN || envVars.DISCORD_BOT_TOKEN) {
channelAuth.discord = 'configured';
}
return channelAuth;
}
export function loadRegisteredGroupsSummary(
dbPath = path.join(STORE_DIR, 'messages.db'),
): RegisteredGroupsSummary {
let registeredGroups = 0;
const groupsByAgent: Record<string, number> = {};
if (!fs.existsSync(dbPath)) {
return { registeredGroups, groupsByAgent };
}
try {
const db = new Database(dbPath, { readonly: true });
const row = db
.prepare('SELECT COUNT(*) as count FROM registered_groups')
.get() as { count: number };
registeredGroups = row.count;
try {
const rows = db
.prepare(
'SELECT agent_type, COUNT(*) as count FROM registered_groups GROUP BY agent_type',
)
.all() as { agent_type: string; count: number }[];
for (const current of rows) {
groupsByAgent[current.agent_type || 'unknown'] = current.count;
}
} catch {
// agent_type column might not exist in older schema
}
db.close();
} catch {
// Table might not exist
}
return { registeredGroups, groupsByAgent };
}
export function buildVerifySummary(
services: ServiceCheck[],
serviceDefs: ServiceDef[],
credentials: CredentialsStatus,
channelAuth: Record<string, string>,
registeredGroups: number,
groupsByAgent: Record<string, number>,
): VerifySummary {
const configuredChannels = Object.keys(channelAuth);
const allConfiguredServicesRunning = services.every(
(service) => service.status === 'running',
);
const codexConfigured = serviceDefs.some(
(service) => service.kind === 'codex',
);
const reviewConfigured = serviceDefs.some(
(service) => service.kind === 'review',
);
const status =
allConfiguredServicesRunning &&
credentials === 'configured' &&
configuredChannels.length > 0 &&
registeredGroups > 0
? 'success'
: 'failed';
const servicesSummary: Record<string, string> = {};
for (const service of services) {
servicesSummary[service.name] = service.status;
}
return {
status,
servicesSummary,
configuredChannels,
channelAuth,
registeredGroups,
groupsByAgent,
codexConfigured,
reviewConfigured,
};
}