import { readdirSync, readFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { afterEach, describe, expect, it, vi } from "vitest"; import { createPiSession, type PiSession, } from "../../../test/fixture/create-pi-session.ts"; const extensionPath = fileURLToPath(new URL("../index.ts", import.meta.url)); let session: PiSession | undefined; afterEach(async () => { await session?.dispose(); session = undefined; }); function readRecords(directory: string) { return readdirSync(directory).flatMap((file) => readFileSync(path.join(directory, file), "utf8") .trim() .split("\n") .filter(Boolean) .map((line) => JSON.parse(line) as { event: string; extension: string }), ); } describe("git-safe debug interface", () => { it("writes its lifecycle records in the isolated sandbox", async () => { session = await createPiSession({ env: { PI_GIT_SAFE_DEBUG: "1" }, extensionPaths: [extensionPath], }); const runner = session.session.extensionRunner; await runner.emit({ type: "session_start", reason: "startup", }); await runner.emitToolResult({ type: "tool_result", toolName: "read", toolCallId: "missing-read", input: { path: path.join(session.cwd, "missing") }, content: [], isError: true, } as never); await runner.emit({ type: "session_shutdown", reason: "quit", }); if (!session.env["XDG_STATE_HOME"]) throw new Error("missing sandbox state home"); const directory = path.join( session.env["XDG_STATE_HOME"], "pi-ext", "debug", "git-safe", ); // Debug records flush asynchronously; poll until they appear. await vi.waitFor( () => { const records = readRecords(directory); expect(records).toContainEqual( expect.objectContaining({ event: "session.start", extension: "git-safe", }), ); expect(records).toContainEqual( expect.objectContaining({ event: "session.shutdown", extension: "git-safe", }), ); expect(records).toContainEqual( expect.objectContaining({ event: "read.spotlight.error", type: "readpath", }), ); }, { timeout: 5_000 }, ); }); });