Files
brain/tools/verdict-surface-store.mjs
T

54 lines
2.1 KiB
JavaScript

#!/usr/bin/env node
/** verdict-surface-store — пер-сессионный транзиентный стор вердиктов + pending-ack маркер (SP1).
* Fail-quiet: любая ошибка → безопасный no-op/пусто. Дефолт baseDir = ~/.claude/runtime. */
import { homedir } from 'node:os';
import { join } from 'node:path';
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
function baseOf(baseDir) { return baseDir || join(homedir(), '.claude', 'runtime'); }
function queuePath(sid, baseDir) { return join(baseOf(baseDir), `verdict-surface-${sid || 'unknown'}.json`); }
function ackPath(sid, baseDir) { return join(baseOf(baseDir), `verdict-pending-ack-${sid || 'unknown'}.json`); }
function readJson(p) { try { return JSON.parse(readFileSync(p, 'utf8')); } catch { return null; } }
function ensureDir(p) { try { mkdirSync(baseOf(p), { recursive: true }); } catch {} }
export function pushVerdict(sid, obj, baseDir) {
try {
ensureDir(baseDir);
const p = queuePath(sid, baseDir);
let arr = existsSync(p) ? readJson(p) : [];
if (!Array.isArray(arr)) arr = [];
arr.push(obj);
writeFileSync(p, JSON.stringify(arr));
return true;
} catch { return false; }
}
export function drainVerdicts(sid, baseDir) {
try {
const p = queuePath(sid, baseDir);
if (!existsSync(p)) return [];
const arr = readJson(p);
try { writeFileSync(p, '[]'); } catch {}
return Array.isArray(arr) ? arr : [];
} catch { return []; }
}
export function markSurfaced(sid, outcomes, baseDir) {
try { ensureDir(baseDir); writeFileSync(ackPath(sid, baseDir), JSON.stringify(outcomes || [])); return true; }
catch { return false; }
}
export function readPendingAck(sid, baseDir) {
try {
const p = ackPath(sid, baseDir);
if (!existsSync(p)) return null;
const v = readJson(p);
return Array.isArray(v) ? v : null;
} catch { return null; }
}
export function clearPendingAck(sid, baseDir) {
try { const p = ackPath(sid, baseDir); if (existsSync(p)) writeFileSync(p, 'null'); return true; }
catch { return false; }
}