@@ -279,6 +279,54 @@ describe('ClaudeCliRuntime abort force-kill fallback', () => {
279279 } ] ) ;
280280 } ) ;
281281
282+ it ( 'settles cleanly when an interrupt ends a fenced background wait' , async ( ) => {
283+ const runtime = createRuntime ( ) ;
284+ const ctrl = createControllableProc ( ) ;
285+ spawnMock . mockReturnValue ( ctrl . proc ) ;
286+ const failures = [ ] ;
287+ const finishes = [ ] ;
288+ runtime . onFailed ( ( chatId , message ) => failures . push ( { chatId, message } ) ) ;
289+ runtime . onFinished ( ( chatId , exitCode ) => finishes . push ( { chatId, exitCode } ) ) ;
290+
291+ const turn = runtime . startClaudeCliSession ( startOptions ( ) ) ;
292+ ctrl . push ( INIT ) ;
293+ await flush ( ) ;
294+ ctrl . startLatestInput ( ) ;
295+ ctrl . push ( {
296+ type : 'system' ,
297+ subtype : 'background_tasks_changed' ,
298+ tasks : [ { task_id : 'background-build' , task_type : 'local_bash' } ] ,
299+ } ) ;
300+ ctrl . push ( { type : 'assistant' , content : [ { type : 'text' , text : 'started' } ] } ) ;
301+ ctrl . push ( RESULT ) ;
302+ ctrl . push ( IDLE ) ;
303+ await flush ( ) ;
304+ expect ( runtime . isClaudeInternalSessionRunning ( 'session-1' ) ) . toBe ( true ) ;
305+
306+ await runtime . abortClaudeInternalSession ( 'session-1' ) ;
307+ const interrupt = ctrl . writes
308+ . map ( ( line ) => JSON . parse ( line ) )
309+ . find ( ( message ) => message . request ?. subtype === 'interrupt' ) ;
310+ ctrl . push ( {
311+ type : 'control_response' ,
312+ response : {
313+ subtype : 'success' ,
314+ request_id : interrupt . request_id ,
315+ response : { cancelled : [ ] , still_queued : [ ] } ,
316+ } ,
317+ } ) ;
318+ await flush ( ) ;
319+ const completionFallback = scheduled . find ( ( entry ) => entry . ms === 15_000 ) ;
320+ expect ( completionFallback ) . toBeDefined ( ) ;
321+
322+ ctrl . push ( IDLE ) ;
323+ await turn ;
324+ expect ( cleared ) . toContain ( completionFallback . id ) ;
325+ expect ( ctrl . proc . killed ) . toBe ( false ) ;
326+ expect ( failures ) . toEqual ( [ ] ) ;
327+ expect ( finishes ) . toEqual ( [ { chatId : 'chat-1' , exitCode : 0 } ] ) ;
328+ } ) ;
329+
282330 it ( 'cancels a queued submitted input when an internal turn is interrupted' , async ( ) => {
283331 const runtime = createRuntime ( ) ;
284332 const ctrl = createControllableProc ( ) ;
0 commit comments