import { describe, expect, it } from "bun:test"; import { WorkerCore } from "@oh-my-pi/pi-coding-agent/eval/js/worker-core"; import type { SessionSnapshot, Transport, WorkerInbound, WorkerOutbound, } from "@oh-my-pi/pi-coding-agent/eval/js/worker-protocol"; interface WorkerHarness { send(message: WorkerInbound): void; onMessage(handler: (message: WorkerOutbound) => void): () => void; } function createWorkerHarness(): WorkerHarness { const hostListeners = new Set<(message: WorkerOutbound) => void>(); const workerListeners = new Set<(message: WorkerInbound) => void>(); const transport: Transport = { send: message => { queueMicrotask(() => { for (const listener of hostListeners) listener(message); }); }, onMessage: handler => { workerListeners.add(handler); return () => workerListeners.delete(handler); }, close: () => {}, }; new WorkerCore(transport); return { send(message) { queueMicrotask(() => { for (const listener of workerListeners) listener(message); }); }, onMessage(handler) { hostListeners.add(handler); return () => hostListeners.delete(handler); }, }; } function waitForMessage( harness: WorkerHarness, predicate: (message: WorkerOutbound) => boolean, ): Promise { const { promise, resolve } = Promise.withResolvers(); let unsubscribe = (): void => {}; unsubscribe = harness.onMessage(message => { if (!predicate(message)) return; unsubscribe(); resolve(message); }); return promise; } async function initializeWorker(harness: WorkerHarness, snapshot: SessionSnapshot): Promise { const ready = waitForMessage(harness, message => message.type === "ready"); harness.send({ type: "init", snapshot }); expect((await ready).type).toBe("ready"); } describe("WorkerCore", () => { it("reports same-realm cwd conflicts through the worker protocol", async () => { const first = createWorkerHarness(); const second = createWorkerHarness(); const cwd = process.cwd(); await initializeWorker(first, { cwd, sessionId: "same-realm-first", localRoots: {} }); await initializeWorker(second, { cwd, sessionId: "same-realm-second", localRoots: {} }); const gate = Promise.withResolvers(); const entered = Promise.withResolvers(); (globalThis as { __omp_worker_core_gate?: { entered(): void; wait: Promise } }).__omp_worker_core_gate = { entered: () => entered.resolve(), wait: gate.promise, }; try { first.send({ type: "run", runId: "hold-first-runtime", code: "globalThis.__omp_worker_core_gate.entered(); await globalThis.__omp_worker_core_gate.wait;", filename: "[same-realm-first].js", snapshot: { cwd, sessionId: "same-realm-first", localRoots: {} }, }); await entered.promise; const result = waitForMessage( second, message => message.type === "result" && message.runId === "overlap-second-runtime", ); second.send({ type: "run", runId: "overlap-second-runtime", code: "1 + 1;", filename: "[same-realm-second].js", snapshot: { cwd, sessionId: "same-realm-second", localRoots: {} }, }); expect(await result).toMatchObject({ type: "result", runId: "overlap-second-runtime", ok: false, error: { message: "Cannot set cwd while another same-realm JS runtime is running" }, }); } finally { gate.resolve(); delete (globalThis as { __omp_worker_core_gate?: { entered(): void; wait: Promise } }) .__omp_worker_core_gate; first.send({ type: "close" }); second.send({ type: "close" }); } }); });