diff --git a/.claude/skills/web-test/SKILL.md b/.claude/skills/web-test/SKILL.md index d2e6bf7e..22ae1c22 100644 --- a/.claude/skills/web-test/SKILL.md +++ b/.claude/skills/web-test/SKILL.md @@ -57,8 +57,10 @@ node $RUN run script.js # exits when done, no session ### Interactive mode (step-by-step development) ```bash -# 1. Start session (run_in_background=true, prints JSON when ready) -node $RUN start +# 1. Start session in the background — `start` stays running as the server, so don't wait on +# its stdout. Poll `status` instead: it exits 0 only once the session is loaded and live. +node $RUN start # run_in_background=true +until node $RUN status >/dev/null 2>&1; do sleep 2; done # exit 0 = ready # 2. Execute scripts against running session cat <<'SCRIPT' | node $RUN exec - diff --git a/.claude/skills/web-test/scripts/cli/commands/status.mjs b/.claude/skills/web-test/scripts/cli/commands/status.mjs index f183629f..67656c58 100644 --- a/.claude/skills/web-test/scripts/cli/commands/status.mjs +++ b/.claude/skills/web-test/scripts/cli/commands/status.mjs @@ -1,14 +1,32 @@ -// web-test cli/commands/status v1.0 — check session +// web-test cli/commands/status v1.1 — check session (active liveness probe) // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import { existsSync, readFileSync } from 'fs'; import { out } from '../util.mjs'; -import { SESSION_FILE } from '../session.mjs'; +import { SESSION_FILE, cleanup } from '../session.mjs'; -export function cmdStatus() { +export async function cmdStatus() { if (!existsSync(SESSION_FILE)) { - out({ ok: false, message: 'No active session' }); + out({ ok: false, ready: false, message: 'No active session' }); process.exit(1); } const sess = JSON.parse(readFileSync(SESSION_FILE, 'utf-8')); - out({ ok: true, ...sess }); + // The session file is written only after connect() finished, but the server process may have + // died since (crash/reboot) and left the file behind. Don't trust the file — probe the + // in-process /status endpoint for real liveness. + try { + const resp = await fetch(`http://127.0.0.1:${sess.port}/status`, { signal: AbortSignal.timeout(2000) }); + const body = await resp.json(); + if (body.connected) { + out({ ok: true, ready: true, ...sess }); + } else { + out({ ok: false, ready: false, reason: 'browser-disconnected', ...sess }); + process.exit(1); + } + } catch { + // Server unreachable → the file is stale (process gone). Self-heal by removing it so the + // next status/start reads clean. + cleanup(); + out({ ok: false, ready: false, reason: 'server-unreachable', ...sess }); + process.exit(1); + } } diff --git a/.claude/skills/web-test/scripts/run.mjs b/.claude/skills/web-test/scripts/run.mjs index da1fef62..2600cc73 100644 --- a/.claude/skills/web-test/scripts/run.mjs +++ b/.claude/skills/web-test/scripts/run.mjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -// web-test run v1.18 — CLI entry-point (распилено по cli/) +// web-test run v1.19 — CLI entry-point (распилено по cli/) // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills /** * CLI runner for 1C web client automation. @@ -59,7 +59,7 @@ switch (cmd) { case 'exec': await cmdExec(args[0], flags); break; case 'shot': await cmdShot(args[0]); break; case 'stop': await cmdStop(); break; - case 'status': cmdStatus(); break; + case 'status': await cmdStatus(); break; case 'test': await cmdTest(rawArgs); break; default: usage(); }