Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

extensions/the-system/__tests__/board-runtime.test.ts

Raw
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/);
	});
});