From aa014717dce604b21b98daace78b0c7db63dcac8 Mon Sep 17 00:00:00 2001 From: can1357 Date: Mon, 3 Aug 2026 00:19:58 +0200 Subject: [PATCH] refactor(coding-agent): restored static computer worker start hook - The pi-utils/mime subpath fix made the computer worker graph lazy-safe, so the dynamic-import dispatch added for laziness is no longer needed; cli.ts and the bundled-host fixture statically import startComputerWorker() per the no-inline-import rule. - worker-entry keeps the selector-guarded direct-source auto-start; the worker-selector test now pins the exported hook contract. Verified --no-addons CLI startup stays addon-free and the bundled/compiled worker-host tests pass. --- packages/coding-agent/src/cli.ts | 3 ++- .../src/tools/computer/worker-entry.ts | 25 ++++++++++++------- .../fixtures/computer-worker-bundled-host.ts | 5 ++-- .../coding-agent/test/worker-selector.test.ts | 6 +++-- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/coding-agent/src/cli.ts b/packages/coding-agent/src/cli.ts index e597a8588..237fe99b1 100755 --- a/packages/coding-agent/src/cli.ts +++ b/packages/coding-agent/src/cli.ts @@ -36,6 +36,7 @@ import { TERMINAL_OUTPUT_WORKER_ARG } from "./launch/terminal-output-worker-prot import { LSP_MUX_WORKER_ARG } from "./lsp/mux/protocol"; import { COMPUTER_WORKER_ARG } from "./tools/computer/protocol"; import { smokeTestComputerWorker } from "./tools/computer/supervisor"; +import { startComputerWorker } from "./tools/computer/worker-entry"; if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) { process.stderr.write( @@ -169,7 +170,7 @@ async function runWorkerEntrypoint(arg: string | undefined): Promise { } if (arg === COMPUTER_WORKER_ARG) { if (parentPort) installWorkerInbox(parentPort); - await import("./tools/computer/worker-entry"); + startComputerWorker(); return true; } if (arg === JS_EVAL_WORKER_ARG) { diff --git a/packages/coding-agent/src/tools/computer/worker-entry.ts b/packages/coding-agent/src/tools/computer/worker-entry.ts index 68bbe3490..14a0b4ea5 100644 --- a/packages/coding-agent/src/tools/computer/worker-entry.ts +++ b/packages/coding-agent/src/tools/computer/worker-entry.ts @@ -1,16 +1,14 @@ import { parentPort } from "node:worker_threads"; -import { consumeWorkerInbox } from "@oh-my-pi/pi-utils/worker-host"; +import { consumeWorkerInbox, isWorkerHostSelector } from "@oh-my-pi/pi-utils/worker-host"; import type { ComputerWorkerInbound, ComputerWorkerTransport } from "./protocol"; import { ComputerWorkerCore } from "./worker"; -// Side-effect entry module: evaluating it inside a worker thread starts the -// computer worker; importing it from the main thread (tests, SDK embedding) is -// a no-op. The CLI host dispatches the `__omp_worker_computer` selector by -// dynamically importing this module after installing the worker inbox, so the -// computer worker graph stays off normal CLI startup. Loaded directly (source -// fallback outside a CLI host), top-level evaluation runs synchronously at -// worker start and `parentPort.on` below wins the flush on its own. -if (parentPort) { +let started = false; + +/** Starts the computer worker once when running inside a Bun worker thread. */ +export function startComputerWorker(): void { + if (started || !parentPort) return; + started = true; const port = parentPort; const inbox = consumeWorkerInbox(); const transport: ComputerWorkerTransport = { @@ -30,3 +28,12 @@ if (parentPort) { new ComputerWorkerCore(transport); } + +// Direct-source fallback: loaded as a worker's entry module outside a CLI +// host there is no selector argv, so start immediately. When any CLI-host +// worker re-enters cli.ts (which imports this module statically), the +// selector guard defers to the host's dispatch — an unguarded auto-start +// would hijack the message port of every other worker kind. +if (!Bun.argv.some(isWorkerHostSelector)) { + startComputerWorker(); +} diff --git a/packages/coding-agent/test/fixtures/computer-worker-bundled-host.ts b/packages/coding-agent/test/fixtures/computer-worker-bundled-host.ts index 899c68a68..ca18e05df 100644 --- a/packages/coding-agent/test/fixtures/computer-worker-bundled-host.ts +++ b/packages/coding-agent/test/fixtures/computer-worker-bundled-host.ts @@ -1,10 +1,9 @@ import { parentPort } from "node:worker_threads"; import { installWorkerInbox } from "@oh-my-pi/pi-utils/worker-host"; import { COMPUTER_WORKER_ARG } from "../../src/tools/computer/protocol"; +import { startComputerWorker } from "../../src/tools/computer/worker-entry"; if (process.argv[2] !== COMPUTER_WORKER_ARG) throw new Error(`unknown worker selector: ${process.argv[2]}`); if (!parentPort) throw new Error("computer worker fixture: missing parentPort"); installWorkerInbox(parentPort); -// Mirrors the CLI host: the worker entry is a self-starting side-effect module -// dispatched via dynamic import after the inbox is installed. -await import("../../src/tools/computer/worker-entry"); +startComputerWorker(); diff --git a/packages/coding-agent/test/worker-selector.test.ts b/packages/coding-agent/test/worker-selector.test.ts index ce7a9b2bc..e56b93abf 100644 --- a/packages/coding-agent/test/worker-selector.test.ts +++ b/packages/coding-agent/test/worker-selector.test.ts @@ -38,7 +38,9 @@ describe("worker selector dispatch", () => { }); describe("computer worker entry", () => { - it("is side-effect-free to import outside a worker and has no manual start hook", () => { - expect("startComputerWorker" in computerWorkerEntry).toBe(false); + it("is side-effect-free to import outside a worker and exposes a named start function", () => { + // Importing on the main thread (no parentPort) must not start the worker + // core; the CLI host and bundled hosts call the exported hook explicitly. + expect(computerWorkerEntry.startComputerWorker).toBeFunction(); }); });