import assert from "node:assert/strict"; import { initTheme } from "@earendil-works/pi-coding-agent"; import { beforeAll, describe, it } from "vitest"; import { createBoardRuntime } from "../board-runtime.ts"; const theme = { fg: (_style: string, text: string) => text, bold: (text: string) => text, } as never; const render = (component: { render(width: number): string[] }) => component.render(120).join("\n"); const renderContext = (expanded: boolean, lastComponent?: unknown) => ({ expanded, lastComponent, isError: false }) as never; const items = [ { id: "PX-SPEC-SPEC0001", state: "todo" as const, rationale: "Acceptance remains incomplete.", }, { id: "PX-ISSUE-ISSUE001", state: "done" as const, rationale: "Regression coverage proves closure.", }, ]; beforeAll(() => initTheme("default", false)); describe("system_board_propose", () => { it("uses concise prompt metadata", () => { const tool = createBoardRuntime().tool; assert.equal(tool.label, "system_board_propose"); assert.equal( tool.promptSnippet, "Propose System board states for human review", ); assert.notEqual(tool.promptSnippet, tool.description); assert.match(tool.description, /does not modify \.system\/board\.json/); assert.deepEqual(tool.promptGuidelines, [ "During /system assess, call system_board_propose exactly once with evidence-backed state changes; use an empty items list when no changes are justified.", ]); }); it("describes the exec update tool as an applying board writer", () => { const tool = createBoardRuntime().updateTool; assert.equal(tool.label, "system_board_update"); assert.equal( tool.promptSnippet, "Update System board states from verified work", ); assert.match(tool.description, /Apply verified board states/); assert.deepEqual(tool.promptGuidelines, [ "After fresh verification in /system exec, call system_board_update exactly once with the states your work proves; use an empty items list when no change is justified.", ]); assert.ok(tool.renderCall); const call = render( tool.renderCall( { items: [ { id: "PX-PLAN-PLAN0001", state: "done", note: "Slice verified by test run.", }, ], }, theme, renderContext(true), ), ); assert.match(call, /^system_board_update 1 item/); assert.match(call, /DONE PX-PLAN-PLAN0001/); assert.match(call, /Slice verified by test run\./); assert.ok(tool.renderResult); assert.equal( render( tool.renderResult( { content: [], details: { items: [] } }, { expanded: false, isPartial: false }, theme, renderContext(false), ), ).trimEnd(), "✓ no board changes", ); assert.equal( render( tool.renderResult( { content: [], details: { items } }, { expanded: false, isPartial: false }, theme, renderContext(false), ), ).trimEnd(), "✓ 2 board changes applied", ); }); it("keeps proposal details behind expansion and renders errors", () => { const tool = createBoardRuntime().tool; assert.ok(tool.renderCall); const collapsedCallComponent = tool.renderCall( { items }, theme, renderContext(false), ); const collapsedCall = render(collapsedCallComponent); const expandedCallComponent = tool.renderCall( { items }, theme, renderContext(true, collapsedCallComponent), ); const expandedCall = render(expandedCallComponent); assert.equal(expandedCallComponent, collapsedCallComponent); assert.match(collapsedCall, /^system_board_propose 2 items/); assert.match(collapsedCall, /to expand/); assert.doesNotMatch(collapsedCall, /Acceptance remains incomplete/); assert.match(expandedCall, /TODO PX-SPEC-SPEC0001/); assert.match(expandedCall, /Acceptance remains incomplete/); assert.ok(tool.renderResult); const result = { content: [], details: { items } }; const collapsedResultComponent = tool.renderResult( result, { expanded: false, isPartial: false }, theme, renderContext(false), ); const collapsedResult = render(collapsedResultComponent); const expandedResultComponent = tool.renderResult( result, { expanded: true, isPartial: false }, theme, renderContext(true, collapsedResultComponent), ); const expandedResult = render(expandedResultComponent); assert.equal(expandedResultComponent, collapsedResultComponent); assert.equal(collapsedResult.trimEnd(), "✓ 2 changes proposed"); assert.equal(expandedResult.trimEnd(), "✓ 2 changes proposed"); const empty = render( tool.renderResult( { content: [], details: { items: [] } }, { expanded: false, isPartial: false }, theme, renderContext(false), ), ); assert.equal(empty.trimEnd(), "✓ no changes proposed"); const errorResult = { content: [ { type: "text", text: "proposal failed\nEND-PROPOSAL-DETAILS" }, ], }; const error = render( tool.renderResult( errorResult, { expanded: false, isPartial: false }, theme, { ...renderContext(false), isError: true } as never, ), ); const expandedError = render( tool.renderResult( errorResult, { expanded: true, isPartial: false }, theme, { ...renderContext(true), isError: true } as never, ), ); assert.match(error, /^proposal failed/); assert.match(error, /to expand/); assert.doesNotMatch(error, /END-PROPOSAL-DETAILS/); assert.match(expandedError, /END-PROPOSAL-DETAILS/); }); });