@@ -298,6 +298,12 @@ describe("runExec", () => {
298298 const sessionId = "exec-dispose-fail" ;
299299 let disposeCalls = 0 ;
300300 const dummySource = { id : "test" , provider : "test" , model : "test" } as InferenceSource ;
301+ const stderrChunks : string [ ] = [ ] ;
302+ const origWrite = process . stderr . write . bind ( process . stderr ) ;
303+ process . stderr . write = ( ( chunk : string | Uint8Array , ...rest : unknown [ ] ) => {
304+ stderrChunks . push ( typeof chunk === "string" ? chunk : Buffer . from ( chunk ) . toString ( "utf8" ) ) ;
305+ return origWrite ( chunk as never , ...( rest as never [ ] ) ) ;
306+ } ) as typeof process . stderr . write ;
301307 try {
302308 await withMockedModuleDuring (
303309 import . meta. resolve ( "node:os" ) ,
@@ -347,6 +353,9 @@ describe("runExec", () => {
347353 providers : [ ] ,
348354 } ) ;
349355 expect ( result . exitCode ) . toBe ( 1 ) ;
356+ expect ( result . status ) . toBe ( "failed" ) ;
357+ expect ( result . error ) . toMatch ( / p l u g i n d i s p o s e f a i l e d | r u n t i m e d i s p o s e f a i l e d / i) ;
358+ expect ( stderrChunks . join ( "" ) ) . toMatch ( / r u n t i m e d i s p o s e f a i l e d / i) ;
350359 expect ( disposeCalls ) . toBe ( 1 ) ;
351360 expect ( getActiveDisposeHost ( ) ) . toBeNull ( ) ;
352361 } ,
@@ -356,6 +365,7 @@ describe("runExec", () => {
356365 } ,
357366 ) ;
358367 } finally {
368+ process . stderr . write = origWrite ;
359369 if ( previous !== null ) setActiveRun ( previous ) ;
360370 else clearActiveRun ( ) ;
361371 rmSync ( cwd , { recursive : true , force : true } ) ;
@@ -415,6 +425,20 @@ describe("disposeExecRuntime", () => {
415425 expect ( calls ) . toEqual ( [ "agent" , "toolset" ] ) ;
416426 } ) ;
417427
428+ test ( "rejects leftover-child dispose from the toolset" , async ( ) => {
429+ await expect (
430+ disposeExecRuntime ( {
431+ agent : { close : async ( ) => undefined } ,
432+ toolset : {
433+ dispose : async ( ) => {
434+ throw new Error ( "1 shell child process still live after 2000ms reap" ) ;
435+ } ,
436+ } ,
437+ subAgentSessions : null ,
438+ } ) ,
439+ ) . rejects . toThrow ( / s t i l l l i v e a f t e r 2 0 0 0 m s r e a p / ) ;
440+ } ) ;
441+
418442 test ( "rejects when toolset dispose fails" , async ( ) => {
419443 await expect (
420444 disposeExecRuntime ( {
0 commit comments