repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/the-system/__tests__/contract.test.ts
Rawimport { readdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai";
import {
createCodemodeExtension,
type ExtensionUIContext,
} from "@earendil-works/pi-coding-agent";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
createPiSession,
type PiSession,
} from "../../../test/fixture/create-pi-session.ts";
import { applyInitialization } from "../init.ts";
const ENTRY = fileURLToPath(new URL("../index.ts", import.meta.url));
const recordingUi = (
select: (title: string, items: string[]) => string | undefined,
): ExtensionUIContext =>
({
select: async (title: string, items: string[]) => select(title, items),
confirm: async () => false,
input: async () => undefined,
notify: () => {},
onTerminalInput: () => () => {},
setStatus: () => {},
setWorkingMessage: () => {},
setWorkingVisible: () => {},
setWorkingIndicator: () => {},
setHiddenThinkingLabel: () => {},
setWidget: () => {},
setFooter: () => {},
setHeader: () => {},
setTitle: () => {},
custom: async () => undefined,
pasteToEditor: () => {},
setEditorText: () => {},
getEditorText: () => "",
editor: async () => undefined,
addAutocompleteProvider: () => {},
setEditorComponent: () => {},
getEditorComponent: () => undefined,
getAllThemes: () => [],
getTheme: () => undefined,
setTheme: () => ({ success: false, error: "UI not available" }),
getToolsExpanded: () => false,
setToolsExpanded: () => {},
}) as unknown as ExtensionUIContext;
describe("the-system pi-test-harness", () => {
let session: PiSession | undefined;
afterEach(async () => {
await session?.dispose();
session = undefined;
});
it("loads in real Pi extension runtime", async () => {
session = await createPiSession({ extensionPaths: [ENTRY] });
expect(session.extensions).toHaveLength(1);
expect(session.extensions[0]!.path).toBe(ENTRY);
expect(session.session.getActiveToolNames()).not.toContain("mockup");
});
it("writes debug lifecycle records in its sandbox when enabled", async () => {
session = await createPiSession({
env: { PI_THE_SYSTEM_DEBUG: "1" },
extensionPaths: [ENTRY],
});
const context = session.session.extensionRunner.createCommandContext();
const [lifecycleExtension] = session.extensions;
if (!lifecycleExtension) throw new Error("the-system extension not loaded");
for (const handler of lifecycleExtension.handlers.get("session_start") ??
[])
await handler({ type: "session_start" }, context);
for (const handler of lifecycleExtension.handlers.get("session_shutdown") ??
[])
await handler({ type: "session_shutdown" }, context);
const directory = path.join(
session.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("registers scoped tools deferred without declaring them to the model", async () => {
session = await createPiSession({ extensionPaths: [ENTRY] });
applyInitialization(session.cwd, "PX");
const extension = session.extensions.find((item) => item.path === ENTRY);
if (!extension) throw new Error("the-system extension not loaded");
const sendUserMessage = vi
.spyOn(session.session, "sendUserMessage")
.mockResolvedValue();
const systemCommand = extension.commands.get("system");
if (!systemCommand) throw new Error("system command not registered");
await systemCommand.handler(
"spec let us discuss caching",
session.session.extensionRunner.createCommandContext(),
);
expect(sendUserMessage).toHaveBeenCalledOnce();
for (const name of [
"system_bundle_slot",
"system_board_propose",
"system_board_update",
]) {
const tool = extension.tools.get(name)?.definition;
expect(tool?.exposure).toBe("deferred");
expect(tool?.annotations?.readOnlyHint).toBe(false);
expect(session.session.getCallableToolNames()).toContain(name);
expect(session.session.getActiveToolNames()).not.toContain(name);
expect(session.session.systemPrompt).not.toContain(`- ${name}:`);
}
});
it.each([true, false])(
"preserves nested codemode mutation approval: %s",
async (approve) => {
session = await createPiSession({
extensionPaths: [ENTRY],
extensionFactories: [createCodemodeExtension()],
userSettings: { defaultTools: ["+codemode"] },
responses: [
fauxAssistantMessage(
fauxToolCall("codemode", {
code: 'await tools.edit({ path: ".system/SYSTEM.md", edits: [{ oldText: "Approved.", newText: "Human-approved." }] });',
}),
),
fauxAssistantMessage("approval requested"),
],
});
applyInitialization(session.cwd, "PX");
const extension = session.extensions.find((item) => item.path === ENTRY);
if (!extension) throw new Error("the-system extension not loaded");
const systemCommand = extension.commands.get("system");
if (!systemCommand) throw new Error("system command not registered");
vi.spyOn(session.session, "sendUserMessage").mockResolvedValue();
await systemCommand.handler(
"spec nested confirmation",
session.session.extensionRunner.createCommandContext(),
);
writeFileSync(
path.join(session.cwd, ".system", "SYSTEM.md"),
"Approved.\n",
);
const nestedStarts: {
toolName: string;
parentToolCallId?: string | undefined;
}[] = [];
const unsubscribe = session.session.subscribe((event) => {
if (event.type === "tool_execution_start" && event.toolName === "edit")
nestedStarts.push({
toolName: event.toolName,
parentToolCallId: event.parentToolCallId,
});
});
const selectCalls: { args: [string, string[]] }[] = [];
session.session.extensionRunner.setUIContext(
recordingUi((title, items) => {
selectCalls.push({ args: [title, items] });
return items[approve ? 0 : 1];
}),
"tui",
);
await session.session.prompt("run the scripted nested edit");
unsubscribe();
const [approval] = selectCalls;
expect(approval?.args).toEqual([
"The System ownership approval",
[
"Approve once: edit .system/SYSTEM.md",
"Deny: keep .system/SYSTEM.md unchanged",
],
]);
expect(nestedStarts).toEqual([
{ toolName: "edit", parentToolCallId: expect.any(String) },
]);
expect(
readFileSync(path.join(session.cwd, ".system", "SYSTEM.md"), "utf8"),
).toBe(approve ? "Human-approved.\n" : "Approved.\n");
},
);
});