From 4bd67f11a871a3bc3f3f571c1b2e82d5605268b7 Mon Sep 17 00:00:00 2001 From: Agent Core Dev Date: Fri, 3 Apr 2026 22:45:53 +0800 Subject: [PATCH] fix: use exit event instead of close to resolve process hang with background jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cross-spawn spawner relied on the 'close' event to mark a process as complete. In Node.js, 'close' fires only after all stdio streams are closed. When a shell spawns a background child (e.g., 'cmd &'), the child inherits stdout/stderr pipe descriptors, keeping the streams open even after the shell exits. This caused the 'close' event to never fire, making the bash tool hang indefinitely. Switching to the 'exit' event resolves this — it fires as soon as the process terminates, regardless of inherited pipe descriptors. --- opencode-cli | 1 + packages/opencode/src/effect/cross-spawn-spawner.ts | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) create mode 160000 opencode-cli diff --git a/opencode-cli b/opencode-cli new file mode 160000 index 0000000000..224b297604 --- /dev/null +++ b/opencode-cli @@ -0,0 +1 @@ +Subproject commit 224b297604143373d680621ac4e9cb0def609be6 diff --git a/packages/opencode/src/effect/cross-spawn-spawner.ts b/packages/opencode/src/effect/cross-spawn-spawner.ts index 92e5b3ba2d..6605e40d73 100644 --- a/packages/opencode/src/effect/cross-spawn-spawner.ts +++ b/packages/opencode/src/effect/cross-spawn-spawner.ts @@ -272,12 +272,10 @@ export const make = Effect.gen(function* () { resume(Effect.fail(toPlatformError("spawn", err, command))) }) proc.on("exit", (...args) => { - exit = args - }) - proc.on("close", (...args) => { if (end) return end = true - Deferred.doneUnsafe(signal, Exit.succeed(exit ?? args)) + exit = args + Deferred.doneUnsafe(signal, Exit.succeed(exit)) }) proc.on("spawn", () => { resume(Effect.succeed([proc, signal]))