diff --git a/src/adapters/process-transport.ts b/src/adapters/process-transport.ts index 23187cd..3b7931e 100644 --- a/src/adapters/process-transport.ts +++ b/src/adapters/process-transport.ts @@ -419,6 +419,10 @@ async function terminatePosix( pid: number, graceMs: number, ): Promise { + if (hasEnded(child)) { + return TERMINATION_SCOPE.DIRECT_CHILD_ONLY; + } + let groupReached = signalProcessGroup(pid, 'SIGTERM'); if (!groupReached) { killDirectChild(child, 'SIGTERM'); @@ -743,9 +747,19 @@ export function invokeAgentProcess( }; if (child.stdout !== null) { + onEvent(child.stdout, 'error', () => { + // Read failures are consumed here without promoting the exchange to a + // terminal failure state, matching the stdin pattern. The close path + // decides the outcome. + }); onReadableData(child.stdout, onStdout); } if (child.stderr !== null) { + onEvent(child.stderr, 'error', () => { + // Read failures are consumed here without promoting the exchange to a + // terminal failure state, matching the stdin pattern. The close path + // decides the outcome. + }); onReadableData(child.stderr, onStderr); } diff --git a/tests/adapters/process-transport.test.ts b/tests/adapters/process-transport.test.ts index 673da1e..61e04db 100644 --- a/tests/adapters/process-transport.test.ts +++ b/tests/adapters/process-transport.test.ts @@ -117,7 +117,7 @@ describe('invokeAgentProcess — success', () => { } }); - it('accepts a zero-argument argv', async () => { + it('accepts a single-argument argv', async () => { const exchange = await invokeAgentProcess( makeSpec({ args: ['--version'] }), makeLimits(), @@ -127,6 +127,16 @@ describe('invokeAgentProcess — success', () => { expect(exchange.exitCode).toBe(0); }); + it('accepts a zero-argument argv', async () => { + const exchange = await invokeAgentProcess( + makeSpec({ args: [] }), + makeLimits({ timeoutMs: 500, graceMs: 200 }), + ); + + // Node starts an interactive REPL with no arguments, which times out + expect(exchange.outcome).toBe('TIMED_OUT'); + }, 15_000); + it('reports source bytes that match the decoded stdout for valid UTF-8', async () => { const exchange = await runStub(STUB.MULTIBYTE, ['3']);