import { readdirSync, readFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import type { CompactionEntry } 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"; describe("continuity debug", () => { let session: PiSession | undefined; afterEach(async () => { await session?.dispose(); session = undefined; }); it("writes its lifecycle JSONL through the standalone factory", async () => { session = await createPiSession({ extensionPaths: [fileURLToPath(new URL("../index.ts", import.meta.url))], env: { PI_CONTINUITY_DEBUG: "1" }, }); expect(session.errors).toEqual([]); await session.session.extensionRunner.emit({ type: "session_start", reason: "startup", }); await session.session.extensionRunner.emit({ type: "session_compact", compactionEntry: { id: "compact-debug" } as CompactionEntry, fromExtension: false, reason: "overflow", willRetry: true, }); await session.session.extensionRunner.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", "continuity", ); const records = await vi.waitFor(() => { const [file] = readdirSync(directory); if (!file) throw new Error("no debug file yet"); const parsed = readFileSync(path.join(directory, file), "utf8") .trim() .split("\n") .filter((line) => line.length > 0) .map((line) => JSON.parse(line)); const events = parsed.map((record) => record.event); if ( !["session.start", "session.shutdown", "continuation"].every((event) => events.includes(event), ) ) throw new Error("debug records not flushed yet"); return parsed; }); expect(records.map((record) => record.event)).toEqual( expect.arrayContaining([ "session.start", "session.shutdown", "continuation", ]), ); expect(records).toContainEqual( expect.objectContaining({ event: "continuation", outcome: "skipped-retry", }), ); }); });