import assert from "node:assert/strict"; import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { test } from "node:test"; import { goalDisplay, goalDetails } from "../lib/display.ts"; import { initialState, setGoal, pauseGoal, blockGoal, resumeGoal, completeGoal, clearGoal } from "../lib/state.ts"; import { saveState, loadState } from "../lib/store.ts"; const text = "Long goal\n" + "Full acceptance criteria, never truncate. ".repeat(100) + "\nEND-OF-GOAL"; test("footer maps each lifecycle state to text and a theme role", () => { const active = setGoal(initialState(), text); for (const [state, label, color] of [ [initialState(), "None", "muted"], [active, "Active", "accent"], [{ ...active, activeWait: { owner: "reviewer" } }, "Waiting", "warning"], [{ ...active, activeWait: { owner: "reviewer", wakeSent: true } }, "Active", "accent"], [pauseGoal(active, "operator stop"), "Paused", "warning"], [pauseGoal(active, "blocked: legacy reason"), "Blocked", "error"], [blockGoal(active, "missing permission"), "Blocked", "error"], [completeGoal(active, "verified"), "Complete", "success"], ] as const) assert.deepEqual(goalDisplay(state), { label, color }); }); test("full multiline goal survives completion, persistence, and read-only recall", () => { const dir = mkdtempSync(join(tmpdir(), "goal-display-")); try { const active = setGoal(initialState(), text); const complete = completeGoal(active, "verified ".repeat(300)); assert.equal(complete.lastOutcome?.text, text); assert.equal(complete.lastOutcome?.evidence.length, 1000); assert.equal(complete.status, "none"); assert.deepEqual(resumeGoal(complete), complete); const path = join(dir, "state.json"); saveState(complete, path); assert.deepEqual(loadState(path), complete); for (const state of [active, blockGoal(active, "denied"), pauseGoal(active, "stop"), loadState(path)]) { const before = JSON.stringify(state); assert.ok(goalDetails(state).includes(text)); assert.equal(JSON.stringify(state), before); } assert.equal(goalDisplay(clearGoal(complete)).label, "None"); assert.equal(setGoal(complete, "replacement").lastOutcome, undefined); assert.equal(resumeGoal(blockGoal(active, "denied")).status, "active"); } finally { rmSync(dir, { recursive: true, force: true }); } }); test("old records and malformed outcome fields are safe to recall", () => { const dir = mkdtempSync(join(tmpdir(), "goal-display-")); const path = join(dir, "state.json"); try { const old = pauseGoal(setGoal(initialState(), text), "blocked: legacy"); saveState(old, path); assert.equal(goalDisplay(loadState(path)).label, "Blocked"); for (const lastOutcome of [null, {}, { status: "complete", text: 123 }, { status: "complete", text, evidence: "yes", at: "invalid" }]) { saveState({ ...initialState(), lastOutcome } as any, path); assert.equal(goalDisplay(loadState(path)).label, "None"); assert.doesNotThrow(() => goalDetails(loadState(path))); } saveState({ ...old, pausedReason: {} } as any, path); assert.doesNotThrow(() => goalDetails(loadState(path))); assert.doesNotThrow(() => goalDetails({ ...setGoal(initialState(), text), activeWait: { owner: "test", deadlineAt: 1e100 } })); } finally { rmSync(dir, { recursive: true, force: true }); } });