clawdie-ai/setup/verify.ts
2026-03-07 23:08:14 +01:00

124 lines
3.4 KiB
TypeScript

/**
* Step: verify — End-to-end health check of the full installation.
* Replaces 09-verify.sh
*
* Uses better-sqlite3 directly (no sqlite3 CLI), platform-aware service checks.
*/
import { execSync } from 'child_process';
import fs from 'fs';
import os from 'os';
import path from 'path';
import Database from 'better-sqlite3';
import { STORE_DIR } from '../src/config.js';
import { logger } from '../src/logger.js';
import { getPlatform } from './platform.js';
import { emitStatus } from './status.js';
export async function run(_args: string[]): Promise<void> {
const projectRoot = process.cwd();
const platform = getPlatform();
const homeDir = os.homedir();
logger.info('Starting verification');
// 1. Check service status
let service = 'not_found';
const pidFile = path.join(projectRoot, 'clawdie.pid');
if (fs.existsSync(pidFile)) {
try {
const pid = fs.readFileSync(pidFile, 'utf-8').trim();
if (pid) {
execSync(`kill -0 ${pid}`, { stdio: 'ignore' });
service = 'running';
}
} catch {
service = 'stopped';
}
}
logger.info({ service }, 'Service status');
// 2. Check jail runtime tools
let jailRuntime = 'missing';
try {
execSync('command -v jexec', { stdio: 'ignore' });
execSync('command -v jls', { stdio: 'ignore' });
jailRuntime = 'available';
} catch {
// No jail toolchain
}
// 3. Check credentials
let credentials = 'missing';
const envFile = path.join(projectRoot, '.env');
if (fs.existsSync(envFile)) {
const envContent = fs.readFileSync(envFile, 'utf-8');
if (
/^(ANTHROPIC_API_KEY|OPENAI_API_KEY|AZURE_OPENAI_API_KEY|GEMINI_API_KEY|GROQ_API_KEY|CEREBRAS_API_KEY|XAI_API_KEY|OPENROUTER_API_KEY|AI_GATEWAY_API_KEY|ZAI_API_KEY|MISTRAL_API_KEY|MINIMAX_API_KEY|OPENCODE_API_KEY|KIMI_API_KEY|AWS_BEARER_TOKEN_BEDROCK|AWS_ACCESS_KEY_ID)=/m.test(
envContent,
)
) {
credentials = 'configured';
}
}
// 4. Check Telegram bot configuration
let telegramAuth = 'not_configured';
if (fs.existsSync(envFile)) {
const envContent = fs.readFileSync(envFile, 'utf-8');
if (/^TELEGRAM_BOT_TOKEN=.+/m.test(envContent)) {
telegramAuth = 'configured';
}
}
// 5. Check registered groups (using better-sqlite3, not sqlite3 CLI)
let registeredGroups = 0;
const dbPath = path.join(STORE_DIR, 'messages.db');
if (fs.existsSync(dbPath)) {
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;
db.close();
} catch {
// Table might not exist
}
}
// 6. Check mount allowlist
let mountAllowlist = 'missing';
if (
fs.existsSync(
path.join(homeDir, '.config', 'clawdie-cp', 'mount-allowlist.json'),
)
) {
mountAllowlist = 'configured';
}
// Determine overall status
const status =
service === 'running' &&
credentials !== 'missing' &&
telegramAuth !== 'not_configured' &&
registeredGroups > 0
? 'success'
: 'failed';
logger.info({ status }, 'Verification complete');
emitStatus('VERIFY', {
SERVICE: service,
JAIL_RUNTIME: jailRuntime,
CREDENTIALS: credentials,
TELEGRAM_AUTH: telegramAuth,
REGISTERED_GROUPS: registeredGroups,
MOUNT_ALLOWLIST: mountAllowlist,
STATUS: status,
LOG: 'logs/setup.log',
});
if (status === 'failed') process.exit(1);
}