/** * A machine-global pointer to the most recent cele2e run. * * Without one, "how did my run go?" is answered by `ls -t e2e/results | head -1` * — which returns the newest directory, not YOUR run. When a run refuses to * start (a held lock, a failed preflight) that inference silently hands back the * PREVIOUS run's numbers, and a suite that never executed reads as a clean pass. * * Written at run start (so a run that dies mid-way still has a findable results * dir) and again at the end with the counts. Lives beside the run-lock rather * than in a worktree, because which checkout started the run is not something * the reader knows. */ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { homedir } from 'node:os'; import { dirname, join } from 'node:path'; export interface LastRun { runId: string; resultsDir: string; startedAt: string; /** 'running' until the suite finishes; then 'completed' or 'failed'. */ status: 'running' | 'completed' | 'failed'; total: number; passed: number; failed: number; /** Stages a failing earlier stage blocked. Distinct from real failures. */ skipped: number; durationMs: number; } export function lastRunPath(): string { return ( process.env.CELILO_E2E_LAST_RUN_PATH || join(homedir(), '.cache', 'celilo-e2e', 'last-run.json') ); } export function writeLastRun(run: LastRun): void { try { mkdirSync(dirname(lastRunPath()), { recursive: true }); writeFileSync(lastRunPath(), `${JSON.stringify(run, null, 2)}\n`); } catch { // ponytail: a bookkeeping pointer must never be the thing that fails a run. } } export function readLastRun(): LastRun | null { try { return JSON.parse(readFileSync(lastRunPath(), 'utf-8')) as LastRun; } catch { return null; } }