Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

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

Raw
import assert from "node:assert/strict";
import {
	chmodSync,
	mkdirSync,
	mkdtempSync,
	readFileSync,
	rmSync,
	writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, it } from "vitest";
import registerTheSystem from "../index.ts";
import { editorCandidates, parseEditorCommand } from "../open-editor.ts";
import { composeSystemSection, runtimeState } from "../system.ts";
import { createSystemCommand } from "../system-command.ts";
import { systemPromptFor } from "../system-prompts.ts";

const roots: string[] = [];
const temp = () => {
	const root = mkdtempSync(path.join(tmpdir(), "the-system-command-"));
	roots.push(root);
	return root;
};
const write = (root: string, relative: string, content: string) => {
	const target = path.join(root, relative);
	mkdirSync(path.dirname(target), { recursive: true });
	writeFileSync(target, content, "utf8");
};
type CapturedTool = {
	execute: (
		toolCallId: string,
		params: unknown,
		signal: undefined,
		onUpdate: undefined,
		ctx: unknown,
	) => Promise<unknown>;
};
const validSystem = (root: string) => {
	for (const directory of ["specs", "phases", "plans", "issues", "research"])
		mkdirSync(path.join(root, ".system", directory), { recursive: true });
	for (const file of ["SYSTEM.md", "MISSION.md", "RULES.md"])
		write(root, `.system/${file}`, `# ${file}\n`);
	write(root, ".system/config.json", '{"prefix":"PX","schemaVersion":0}');
	write(root, ".system/board.json", '{"schemaVersion":0,"items":{}}');
	write(
		root,
		".system/specs/PX-SPEC-SPEC0001-contract/index.md",
		[
			"---",
			"id: PX-SPEC-SPEC0001",
			"type: spec",
			"title: Contract",
			"extra:",
			"  nested: yes",
			"---",
			"",
			"# Contract",
			"",
			"> [!NOTE]",
			"> Alert body.",
			"",
			"Term",
			": Definition",
			"",
			"```mermaid",
			"flowchart TD; A-->B;",
			"```",
			"",
			"Math $x+1$.",
			"",
			"```ts",
			"const ok = true;",
			"```",
			"",
			"[Interactive prototype](./mockup-card.html)",
			"",
			"[Architecture diagram](./architecture.svg)",
			"",
			"[Walkthrough](./walkthrough.webm)",
			"",
			"[Supporting notes](./notes.md)",
			"",
			"An inline [prototype link](./mockup-card.html) stays inline.",
			"",
			"<mark>raw</mark>",
		].join("\n"),
	);
	write(
		root,
		".system/specs/PX-SPEC-SPEC0001-contract/mockup-card.html",
		"<section>Mockup card</section>",
	);
	write(
		root,
		".system/specs/PX-SPEC-SPEC0001-contract/architecture.svg",
		'<svg xmlns="http://www.w3.org/2000/svg"></svg>',
	);
	write(
		root,
		".system/specs/PX-SPEC-SPEC0001-contract/walkthrough.webm",
		"video",
	);
	write(
		root,
		".system/specs/PX-SPEC-SPEC0001-contract/notes.md",
		"# Supporting notes\n",
	);
	write(
		root,
		".system/phases/PX-PHASE-PHASE001-delivery/index.md",
		"---\nid: PX-PHASE-PHASE001\ntype: phase\ntitle: Delivery\nlabel: delivery\n---\n\n# Delivery\n",
	);
	write(
		root,
		".system/phases/PX-PHASE-PHASE002-alpha/index.md",
		"---\nid: PX-PHASE-PHASE002\ntype: phase\ntitle: Alpha\nlabel: alpha\n---\n\n# Alpha\n",
	);
	write(
		root,
		".system/plans/PX-PLAN-PLAN0001-build/index.md",
		"---\nid: PX-PLAN-PLAN0001\ntype: plan\ntitle: Build\nspec: PX-SPEC-SPEC0001\nstatus: draft\n---\n\n# Build\n",
	);
	write(
		root,
		".system/plans/PX-PLAN-PLAN0002-alpha/index.md",
		"---\nid: PX-PLAN-PLAN0002\ntype: plan\ntitle: Alpha\nspec: PX-SPEC-SPEC0001\nstatus: draft\ndepends_on: [PX-PLAN-PLAN0001]\n---\n\n# Alpha\n",
	);
};

afterEach(() => {
	for (const root of roots.splice(0))
		rmSync(root, { recursive: true, force: true });
});

describe("/system command", () => {
	it("assigns bundle migration, not machine schema updates, to the agent", () => {
		const prompt = systemPromptFor("init", "");
		assert.match(prompt, /config and board schema markers mechanically/);
		assert.match(prompt, /migrate existing bundles to schema 0/);
	});

	it("keeps MISSION outside phase authoring", () => {
		assert.match(systemPromptFor("phase", ""), /Do not mutate MISSION/);
	});

	it("requires exec to deliver complete vertical slices", () => {
		const prompt = systemPromptFor("exec", "");
		assert.match(prompt, /Load the vertical-slices skill/);
		assert.match(prompt, /thin vertical slices/);
		assert.match(prompt, /complete, observable behavior/);
		assert.match(prompt, /Do not batch work horizontally/);
		assert.match(prompt, /freshly verify each slice before starting the next/);
		assert.match(prompt, /define required outcome, not implementation order/);
		assert.match(
			prompt,
			/Re-sequence layered plan content into vertical slices/,
		);
		assert.match(prompt, /Do not pause for human approval between slices/);
	});

	it("plans behavior decomposition with visual models", () => {
		const prompt = systemPromptFor("plan", "");
		assert.match(
			prompt,
			/Decompose by observable behavior, not by architectural layer/,
		);
		assert.match(prompt, /without a layer-by-layer build order/);
		assert.match(
			prompt,
			/Model the module and interface structure, or the behavior sequence, as a diagram/,
		);
	});

	it("defaults System Markdown to visual models", () => {
		const prompt = systemPromptFor("spec", "");
		assert.match(
			prompt,
			/Model structure, sequence, state, entities, and decisions visually by default/,
		);
		assert.match(prompt, /select a format first/);
		assert.match(prompt, /Terse governs prose, not models/);
	});

	it("registers /system and defers scoped extension tools", () => {
		const commands: string[] = [];
		const tools: string[] = [];
		registerTheSystem({
			registerCommand: (name: string) => commands.push(name),
			registerTool: (tool: { name: string }) => tools.push(tool.name),
			on() {},
		} as never);
		assert.deepEqual(commands, ["system"]);
		assert.deepEqual(tools, []);
	});

	it("keeps scoped tools through clarification until their existing completion signal", async () => {
		const project = temp();
		validSystem(project);
		let activeTools = ["read"];
		let command:
			| { handler: (args: string, ctx: unknown) => Promise<void> }
			| undefined;
		let boardTool: CapturedTool | undefined;
		let boardUpdateTool: CapturedTool | undefined;
		let bundleSlotTool: CapturedTool | undefined;
		let agentSettled: ((event: unknown, ctx: unknown) => void) | undefined;
		registerTheSystem({
			registerCommand(_name: string, definition: typeof command) {
				command = definition;
			},
			registerTool(definition: { name: string }) {
				if (definition.name === "system_board_propose")
					boardTool = definition as CapturedTool;
				if (definition.name === "system_board_update")
					boardUpdateTool = definition as CapturedTool;
				if (definition.name === "system_bundle_slot")
					bundleSlotTool = definition as CapturedTool;
			},
			on(event: string, handler: (...args: never[]) => unknown) {
				if (event === "agent_settled") agentSettled = handler as never;
			},
			getActiveTools: () => activeTools,
			setActiveTools: (tools: string[]) => {
				activeTools = tools;
			},
			sendUserMessage() {},
		} as never);
		const ctx = {
			cwd: project,
			mode: "interactive",
			hasUI: false,
			isIdle: () => true,
			abort() {},
			sessionManager: {
				getSessionId: () => project,
				getBranch: () => [],
			},
			ui: {
				notify() {},
				setStatus() {},
				theme: { fg: (_color: string, text: string) => text },
			},
		};

		assert.ok(command);
		await command.handler("assess", ctx);
		assert.ok(activeTools.includes("system_board_propose"));

		agentSettled?.({}, ctx);
		assert.ok(activeTools.includes("system_board_propose"));

		assert.ok(boardTool);
		await boardTool.execute(
			"proposal",
			{
				items: [
					{
						id: "PX-SPEC-SPEC0001",
						state: "todo",
						rationale: "Implementation remains incomplete.",
					},
				],
			},
			undefined,
			undefined,
			ctx,
		);
		agentSettled?.({}, ctx);
		assert.ok(!activeTools.includes("system_board_propose"));

		assert.deepEqual(
			JSON.parse(
				readFileSync(path.join(project, ".system/board.json"), "utf8"),
			),
			{ schemaVersion: 0, items: {} },
		);

		await command.handler("exec PX-SPEC-SPEC0001", ctx);
		assert.ok(activeTools.includes("system_board_update"));
		assert.ok(!activeTools.includes("system_board_propose"));
		agentSettled?.({}, ctx);
		assert.ok(activeTools.includes("system_board_update"));
		assert.ok(boardUpdateTool);
		const updateItems = (
			items: { id: string; state: string; note: string }[],
		) => ({ items });
		await assert.rejects(
			boardUpdateTool.execute(
				"exec-invalid",
				updateItems([
					{
						id: "PX-SPEC-SPEC0001",
						state: "done",
						note: "Claimed without finished plans.",
					},
				]),
				undefined,
				undefined,
				ctx,
			),
			/cannot be done while plans remain todo/,
		);
		assert.deepEqual(
			JSON.parse(
				readFileSync(path.join(project, ".system/board.json"), "utf8"),
			),
			{ schemaVersion: 0, items: {} },
		);
		agentSettled?.({}, ctx);
		assert.ok(activeTools.includes("system_board_update"));
		await boardUpdateTool.execute(
			"exec-update",
			updateItems([
				{
					id: "PX-PLAN-PLAN0001",
					state: "done",
					note: "Slice one verified.",
				},
				{
					id: "PX-PLAN-PLAN0002",
					state: "done",
					note: "Slice two verified.",
				},
				{
					id: "PX-SPEC-SPEC0001",
					state: "done",
					note: "Fresh verification passed.",
				},
			]),
			undefined,
			undefined,
			ctx,
		);
		agentSettled?.({}, ctx);
		assert.ok(!activeTools.includes("system_board_update"));
		const applied = JSON.parse(
			readFileSync(path.join(project, ".system/board.json"), "utf8"),
		);
		assert.equal(applied.items["PX-SPEC-SPEC0001"].state, "done");
		assert.equal(applied.items["PX-SPEC-SPEC0001"].source, "agent");
		assert.equal(
			applied.items["PX-SPEC-SPEC0001"].note,
			"Fresh verification passed.",
		);

		await command.handler("spec", ctx);
		assert.ok(activeTools.includes("system_bundle_slot"));
		agentSettled?.({}, ctx);
		assert.ok(activeTools.includes("system_bundle_slot"));

		assert.ok(bundleSlotTool);
		await bundleSlotTool.execute(
			"slot-one",
			{ type: "spec", title: "First contract" },
			undefined,
			undefined,
			ctx,
		);
		assert.ok(activeTools.includes("system_bundle_slot"));
		await bundleSlotTool.execute(
			"slot-two",
			{ type: "issue", title: "Second concern" },
			undefined,
			undefined,
			ctx,
		);
		agentSettled?.({}, ctx);
		assert.ok(!activeTools.includes("system_bundle_slot"));
	});

	it("discovers vertical slicing generally and format skills only in valid projects", async () => {
		let discover: ((event: { cwd: string }) => Promise<unknown>) | undefined;
		registerTheSystem({
			registerCommand() {},
			registerTool() {},
			on(event: string, handler: (...args: never[]) => unknown) {
				if (event === "resources_discover") discover = handler as never;
			},
		} as never);
		const skills = path.resolve(import.meta.dirname, "../skills");
		const genericSkills = [path.join(skills, "vertical-slices")];
		const inactive = temp();
		assert.deepEqual(await discover?.({ cwd: inactive }), {
			skillPaths: genericSkills,
		});
		mkdirSync(path.join(inactive, ".system"));
		assert.deepEqual(await discover?.({ cwd: inactive }), {
			skillPaths: genericSkills,
		});
		const active = temp();
		validSystem(active);
		assert.deepEqual(await discover?.({ cwd: active }), {
			skillPaths: [
				...genericSkills,
				path.join(skills, "the-system-gfm"),
				path.join(skills, "the-system-tex"),
				path.join(skills, "the-system-mermaid"),
			],
		});
		write(active, ".system/config.json", '{"prefix":"PX","schemaVersion":4}');
		assert.deepEqual(await discover?.({ cwd: active }), {
			skillPaths: genericSkills,
		});
	});

	it("reports schema mismatches with schema-0 init instructions", () => {
		const project = temp();
		validSystem(project);
		write(project, ".system/config.json", '{"prefix":"PX","schemaVersion":4}');
		assert.deepEqual(runtimeState(project), {
			active: true,
			notice:
				"The System schema does not match 0; run /system init to update it.",
		});
		assert.match(
			composeSystemSection(project) ?? "",
			/Schema version 4 does not match 0; run \/system init/,
		);
	});

	it("shows an accent System status for initialized and incomplete projects", async () => {
		for (const [project, expected] of [
			[temp(), undefined],
			[temp(), "accent: ?"],
			[temp(), "accent: PX"],
			[temp(), "accent: PX · delivery"],
		] as const) {
			if (expected === "accent: ?") mkdirSync(path.join(project, ".system"));
			if (expected?.startsWith("accent: PX")) validSystem(project);
			if (expected === "accent: PX · delivery")
				write(
					project,
					".system/config.json",
					'{"prefix":"PX","schemaVersion":0,"currentPhase":"PX-PHASE-PHASE001"}',
				);
			let sessionStart: ((event: unknown, ctx: unknown) => void) | undefined;
			let resolveStatus: (value: string | undefined) => void = () => {};
			const status = new Promise<string | undefined>((resolve) => {
				resolveStatus = resolve;
			});
			registerTheSystem({
				registerCommand() {},
				registerTool() {},
				getActiveTools: () => [],
				setActiveTools() {},
				on(event: string, handler: (event: unknown, ctx: unknown) => void) {
					if (event === "session_start") sessionStart = handler;
				},
			} as never);
			sessionStart?.(
				{},
				{
					cwd: project,
					hasUI: true,
					isIdle: () => true,
					abort() {},
					sessionManager: { getSessionId: () => project },
					ui: {
						notify() {},
						setStatus(_key: string, text: string | undefined) {
							resolveStatus(text);
						},
						theme: {
							fg: (color: string, text: string) => `${color}:${text}`,
						},
					},
				},
			);
			assert.equal(await status, expected);
		}
	});

	it("refreshes the footer phase before later agent turns", async () => {
		const project = temp();
		validSystem(project);
		let sessionStart: ((event: unknown, ctx: unknown) => void) | undefined;
		let beforeAgentStart:
			| ((
					event: {
						systemPrompt: string;
						systemPromptOptions: {
							forceSystemPrompt?: string;
							sections: Record<string, string>;
						};
					},
					ctx: unknown,
			  ) => Promise<unknown>)
			| undefined;
		const statuses: (string | undefined)[] = [];
		const waiters: Array<{
			expected: string | undefined;
			resolve: () => void;
		}> = [];
		const waitForStatus = (expected: string | undefined) => {
			if (statuses.includes(expected)) return Promise.resolve();
			return new Promise<void>((resolve) =>
				waiters.push({ expected, resolve }),
			);
		};
		registerTheSystem({
			registerCommand() {},
			registerTool() {},
			getActiveTools: () => [],
			setActiveTools() {},
			on(event: string, handler: (...args: never[]) => unknown) {
				if (event === "session_start") sessionStart = handler as never;
				if (event === "before_agent_start") beforeAgentStart = handler as never;
			},
		} as never);
		const ctx = {
			cwd: project,
			hasUI: true,
			isIdle: () => true,
			abort() {},
			sessionManager: {
				getSessionId: () => project,
				getBranch: () => [],
			},
			ui: {
				notify() {},
				setStatus(_key: string, text: string | undefined) {
					statuses.push(text);
					for (const waiter of waiters)
						if (waiter.expected === text) waiter.resolve();
				},
				theme: {
					fg: (color: string, text: string) => `${color}:${text}`,
				},
			},
		};
		sessionStart?.({}, ctx);
		await waitForStatus("accent: PX");
		write(
			project,
			".system/config.json",
			'{"prefix":"PX","schemaVersion":0,"currentPhase":"PX-PHASE-PHASE001"}',
		);
		const systemPromptOptions = { sections: {} as Record<string, string> };
		await beforeAgentStart?.(
			{ systemPrompt: "BASE", systemPromptOptions },
			ctx,
		);
		assert.match(
			systemPromptOptions.sections.the_system,
			/# The System project law/,
		);
		await waitForStatus("accent: PX · delivery");
	});

	it("offers subcommand completions and help", async () => {
		const command = createSystemCommand({ sendUserMessage() {} } as never);
		assert.deepEqual(
			command.getArgumentCompletions?.("sp")?.map((item) => item.value),
			["spec", "spec-verify"],
		);
		assert.deepEqual(
			command.getArgumentCompletions?.("ed")?.map((item) => item.value),
			["edit"],
		);
		assert.deepEqual(
			command.getArgumentCompletions?.("bo")?.map((item) => item.value),
			["book", "board"],
		);
		assert.equal(command.getArgumentCompletions?.("doctor"), null);
		const notices: string[] = [];
		await command.handler("", {
			cwd: temp(),
			waitForIdle: async () => {},
			ui: { notify: (message: string) => notices.push(message) },
		} as never);
		assert.match(notices[0] ?? "", /\/system <subcommand>/);
	});

	it("opens the board directly through its runtime", async () => {
		const project = temp();
		validSystem(project);
		const notices: string[] = [];
		const command = createSystemCommand({ sendUserMessage() {} } as never, {
			openBoard: async (cwd) => {
				assert.equal(cwd, project);
				return "System board running: http://127.0.0.1:1234";
			},
		});
		await command.handler("board", {
			cwd: project,
			waitForIdle: async () => {},
			ui: { notify: (message: string) => notices.push(message) },
		} as never);
		assert.match(notices[0] ?? "", /System board running/);
	});

	it("runs init directly after confirmation", async () => {
		const project = temp();
		const command = createSystemCommand({ sendUserMessage() {} } as never);
		const notices: string[] = [];
		await command.handler("init PX", {
			cwd: project,
			waitForIdle: async () => {},
			ui: {
				confirm: async () => true,
				notify: (message: string) => notices.push(message),
			},
		} as never);
		assert.match(notices[0] ?? "", /Initialized The System/);
		assert.match(notices[0] ?? "", /\/reload to activate System format skills/);
		assert.deepEqual(
			JSON.parse(
				readFileSync(path.join(project, ".system/config.json"), "utf8"),
			),
			{ prefix: "PX", schemaVersion: 0, title: path.basename(project) },
		);
		assert.match(
			readFileSync(path.join(project, ".system/SYSTEM.md"), "utf8"),
			/Stable project identity/,
		);
	});

	it("updates machine schema mechanically, then offers agent bundle migration", async () => {
		const project = temp();
		validSystem(project);
		write(
			project,
			".system/config.json",
			'{"prefix":"PX","schemaVersion":4,"title":"Project"}',
		);
		const sent: string[] = [];
		const confirmations: string[] = [];
		let idle = false;
		let migrations = 0;
		const command = createSystemCommand(
			{ sendUserMessage: (message: string) => sent.push(message) } as never,
			{ activateBundleMigration: () => migrations++ },
		);
		await command.handler("init", {
			cwd: project,
			waitForIdle: async () => {
				idle = true;
			},
			ui: {
				confirm: async (title: string, summary: string) => {
					confirmations.push(title);
					if (title === "Initialize The System?")
						assert.match(
							summary,
							/Update: \.system\/config\.json schemaVersion 4 -> 0/,
						);
					else assert.match(summary, /Machine schema updated mechanically/);
					return true;
				},
				notify() {},
			},
		} as never);
		assert.deepEqual(confirmations, [
			"Initialize The System?",
			"Should System bundles be migrated by agent?",
		]);
		assert.equal(idle, true);
		assert.equal(migrations, 1);
		assert.match(sent[0] ?? "", /# \/system init/);
		assert.match(
			sent[0] ?? "",
			/Source: \.system\/config\.json schemaVersion 4 -> 0/,
		);
		assert.equal(
			JSON.parse(
				readFileSync(path.join(project, ".system/config.json"), "utf8"),
			).schemaVersion,
			0,
		);
	});

	it("updates board schema without offering bundle migration", async () => {
		const project = temp();
		validSystem(project);
		write(project, ".system/board.json", '{"schemaVersion":4,"items":{}}');
		const sent: string[] = [];
		const confirmations: string[] = [];
		const command = createSystemCommand({
			sendUserMessage: (message: string) => sent.push(message),
		} as never);
		await command.handler("init", {
			cwd: project,
			waitForIdle: async () => {},
			ui: {
				confirm: async (title: string) => {
					confirmations.push(title);
					return true;
				},
				notify() {},
			},
		} as never);
		assert.deepEqual(confirmations, ["Initialize The System?"]);
		assert.deepEqual(sent, []);
		assert.equal(
			JSON.parse(readFileSync(path.join(project, ".system/board.json"), "utf8"))
				.schemaVersion,
			0,
		);
	});

	it("reuses existing prefix on init rerun", async () => {
		const project = temp();
		validSystem(project);
		const notices: string[] = [];
		const command = createSystemCommand({ sendUserMessage() {} } as never);
		await command.handler("init", {
			cwd: project,
			waitForIdle: async () => {},
			ui: {
				input: async () => assert.fail("must not ask for prefix"),
				confirm: async (_title: string, summary: string) => {
					assert.match(summary, /Prefix: PX/);
					return true;
				},
				notify: (message: string) => notices.push(message),
			},
		} as never);
		assert.match(notices[0] ?? "", /Initialized The System/);
		assert.doesNotMatch(notices[0] ?? "", /\/reload/);
	});

	it("waits for board activation before sending lifecycle prompts", async () => {
		const project = temp();
		validSystem(project);
		const sent: string[] = [];
		let release: (() => void) | undefined;
		const activated = new Promise<void>((resolve) => {
			release = resolve;
		});
		const command = createSystemCommand(
			{
				sendUserMessage: (message: string) => sent.push(message),
			} as never,
			{ activateBoardProposal: () => activated },
		);

		const pending = command.handler("assess", {
			cwd: project,
			ui: { notify() {} },
		} as never);
		await Promise.resolve();
		assert.deepEqual(sent, []);
		release?.();
		await pending;
		assert.equal(sent.length, 1);
	});

	it("injects lifecycle prompts and activates bundle allocation", async () => {
		const project = temp();
		validSystem(project);
		const sent: string[] = [];
		let activations = 0;
		let proposalRuns = 0;
		let updateRuns = 0;
		const command = createSystemCommand(
			{
				sendUserMessage: (message: string) => sent.push(message),
			} as never,
			{
				activateBundleTool: () => activations++,
				activateBoardProposal: () => proposalRuns++,
				activateBoardUpdate: () => updateRuns++,
			},
		);
		for (const subcommand of [
			"research",
			"spec",
			"spec-verify",
			"assess",
			"phase",
			"plan",
			"issue",
			"exec",
		])
			for (const instruction of ["", "login flow"])
				await command.handler(`${subcommand} ${instruction}`, {
					cwd: project,
					waitForIdle: async () =>
						assert.fail("lifecycle command must not wait"),
					ui: { notify() {} },
				} as never);
		for (const message of sent) {
			assert.match(message, /The System document contract/);
			assert.match(message, /# The System board state/);
			assert.match(message, /PX-SPEC-SPEC0001 · Contract · todo · default/);
		}
		assert.equal(activations, 10);
		assert.equal(proposalRuns, 2);
		assert.equal(updateRuns, 2);
		assert.doesNotMatch(sent.join("\n"), /Extension-generated bundle slot/);
		const execPrompt =
			sent.find((item) => item.includes("# /system exec")) ?? "";
		assert.match(execPrompt, /spec\+plan/);
		assert.match(execPrompt, /call system_board_update exactly once/);
		assert.match(execPrompt, /The System board contract/);
		assert.match(execPrompt, /recorded with source agent/);
		const assessPrompt =
			sent.find((item) => item.includes("# /system assess")) ?? "";
		assert.match(
			assessPrompt,
			/Submit the assessment through system_board_propose/,
		);
		assert.doesNotMatch(assessPrompt, /empty items list/);
		const phasePrompt =
			sent.find((item) => item.includes("# /system phase\n")) ?? "";
		assert.match(phasePrompt, /project-wide operating phase/);
		assert.match(phasePrompt, /config currentPhase/);
		assert.doesNotMatch(phasePrompt, /large specs/);
		const specPrompt =
			sent.find(
				(item) =>
					item.includes("# /system spec\n") && item.includes("login flow"),
			) ?? "";
		assert.match(specPrompt, /login flow/);
		assert.match(specPrompt, /a prose-only spec is incomplete/);
		assert.match(specPrompt, /Use mockups for visual elements/);
		assert.match(specPrompt, /Persist accepted visual assets/);
		assert.match(
			specPrompt,
			/required local dependencies inside the spec bundle/,
		);
		assert.match(
			specPrompt,
			/encode accepted feedback as behavior and constraints/,
		);
		assert.match(
			sent.find((item) => item.endsWith("before writing.")) ?? "",
			/No instructions were supplied/,
		);
	});

	it("keeps print-mode lifecycle commands alive through the generated turn", async () => {
		const order: string[] = [];
		const command = createSystemCommand({
			sendUserMessage: () => order.push("send"),
		} as never);
		await command.handler("spec explain only", {
			cwd: temp(),
			mode: "json",
			waitForIdle: async () => {
				order.push("settled");
			},
			ui: { notify() {} },
		} as never);
		assert.deepEqual(order, ["send", "settled"]);
	});

	it("runs doctor directly and renders rich browser view/book files", async () => {
		const project = temp();
		validSystem(project);
		const command = createSystemCommand({ sendUserMessage() {} } as never);
		const notices: string[] = [];
		const severities: string[] = [];
		let prompts = 0;
		let widgets = 0;
		const ctx = {
			cwd: project,
			hasUI: true,
			waitForIdle: async () => {},
			ui: {
				confirm: async () => {
					prompts += 1;
					return true;
				},
				notify: (message: string, severity: string) => {
					notices.push(message);
					severities.push(severity);
				},
				setWidget: () => {
					widgets += 1;
				},
			},
		} as never;
		await command.handler("doctor", ctx);
		await command.handler("view PX-SPEC-SPEC0001", ctx);
		await command.handler("book", ctx);
		await command.handler("view PX-SPEC-SPEC0001 extra", ctx);
		await command.handler("edit PX-SPEC-SPEC0001 extra", ctx);
		assert.match(notices[0] ?? "", /OK/);
		assert.equal(severities[0], "info");
		assert.equal(prompts, 0);
		assert.equal(widgets, 0);
		assert.match(notices[1] ?? "", /System view written:/);
		assert.match(notices[1] ?? "", /Open: file:\/\//);
		assert.match(notices[2] ?? "", /System book written:/);
		assert.match(notices[3] ?? "", /Usage: \/system view/);
		assert.match(notices[4] ?? "", /Usage: \/system edit/);
		const view = readFileSync(pathFromNotice(notices[1] ?? ""), "utf8");
		const docs = readFileSync(pathFromNotice(notices[2] ?? ""), "utf8");
		assert.match(view, /class="system-article"/);
		assert.match(
			view,
			/<h1 id="PX-SPEC-SPEC0001-contract"><a href="#PX-SPEC-SPEC0001-contract">Contract<\/a><\/h1>/,
		);
		assert.match(view, /<summary>Metadata<\/summary>/);
		assert.match(view, /nested/);
		assert.doesNotMatch(view, /On this page/);
		assert.match(view, /class="mermaid"/);
		assert.match(view, /mjx-container/);
		assert.match(view, /hljs/);
		assert.match(
			view,
			/<iframe src="file:\/\/.*mockup-card\.html" loading="lazy" title="Interactive prototype"><\/iframe>/,
		);
		assert.doesNotMatch(view, /<iframe[^>]+sandbox/);
		assert.match(
			view,
			/<img src="file:\/\/.*architecture\.svg" alt="Architecture diagram" loading="lazy">/,
		);
		assert.match(
			view,
			/<video controls preload="metadata"><source src="file:\/\/.*walkthrough\.webm">/,
		);
		assert.match(view, /href="file:\/\/.*notes\.md">Supporting notes<\/a>/);
		assert.doesNotMatch(view, /notes\.html/);
		assert.match(
			view,
			/An inline <a href="file:\/\/.*mockup-card\.html">prototype link<\/a> stays inline\./,
		);
		assert.match(view, /class="visual-asset-preview visual-asset-html"/);
		assert.match(view, /class="visual-asset-preview visual-asset-image"/);
		assert.match(view, /class="visual-asset-preview visual-asset-video"/);
		assert.match(view, /<mark>raw<\/mark>/);
		assert.match(docs, /the-system-command-.* Dossier/);
		assert.match(docs, /<section id="PX-SPEC-SPEC0001" class="book-section">/);
		assert.match(docs, /class="book-top"/);
		assert.match(docs, /class="book-nav"/);
		assert.match(docs, /class="mobile-nav"/);
		assert.match(docs, /class="nav-utils"/);
		assert.doesNotMatch(docs, /<aside class="book-toc"/);
		assert.match(docs, /id="search"/);
		assert.doesNotMatch(docs, /0 diagnostics/);
		assert.match(docs, /rel="icon"/);
		assert.match(docs, /data-search-hit/);
		assert.match(docs, /MiniSearch/);
		assert.doesNotMatch(view, /<nav class="doc-move"/);
		assert.match(docs, /CORE-SYSTEM/);
		assert.match(docs, /Reference graph/);
		assert.match(docs, /System reference graph/);
		assert.match(docs, /href="#PX-SPEC-SPEC0001"/);
		assert.doesNotMatch(
			docs,
			/href="file:[^"]*PX-SPEC-SPEC0001[^"]*index\.html"/,
		);
		assert.match(docs, /data-graph-svg/);
		assert.match(docs, /data-graph-zoom="reset"/);
		assert.match(docs, /pointerdown/);
		assert.match(docs, /wheel/);
		assert.match(docs, /Backlinks/);
		assert.match(docs, /Referenced by/);
		assert.match(docs, /PX-PLAN-PLAN0001/);
		assert.match(docs, /doc-related/);
		assert.match(docs, /#ededed/);
		assert.match(docs, /#121212/);
		assert.match(docs, /prefers-color-scheme:dark/);
		assert.match(docs, /PX-PHASE-PHASE001/);
		assert.doesNotMatch(docs, /after PX-PHASE/);
		assert.ok(
			docs.indexOf('<section id="PX-PHASE-PHASE002"') <
				docs.indexOf('<section id="PX-PHASE-PHASE001"'),
		);
		assert.ok(
			docs.indexOf('<section id="PX-PHASE-PHASE001"') <
				docs.indexOf('<section id="PX-SPEC-SPEC0001"'),
		);
		assert.ok(
			docs.indexOf('<section id="PX-PLAN-PLAN0001"') <
				docs.indexOf('<section id="PX-PLAN-PLAN0002"'),
		);
		assert.match(docs, /spec/);
		assert.match(docs, /class="system-article"/);
	});

	it("opens documents in VISUAL, EDITOR, or a platform editor", async () => {
		const project = temp();
		validSystem(project);
		const editor = path.join(project, "editor.cjs");
		const log = path.join(project, "editor.log");
		writeFileSync(
			editor,
			`const { writeFileSync } = require("node:fs"); writeFileSync(process.argv[2], process.argv.slice(3).join("\\n"));`,
			"utf8",
		);
		chmodSync(editor, 0o755);
		const previousVisual = process.env.VISUAL;
		const previousEditor = process.env.EDITOR;
		process.env.VISUAL = `${JSON.stringify(process.execPath)} ${JSON.stringify(editor)} ${JSON.stringify(log)}`;
		delete process.env.EDITOR;
		try {
			const command = createSystemCommand({ sendUserMessage() {} } as never);
			const notices: string[] = [];
			await command.handler("edit contract", {
				cwd: project,
				waitForIdle: async () => {},
				ui: { notify: (message: string) => notices.push(message) },
			} as never);
			assert.match(notices[0] ?? "", /System document opened:/);
			assert.equal(
				readFileSync(log, "utf8"),
				path.join(project, ".system/specs/PX-SPEC-SPEC0001-contract/index.md"),
			);
		} finally {
			if (previousVisual === undefined) delete process.env.VISUAL;
			else process.env.VISUAL = previousVisual;
			if (previousEditor === undefined) delete process.env.EDITOR;
			else process.env.EDITOR = previousEditor;
		}
	});
});

describe("editor opening", () => {
	it("parses quoted editor commands and falls back cross-platform", () => {
		assert.deepEqual(parseEditorCommand('code --wait "two words"'), {
			command: "code",
			args: ["--wait", "two words"],
		});
		assert.deepEqual(
			parseEditorCommand(
				'"C:\\Program Files\\Editor\\edit.exe" "C:\\work tree\\file.md"',
			),
			{
				command: "C:\\Program Files\\Editor\\edit.exe",
				args: ["C:\\work tree\\file.md"],
			},
		);
		assert.deepEqual(
			editorCandidates("file.md", { VISUAL: "v", EDITOR: "e" }, "linux").slice(
				0,
				2,
			),
			[
				{ command: "v", args: ["file.md"], wait: true },
				{ command: "e", args: ["file.md"], wait: true },
			],
		);
		assert.deepEqual(editorCandidates("file.md", {}, "win32").at(0), {
			command: "notepad.exe",
			args: ["file.md"],
			wait: false,
		});
		assert.deepEqual(
			editorCandidates("file.md", { TERMUX_VERSION: "0.118" }, "android").at(0),
			{
				command: "termux-open",
				args: ["file.md"],
				wait: false,
			},
		);
	});
});

function pathFromNotice(notice: string): string {
	const match = notice.match(/written: (.*)$/m);
	assert.ok(match?.[1]);
	return match[1];
}