From d7a08623825c7fe5bfe66d0243f30bf20efeb7e9 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Thu, 5 Mar 2026 07:55:33 -0500 Subject: [PATCH] process/supervisor: track child stdin destroyed state --- src/process/supervisor/adapters/child.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/process/supervisor/adapters/child.ts b/src/process/supervisor/adapters/child.ts index a6db4329336..8115bf39270 100644 --- a/src/process/supervisor/adapters/child.ts +++ b/src/process/supervisor/adapters/child.ts @@ -68,19 +68,31 @@ export async function createChildAdapter(params: { }); const child = spawned.child as ChildProcessWithoutNullStreams; + let stdinDestroyed = params.input !== undefined || stdinMode === "pipe-closed"; if (child.stdin) { if (params.input !== undefined) { child.stdin.write(params.input); child.stdin.end(); + stdinDestroyed = true; } else if (stdinMode === "pipe-closed") { child.stdin.end(); + stdinDestroyed = true; } + child.stdin.on("close", () => { + stdinDestroyed = true; + }); } const stdin: ManagedRunStdin | undefined = child.stdin ? { - destroyed: false, + get destroyed() { + return stdinDestroyed; + }, write: (data: string, cb?: (err?: Error | null) => void) => { + if (stdinDestroyed) { + cb?.(new Error("stdin is not writable")); + return; + } try { child.stdin.write(data, cb); } catch (err) { @@ -88,14 +100,22 @@ export async function createChildAdapter(params: { } }, end: () => { + if (stdinDestroyed) { + return; + } try { + stdinDestroyed = true; child.stdin.end(); } catch { // ignore close errors } }, destroy: () => { + if (stdinDestroyed) { + return; + } try { + stdinDestroyed = true; child.stdin.destroy(); } catch { // ignore destroy errors