@@ -34,10 +34,14 @@ describe("OutputInterceptor", () => {
3434
3535 storageDir = path . normalize ( "/tmp/test-storage" )
3636
37- // Setup mock write stream
37+ // Setup mock write stream with callback support for end()
3838 mockWriteStream = {
3939 write : vi . fn ( ) ,
40- end : vi . fn ( ) ,
40+ end : vi . fn ( ( callback ?: ( ) => void ) => {
41+ // Immediately call the callback to simulate stream flush completing
42+ if ( callback ) callback ( )
43+ } ) ,
44+ on : vi . fn ( ) ,
4145 }
4246
4347 vi . mocked ( fs . existsSync ) . mockReturnValue ( true )
@@ -49,7 +53,7 @@ describe("OutputInterceptor", () => {
4953 } )
5054
5155 describe ( "Buffering behavior" , ( ) => {
52- it ( "should keep small output in memory without spilling to disk" , ( ) => {
56+ it ( "should keep small output in memory without spilling to disk" , async ( ) => {
5357 const interceptor = new OutputInterceptor ( {
5458 executionId : "12345" ,
5559 taskId : "task-1" ,
@@ -64,7 +68,7 @@ describe("OutputInterceptor", () => {
6468 expect ( interceptor . hasSpilledToDisk ( ) ) . toBe ( false )
6569 expect ( fs . createWriteStream ) . not . toHaveBeenCalled ( )
6670
67- const result = interceptor . finalize ( )
71+ const result = await interceptor . finalize ( )
6872 expect ( result . preview ) . toBe ( smallOutput )
6973 expect ( result . truncated ) . toBe ( false )
7074 expect ( result . artifactPath ) . toBe ( null )
@@ -94,7 +98,7 @@ describe("OutputInterceptor", () => {
9498 expect ( mockWriteStream . write ) . toHaveBeenCalled ( )
9599 } )
96100
97- it ( "should truncate preview after spilling to disk using head/tail split" , ( ) => {
101+ it ( "should truncate preview after spilling to disk using head/tail split" , async ( ) => {
98102 const interceptor = new OutputInterceptor ( {
99103 executionId : "12345" ,
100104 taskId : "task-1" ,
@@ -109,7 +113,7 @@ describe("OutputInterceptor", () => {
109113
110114 expect ( interceptor . hasSpilledToDisk ( ) ) . toBe ( true )
111115
112- const result = interceptor . finalize ( )
116+ const result = await interceptor . finalize ( )
113117 expect ( result . truncated ) . toBe ( true )
114118 expect ( result . artifactPath ) . toBe ( path . join ( storageDir , "cmd-12345.txt" ) )
115119 // Preview is head (1024) + omission indicator + tail (1024)
@@ -268,7 +272,7 @@ describe("OutputInterceptor", () => {
268272 } )
269273
270274 describe ( "finalize() method" , ( ) => {
271- it ( "should return preview output for small commands" , ( ) => {
275+ it ( "should return preview output for small commands" , async ( ) => {
272276 const interceptor = new OutputInterceptor ( {
273277 executionId : "12345" ,
274278 taskId : "task-1" ,
@@ -280,15 +284,15 @@ describe("OutputInterceptor", () => {
280284 const output = "Hello World\n"
281285 interceptor . write ( output )
282286
283- const result = interceptor . finalize ( )
287+ const result = await interceptor . finalize ( )
284288
285289 expect ( result . preview ) . toBe ( output )
286290 expect ( result . totalBytes ) . toBe ( Buffer . byteLength ( output , "utf8" ) )
287291 expect ( result . artifactPath ) . toBe ( null )
288292 expect ( result . truncated ) . toBe ( false )
289293 } )
290294
291- it ( "should return PersistedCommandOutput for large commands with head/tail preview" , ( ) => {
295+ it ( "should return PersistedCommandOutput for large commands with head/tail preview" , async ( ) => {
292296 const interceptor = new OutputInterceptor ( {
293297 executionId : "12345" ,
294298 taskId : "task-1" ,
@@ -300,7 +304,7 @@ describe("OutputInterceptor", () => {
300304 const largeOutput = "x" . repeat ( 5000 )
301305 interceptor . write ( largeOutput )
302306
303- const result = interceptor . finalize ( )
307+ const result = await interceptor . finalize ( )
304308
305309 expect ( result . truncated ) . toBe ( true )
306310 expect ( result . artifactPath ) . toBe ( path . join ( storageDir , "cmd-12345.txt" ) )
@@ -310,7 +314,7 @@ describe("OutputInterceptor", () => {
310314 expect ( result . preview ) . toContain ( "bytes omitted...]" )
311315 } )
312316
313- it ( "should close write stream when finalizing" , ( ) => {
317+ it ( "should close write stream when finalizing" , async ( ) => {
314318 const interceptor = new OutputInterceptor ( {
315319 executionId : "12345" ,
316320 taskId : "task-1" ,
@@ -321,12 +325,12 @@ describe("OutputInterceptor", () => {
321325
322326 // Trigger spill
323327 interceptor . write ( "x" . repeat ( 3000 ) )
324- interceptor . finalize ( )
328+ await interceptor . finalize ( )
325329
326330 expect ( mockWriteStream . end ) . toHaveBeenCalled ( )
327331 } )
328332
329- it ( "should include correct metadata (artifactId, size, truncated flag)" , ( ) => {
333+ it ( "should include correct metadata (artifactId, size, truncated flag)" , async ( ) => {
330334 const interceptor = new OutputInterceptor ( {
331335 executionId : "12345" ,
332336 taskId : "task-1" ,
@@ -338,7 +342,7 @@ describe("OutputInterceptor", () => {
338342 const output = "x" . repeat ( 5000 )
339343 interceptor . write ( output )
340344
341- const result = interceptor . finalize ( )
345+ const result = await interceptor . finalize ( )
342346
343347 expect ( result ) . toHaveProperty ( "preview" )
344348 expect ( result ) . toHaveProperty ( "totalBytes" , 5000 )
@@ -432,7 +436,7 @@ describe("OutputInterceptor", () => {
432436 } )
433437
434438 describe ( "Head/Tail split behavior" , ( ) => {
435- it ( "should preserve first 50% and last 50% of output" , ( ) => {
439+ it ( "should preserve first 50% and last 50% of output" , async ( ) => {
436440 const interceptor = new OutputInterceptor ( {
437441 executionId : "12345" ,
438442 taskId : "task-1" ,
@@ -450,7 +454,7 @@ describe("OutputInterceptor", () => {
450454 interceptor . write ( middleContent )
451455 interceptor . write ( tailContent )
452456
453- const result = interceptor . finalize ( )
457+ const result = await interceptor . finalize ( )
454458
455459 // Should start with HEAD content (first 1024 bytes of head budget)
456460 expect ( result . preview . startsWith ( "HEAD" ) ) . toBe ( true )
@@ -461,7 +465,7 @@ describe("OutputInterceptor", () => {
461465 expect ( result . preview ) . toContain ( "bytes omitted...]" )
462466 } )
463467
464- it ( "should not add omission indicator when output fits in budget" , ( ) => {
468+ it ( "should not add omission indicator when output fits in budget" , async ( ) => {
465469 const interceptor = new OutputInterceptor ( {
466470 executionId : "12345" ,
467471 taskId : "task-1" ,
@@ -473,14 +477,14 @@ describe("OutputInterceptor", () => {
473477 const smallOutput = "Hello World\n"
474478 interceptor . write ( smallOutput )
475479
476- const result = interceptor . finalize ( )
480+ const result = await interceptor . finalize ( )
477481
478482 // No omission indicator for small output
479483 expect ( result . preview ) . toBe ( smallOutput )
480484 expect ( result . preview ) . not . toContain ( "[..." )
481485 } )
482486
483- it ( "should handle output that exactly fills head budget" , ( ) => {
487+ it ( "should handle output that exactly fills head budget" , async ( ) => {
484488 const interceptor = new OutputInterceptor ( {
485489 executionId : "12345" ,
486490 taskId : "task-1" ,
@@ -493,14 +497,14 @@ describe("OutputInterceptor", () => {
493497 const exactHeadContent = "x" . repeat ( 1024 )
494498 interceptor . write ( exactHeadContent )
495499
496- const result = interceptor . finalize ( )
500+ const result = await interceptor . finalize ( )
497501
498502 // Should fit entirely in head, no truncation
499503 expect ( result . preview ) . toBe ( exactHeadContent )
500504 expect ( result . truncated ) . toBe ( false )
501505 } )
502506
503- it ( "should split single large chunk across head and tail" , ( ) => {
507+ it ( "should split single large chunk across head and tail" , async ( ) => {
504508 const interceptor = new OutputInterceptor ( {
505509 executionId : "12345" ,
506510 taskId : "task-1" ,
@@ -514,7 +518,7 @@ describe("OutputInterceptor", () => {
514518 const content = "A" . repeat ( 1024 ) + "B" . repeat ( 2000 ) + "C" . repeat ( 1024 )
515519 interceptor . write ( content )
516520
517- const result = interceptor . finalize ( )
521+ const result = await interceptor . finalize ( )
518522
519523 // Head should have A's
520524 expect ( result . preview . startsWith ( "A" ) ) . toBe ( true )
0 commit comments