From ee6325d55903c345bc1439fb28985c8a150881f1 Mon Sep 17 00:00:00 2001 From: Alex Alecu Date: Wed, 25 Feb 2026 13:16:48 +0200 Subject: [PATCH] fix: guard terminateWorker against multiple invocations terminateWorker is registered on SIGHUP, SIGTERM, and used in onExit. If a signal fires and then onExit triggers (or two signals arrive), worker.terminate() and client.call('shutdown') would fire redundantly. Cache the pending promise so subsequent calls return the same operation. --- packages/opencode/src/cli/cmd/tui/thread.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index 0bf215229ed..df8f2fd43da 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -132,12 +132,17 @@ export const TuiThreadCommand = cmd({ // after shutdown because the worker's event loop drains. Send the // shutdown request without awaiting the response, wait for the worker // to exit naturally or force-terminate after a timeout. - const terminateWorker = () => - new Promise((resolve) => { + // Guard against multiple invocations (SIGHUP + SIGTERM + onExit). + let pending: Promise | undefined + const terminateWorker = () => { + if (pending) return pending + pending = new Promise((resolve) => { worker.addEventListener("close", () => resolve(), { once: true }) setTimeout(resolve, 5000) client.call("shutdown", undefined).catch(() => {}) }).then(() => worker.terminate()) + return pending + } process.on("SIGHUP", terminateWorker) process.on("SIGTERM", terminateWorker) // kilocode_change end