mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-06-12 18:11:51 +08:00
72b7a72cbb
Round-trip confirmation before first chat. After cli-agent wires up the Terminal Agent, send `chat ping` through the CLI socket under a spinner with 30s timeout (shared helper in setup/lib/agent-ping.ts, also used by verify). Only after a real reply do we show "Your assistant is ready." and enter the chat loop. Ping failures surface a targeted note (socket_error vs no_reply) and skip the prompt — so users never type into the void. Checkout-mismatch detection. verify resolves the running service PID's script path via `ps -p <pid> -o command=` and compares to projectRoot. If the service is running from a sibling clone (common for developers with multiple checkouts), SERVICE comes back as running_other_checkout instead of running, AGENT_PING is skipped, and the failure note tells the user exactly which bootout + bootstrap pair to run. Native Claude Code install on demand. Only the subscription auth path needs `claude`; the paste-token and paste-API-key paths don't. So register-claude-token.sh now runs setup/install-claude.sh when `claude` is missing (curl -fsSL https://claude.ai/install.sh | bash), then prepends ~/.local/bin to PATH in-process so the rest of the script can see the fresh binary. Gutter-safe wrapping. wrapForGutter + dimWrap in lib/theme.ts hard-wrap text to `process.stdout.columns - gutter` on word boundaries, measuring visible length (ANSI-stripped). dimWrap applies the dim envelope per line because clack resets styling at each line break when rendering multi-line log content — a single outer dim() only colors the first line. Applied to the long "why" notes before container + onecli, the channel-skip info, the ping-failure note, and the checkout-mismatch remediation. Wordmark anchoring. printIntro always includes the NanoClaw wordmark in the clack intro line, whether or not nanoclaw.sh already printed one in bash. Worth ~1 line of redundancy so the brand stays visible at the top of the clack session after bootstrap output scrolls out. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
51 lines
1.5 KiB
TypeScript
51 lines
1.5 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';
|
|
|
|
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 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.on('close', (code) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
clearTimeout(timer);
|
|
if (code === 2) resolve('socket_error');
|
|
else if (code === 0 && stdout.trim().length > 0) resolve('ok');
|
|
else resolve('no_reply');
|
|
});
|
|
child.on('error', () => {
|
|
if (settled) return;
|
|
settled = true;
|
|
clearTimeout(timer);
|
|
resolve('socket_error');
|
|
});
|
|
});
|
|
}
|