Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

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

Raw
import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { createTestSession, type TestSession } from "../../../test/harness";
import { applyInitialization } from "../init.ts";

describe("the-system pi-test-harness", () => {
	let t: TestSession | undefined;

	afterEach(() => {
		t?.dispose();
		t = undefined;
	});

	it("loads in real Pi extension runtime", async () => {
		const extensionPath = path.resolve(import.meta.dirname, "../index.ts");
		t = await createTestSession({ extensions: [extensionPath] });

		expect(t.session.extensionRunner.extensions).toHaveLength(1);
		expect(t.session.extensionRunner.extensions[0].path).toBe(extensionPath);
		expect(t.session.getActiveToolNames()).not.toContain("mockup");
	});

	it("writes debug lifecycle records in its sandbox when enabled", async () => {
		const extensionPath = path.resolve(import.meta.dirname, "../index.ts");
		t = await createTestSession({
			env: { PI_THE_SYSTEM_DEBUG: "1" },
			extensions: [extensionPath],
		});
		const context = t.session.extensionRunner.createCommandContext();
		for (const handler of t.session.extensionRunner.extensions[0].handlers.get(
			"session_start",
		))
			await handler({ type: "session_start" }, context);
		for (const handler of t.session.extensionRunner.extensions[0].handlers.get(
			"session_shutdown",
		))
			await handler({ type: "session_shutdown" }, context);
		const directory = path.join(
			t.cwd,
			".test-state",
			"pi-ext",
			"debug",
			"the-system",
		);
		const records = readFileSync(
			path.join(directory, readdirSync(directory)[0]),
			"utf8",
		)
			.trim()
			.split("\n")
			.map((line) => JSON.parse(line));
		expect(records.map((record) => record.event)).toEqual(
			expect.arrayContaining(["session.start", "session.shutdown"]),
		);
	});

	it("keeps system_bundle_slot through clarification and cancels it on the next lifecycle", async () => {
		const extensionPath = path.resolve(import.meta.dirname, "../index.ts");
		t = await createTestSession({ extensions: [extensionPath] });
		applyInitialization(t.cwd, "PX");
		const [extension] = t.session.extensionRunner.extensions;
		const sendUserMessage = vi
			.spyOn(t.session, "sendUserMessage")
			.mockResolvedValue();
		expect(extension.tools.has("system_bundle_slot")).toBe(false);
		expect(t.session.getActiveToolNames()).not.toContain("system_bundle_slot");
		await extension.commands
			.get("system")
			.handler(
				"spec let us discuss caching",
				t.session.extensionRunner.createCommandContext(),
			);
		expect(sendUserMessage).toHaveBeenCalledOnce();
		expect(extension.tools.has("system_bundle_slot")).toBe(true);
		expect(t.session.getActiveToolNames()).toContain("system_bundle_slot");
		expect(t.session.systemPrompt).toContain(
			"- system_bundle_slot: Reserve an ID and path for a System bundle",
		);
		expect(t.session.systemPrompt).toContain(
			"Resolve needed clarifications before calling system_bundle_slot.",
		);
		expect(t.session.systemPrompt).toContain(
			"- Call system_bundle_slot once per required bundle after choosing its final type and title; use each returned ID and path exactly.",
		);
		for (const handler of extension.handlers.get("agent_settled"))
			await handler(
				{ type: "agent_settled", messages: [] },
				t.session.extensionRunner.createCommandContext(),
			);
		expect(t.session.getActiveToolNames()).toContain("system_bundle_slot");
		await extension.commands
			.get("system")
			.handler(
				"exec continue",
				t.session.extensionRunner.createCommandContext(),
			);
		expect(t.session.getActiveToolNames()).not.toContain("system_bundle_slot");
		expect(t.session.systemPrompt).not.toContain("- system_bundle_slot:");
	});

	it("requests one-shot approval for an existing core mutation", async () => {
		const extensionPath = path.resolve(import.meta.dirname, "../index.ts");
		t = await createTestSession({ extensions: [extensionPath] });
		mkdirSync(path.join(t.cwd, ".system"));
		writeFileSync(path.join(t.cwd, ".system", "SYSTEM.md"), "Approved.\n");

		const blocked = await t.session.extensionRunner.emitToolCall({
			type: "tool_call",
			toolName: "edit",
			toolCallId: "blocked-core-edit",
			input: {
				path: ".system/SYSTEM.md",
				edits: [{ oldText: "Approved.", newText: "Human-approved." }],
			},
		});
		expect(blocked).toBeUndefined();
		const [approval] = t.events.uiCallsFor("select");
		expect(approval?.args).toEqual([
			"The System ownership approval",
			[
				"Approve once: edit .system/SYSTEM.md",
				"Deny: keep .system/SYSTEM.md unchanged",
			],
		]);
	});
});