// Isolated real-Pi fixture for browser-driven checks (including WebDriver BiDi). import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { type FauxResponseFactory, fauxAssistantMessage, } from "@earendil-works/pi-ai"; import { createPiSession } from "../../../test/fixture/create-pi-session.ts"; const canvasPackage = JSON.parse( readFileSync( new URL("../../../dist/canvas/package.json", import.meta.url), "utf8", ), ) as { pi: { extensions: string[] } }; const canvasEntry = canvasPackage.pi.extensions[0]; if (!canvasEntry) throw new Error("Canvas Pi extension entry missing"); const fixture = await createPiSession({ extensionPaths: [ fileURLToPath( new URL(`../../../dist/canvas/${canvasEntry}`, import.meta.url), ), ], env: { PATH: "/canvas-test-no-executables", TERMUX_VERSION: undefined, PI_CANVAS_DEBUG: "0", }, responses: Array.from( { length: 20 }, (): FauxResponseFactory => async (_context, _options, state) => { await new Promise((resolve) => setTimeout(resolve, 1500)); return fauxAssistantMessage( `Firefox drawing observed: ${state.callCount}`, ); }, ), }); let closing = false; const expiry = setTimeout(() => { void close(); }, 600_000); async function close(): Promise { if (closing) return; closing = true; clearTimeout(expiry); await fixture.dispose(); console.log( JSON.stringify({ kind: "closed", calls: fixture.providerState.callCount, errors: fixture.errors, }), ); process.exitCode = fixture.errors.length ? 1 : 0; } process.once("SIGINT", () => { void close(); }); process.once("SIGTERM", () => { void close(); }); try { if (fixture.errors.length) throw new Error(fixture.errors.join("\n")); let url = ""; const context = fixture.session.extensionRunner.createCommandContext(); context.ui.notify = (text) => { const match = text.match(/http:\/\/127\.0\.0\.1:\d+\/#\S+/u); if (match) url = match[0]; }; await fixture.extensions[0]!.commands.get("canvas")!.handler("open", context); if (!url) throw new Error("Canvas fixture did not open."); console.log(JSON.stringify({ kind: "ready", pid: process.pid, url })); } catch (error) { await close(); throw error; }