Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

test/fixture/create-pi-session.test.ts

Raw
import { type ChildProcess, spawn } from "node:child_process";
import { once } from "node:events";
import { access } from "node:fs/promises";
import { join } from "node:path";
import {
	fauxAssistantMessage,
	InMemoryCredentialStore,
} from "@earendil-works/pi-ai";
import { afterEach, describe, expect, it } from "vitest";
import { createPiSession, type PiSession } from "./create-pi-session.ts";

let session: PiSession | undefined;

afterEach(async () => {
	await session?.dispose();
	session = undefined;
});

describe("owned Pi fixture", () => {
	it("waits for a briefly retained child cwd before deleting owned fixtures", async () => {
		let child: ChildProcess | undefined;
		session = await createPiSession({
			extensionFactories: [
				(pi) => {
					pi.on("session_shutdown", () => {
						setTimeout(() => child?.kill(), 150);
					});
				},
			],
		});
		const cwd = session.cwd;
		child = spawn(
			process.execPath,
			["-e", "process.stdout.write('ready'); setInterval(() => {}, 1000);"],
			{ cwd, stdio: ["ignore", "pipe", "ignore"] },
		);
		const closed = once(child, "close");
		try {
			await once(child.stdout!, "data");
			await session.dispose();
			await closed;
			expect(session.errors).toEqual([]);
			await expect(access(cwd)).rejects.toMatchObject({ code: "ENOENT" });
		} finally {
			child.kill();
			await closed;
		}
	});

	it("surfaces shutdown errors after restoring environment and deleting its owned cwd", async () => {
		const originalHome = process.env["HOME"];
		session = await createPiSession({
			extensionFactories: [
				(pi) => {
					pi.on("session_shutdown", () => {
						throw new Error("shutdown regression evidence");
					});
				},
			],
		});
		const cwd = session.cwd;
		await expect(session.dispose()).rejects.toThrow(
			"shutdown regression evidence",
		);
		expect(process.env["HOME"]).toBe(originalHome);
		await expect(access(cwd)).rejects.toMatchObject({ code: "ENOENT" });
	});

	it("keeps injected credentials and catalog cache off disk", async () => {
		session = await createPiSession({
			credentials: new InMemoryCredentialStore(),
			extensionPaths: [],
			responses: [fauxAssistantMessage("in-memory credentials")],
		});

		await session.session.prompt("hi");
		await session.session.modelRuntime.refresh({ allowNetwork: false });

		expect(session.errors).toEqual([]);
		expect(session.providerState.callCount).toBe(1);
		for (const file of ["auth.json", "models-store.json"]) {
			await expect(access(join(session.agentDir, file))).rejects.toMatchObject({
				code: "ENOENT",
			});
		}
	});

	it("drives a scripted model turn through the public provider", async () => {
		session = await createPiSession({
			extensionPaths: [],
			responses: [fauxAssistantMessage("hello from the owned fixture")],
		});

		await session.session.prompt("hi");

		expect(session.errors).toEqual([]);
		expect(session.providerState.callCount).toBe(1);
	});
});