@@ -131,6 +131,17 @@ function abortResult(
131131 return signal ?. aborted ? err ( new FileError ( "aborted" , "aborted" , path ) ) : undefined ;
132132}
133133
134+ type ChildOutputStreamName = "stdout" | "stderr" ;
135+
136+ function listenForChildOutputErrors (
137+ child : ReturnType < typeof spawn > ,
138+ onError : ( stream : ChildOutputStreamName , error : Error ) => void ,
139+ ) : void {
140+ for ( const streamName of [ "stdout" , "stderr" ] as const ) {
141+ child [ streamName ] ?. on ( "error" , ( error : Error ) => onError ( streamName , error ) ) ;
142+ }
143+ }
144+
134145async function pathExists ( path : string ) : Promise < boolean > {
135146 try {
136147 await access ( path , constants . F_OK ) ;
@@ -159,13 +170,20 @@ async function runCommand(
159170 }
160171 const timeout = setTimeout ( ( ) => {
161172 if ( child . pid ) {
162- killProcessTree ( child . pid , { force : true } ) ;
173+ killProcessTree ( child . pid , { force : true , detached : false } ) ;
163174 }
164175 } , timeoutMs ) ;
165176 child . stdout ?. setEncoding ( "utf8" ) ;
166177 child . stdout ?. on ( "data" , ( chunk : string ) => {
167178 stdout += chunk ;
168179 } ) ;
180+ listenForChildOutputErrors ( child , ( ) => {
181+ if ( child . pid ) {
182+ killProcessTree ( child . pid , { force : true , detached : false } ) ;
183+ }
184+ clearTimeout ( timeout ) ;
185+ resolveLocal ( { stdout : "" , status : null } ) ;
186+ } ) ;
169187 child . on ( "error" , ( ) => {
170188 clearTimeout ( timeout ) ;
171189 resolveLocal ( { stdout : "" , status : null } ) ;
@@ -374,7 +392,7 @@ export class NodeExecutionEnv implements ExecutionEnv {
374392 // Guard stdout/stderr against stream errors (e.g. EPIPE when the
375393 // child exits before all pipe data is consumed). Without listeners,
376394 // Node.js throws an uncaught exception that crashes the process.
377- const onStreamError = ( stream : "stdout" | "stderr" , error : Error ) => {
395+ const onStreamError = ( stream : ChildOutputStreamName , error : Error ) => {
378396 if ( settled ) {
379397 return ;
380398 }
@@ -383,8 +401,7 @@ export class NodeExecutionEnv implements ExecutionEnv {
383401 err ( new ExecutionError ( "spawn_error" , `${ stream } read error: ${ error . message } ` , error ) ) ,
384402 ) ;
385403 } ;
386- child . stdout ?. on ( "error" , ( e ) => onStreamError ( "stdout" , e ) ) ;
387- child . stderr ?. on ( "error" , ( e ) => onStreamError ( "stderr" , e ) ) ;
404+ listenForChildOutputErrors ( child , onStreamError ) ;
388405
389406 child . on ( "error" , ( error ) => {
390407 settle ( err ( new ExecutionError ( "spawn_error" , error . message , error ) ) ) ;
0 commit comments