mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-06-04 10:14:47 +08:00
1b08b58fcd
- verify: remove the CLI ping; cli-agent step earlier in setup already proved the round-trip works, and the test agent gets cleaned up before verify runs — so the ping was guaranteed to fail on installs that wired a messaging app instead of staying CLI-only. Status now collapses to service-running ∧ credentials ∧ ≥1 wired group. - agent-ping: catch Claude Code's "Please run /login" / "Not logged in" / "Invalid API key" banners so a successfully-spawned agent that has no credentials no longer reports as 'ok'. - auth paste: validate the full sk-ant-oat…AA shape; when the cleaned input is under 90 chars, surface a truncation-specific hint pointing at terminal wrap as the likely cause. Strip internal whitespace at both validate and assignment so multi-line pastes that survive clack also go through cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
70 lines
2.1 KiB
TypeScript
70 lines
2.1 KiB
TypeScript
/**
|
|
* Round-trip check against the CLI Unix socket.
|
|
*
|
|
* Shared by `setup/verify.ts` (end-of-run health check) and `setup/auto.ts`
|
|
* (confirm the freshly-wired agent actually responds before prompting the
|
|
* user to chat with it).
|
|
*
|
|
* Exit-code contract follows `scripts/chat.ts`:
|
|
* 0 → got a reply on stdout
|
|
* 2 → socket unreachable (service not running or wrong checkout)
|
|
* 3 → no reply before chat.ts's own 120s hard stop
|
|
* This wrapper also guards with its own timeout in case chat.ts hangs.
|
|
*/
|
|
import { spawn } from 'child_process';
|
|
|
|
export type PingResult = 'ok' | 'no_reply' | 'socket_error' | 'auth_error';
|
|
|
|
export function classifyPingResult(exitCode: number | null, stdout: string, stderr = ''): PingResult {
|
|
const output = `${stdout}\n${stderr}`;
|
|
if (
|
|
/Invalid bearer token/i.test(output) ||
|
|
/authentication[_ ]error/i.test(output) ||
|
|
/Failed to authenticate/i.test(output) ||
|
|
/Please run \/login/i.test(output) ||
|
|
/Not logged in/i.test(output) ||
|
|
/Invalid API key/i.test(output)
|
|
) {
|
|
return 'auth_error';
|
|
}
|
|
if (exitCode === 2) return 'socket_error';
|
|
if (exitCode === 0 && stdout.trim().length > 0) return 'ok';
|
|
return 'no_reply';
|
|
}
|
|
|
|
export function pingCliAgent(timeoutMs = 30_000): Promise<PingResult> {
|
|
return new Promise((resolve) => {
|
|
const child = spawn('pnpm', ['run', 'chat', 'ping'], {
|
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
});
|
|
let stdout = '';
|
|
let stderr = '';
|
|
let settled = false;
|
|
const timer = setTimeout(() => {
|
|
if (settled) return;
|
|
settled = true;
|
|
child.kill('SIGKILL');
|
|
resolve('no_reply');
|
|
}, timeoutMs);
|
|
|
|
child.stdout.on('data', (chunk: Buffer) => {
|
|
stdout += chunk.toString('utf-8');
|
|
});
|
|
child.stderr.on('data', (chunk: Buffer) => {
|
|
stderr += chunk.toString('utf-8');
|
|
});
|
|
child.on('close', (code) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
clearTimeout(timer);
|
|
resolve(classifyPingResult(code, stdout, stderr));
|
|
});
|
|
child.on('error', () => {
|
|
if (settled) return;
|
|
settled = true;
|
|
clearTimeout(timer);
|
|
resolve('socket_error');
|
|
});
|
|
});
|
|
}
|