#!/usr/bin/env node /** * verdict-wait — read-only сторож видимости «всё в лоб». Ждёт ПО ЭТАПАМ, пока стадия снимка не * «осядет» (status !== pending), с ранним возвратом: лёг за 30с → вернул за 30с; иначе таймаут НА * ЭТАП (до 5 мин). Ничего не мутирует (только чтение снимка). fail-quiet. * CLI: node verdict-wait.mjs [timeoutMs]. Запускать в фоне (run_in_background) — * выход = доставка исхода стадии разработчику. */ import { readSnapshot } from './verdict-surface-store.mjs'; /** Стадия «осела» — есть запись и статус не pending (терминальный исход). */ export function isStageSettled(snapshotMap, stage) { const r = snapshotMap && snapshotMap[stage]; return !!(r && r.status && r.status !== 'pending'); } /** Человекочитаемая сводка по стадии — для доставки в лицо. */ export function formatWaitResult(snapshotMap, stage) { const r = (snapshotMap && snapshotMap[stage]) || null; if (!r) return `[verdict-wait] ${stage}: нет записи (этап не стартовал)`; if (r.status === 'pending') return `[verdict-wait] ${stage}: ещё печётся (pending)`; return `[verdict-wait] ${stage}: ${r.status}${r.reason ? ` — ${r.reason}` : ''}`; } async function main() { const [hash, stage, timeoutArg] = process.argv.slice(2); const sid = process.env.CLAUDE_SESSION_ID || 'unknown'; const timeoutMs = Math.min(Number(timeoutArg) || 300000, 300000); // предел НА ЭТАП — до 5 мин const stepMs = 2000; let waited = 0; for (;;) { let snap = {}; try { snap = readSnapshot(sid, hash); } catch { snap = {}; } if (isStageSettled(snap, stage)) { process.stdout.write(formatWaitResult(snap, stage) + '\n'); return; } if (waited >= timeoutMs) { process.stdout.write(`[verdict-wait] ${stage}: таймаут ${timeoutMs}ms — этап не осел\n`); return; } await new Promise((res) => setTimeout(res, stepMs)); waited += stepMs; } } import { fileURLToPath } from 'node:url'; const isCli = process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]; if (isCli) main();