import { readdirSync, readFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { afterEach, describe, expect, it } from "vitest"; import { createPiSession, type PiSession, } from "../../../test/fixture/create-pi-session.ts"; describe("tps contract", () => { let session: PiSession | undefined; afterEach(async () => { await session?.dispose(); session = undefined; }); it("loads in real Pi extension runtime", async () => { const extensionPath = fileURLToPath( new URL("../index.ts", import.meta.url), ); session = await createPiSession({ extensionPaths: [extensionPath] }); expect(session.errors).toEqual([]); expect(session.extensions).toHaveLength(1); expect(session.extensions[0]!.path).toBe(extensionPath); }); it("writes debug lifecycle records in its sandbox when enabled", async () => { const extensionPath = fileURLToPath( new URL("../index.ts", import.meta.url), ); session = await createPiSession({ env: { PI_TPS_DEBUG: "1" }, extensionPaths: [extensionPath], }); const runner = session.session.extensionRunner; await runner.emit({ type: "session_start", reason: "startup" }); await runner.emit({ type: "agent_start" }); await runner.emit({ type: "agent_end", messages: [] }); await runner.emit({ type: "session_shutdown", reason: "quit" }); const directory = path.join( session.cwd, ".test-state", "pi-ext", "debug", "tps", ); const records = readFileSync( path.join(directory, readdirSync(directory)[0]!), "utf8", ) .trim() .split("\n") .map((line) => JSON.parse(line)); expect(records).toEqual( expect.arrayContaining([ expect.objectContaining({ event: "session.start" }), expect.objectContaining({ event: "session.shutdown" }), expect.objectContaining({ event: "rate.finish", outcome: "idle" }), ]), ); }); });