@@ -973,20 +973,18 @@ describe('Coordinator deregisterCoordinator', () => {
973973 expect ( ( ) => coordinator . deregisterCoordinator ( 'nonexistent' ) ) . not . toThrow ( ) ;
974974 } ) ;
975975
976- it ( 'child tasks are removed from internal map after coordinator is deregistered' , async ( ) => {
976+ it ( 'tasks become orphans after coordinator is deregistered' , async ( ) => {
977977 coordinator . registerCoordinator ( 'coord-1' , 'proj-1' ) ;
978978 await coordinator . createTask ( { name : 'test' , prompt : 'do' , coordinatorTaskId : 'coord-1' } ) ;
979+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( false ) ;
979980 coordinator . deregisterCoordinator ( 'coord-1' ) ;
980- // markPromptDelivered is now a no-op — task was removed from this.tasks
981+ // Task remains in internal map as an orphan (not removed)
982+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( true ) ;
983+ // markPromptDelivered still works on orphaned tasks
981984 coordinator . markPromptDelivered ( 'task-1' ) ;
982- const outputCb = getOutputCb ( ) ;
983- mockNotifyRenderer . mockClear ( ) ;
984- outputCb ( encode ( 'Done ❯ ' ) ) ;
985- // PTY output is silently dropped — no orphaned notification because the task entry is gone
986- expect ( mockNotifyRenderer ) . not . toHaveBeenCalledWith (
987- 'mcp_coordinator_orphaned_notification' ,
988- expect . anything ( ) ,
989- ) ;
985+ // Close the orphaned task
986+ await coordinator . closeTask ( 'task-1' ) ;
987+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( false ) ;
990988 } ) ;
991989
992990 it ( 'clears staged notification when coordinator is deregistered' , async ( ) => {
@@ -1016,6 +1014,31 @@ describe('Coordinator deregisterCoordinator', () => {
10161014 expect ( coordinator . hasActiveCoordinator ( ) ) . toBe ( false ) ;
10171015 } ) ;
10181016
1017+ it ( 'hasOrphanedTasks returns true after deregister with children, false after closeTask' , async ( ) => {
1018+ coordinator . registerCoordinator ( 'coord-1' , 'proj-1' ) ;
1019+ await coordinator . createTask ( { name : 'test' , prompt : 'do' , coordinatorTaskId : 'coord-1' } ) ;
1020+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( false ) ;
1021+
1022+ coordinator . deregisterCoordinator ( 'coord-1' ) ;
1023+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( true ) ;
1024+
1025+ await coordinator . closeTask ( 'task-1' ) ;
1026+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( false ) ;
1027+ } ) ;
1028+
1029+ it ( 'allOrphanedDoneCallback fires when last orphaned task is closed' , async ( ) => {
1030+ const cb = vi . fn ( ) ;
1031+ coordinator . setAllOrphanedDoneCallback ( cb ) ;
1032+ coordinator . registerCoordinator ( 'coord-1' , 'proj-1' ) ;
1033+ await coordinator . createTask ( { name : 'test' , prompt : 'do' , coordinatorTaskId : 'coord-1' } ) ;
1034+
1035+ coordinator . deregisterCoordinator ( 'coord-1' ) ;
1036+ expect ( cb ) . not . toHaveBeenCalled ( ) ;
1037+
1038+ await coordinator . closeTask ( 'task-1' ) ;
1039+ expect ( cb ) . toHaveBeenCalledTimes ( 1 ) ;
1040+ } ) ;
1041+
10191042 it ( 'deregister cleans up backend resource maps for child tasks' , async ( ) => {
10201043 const { unsubscribeFromAgent } =
10211044 await vi . importMock < typeof import ( '../ipc/pty.js' ) > ( '../ipc/pty.js' ) ;
@@ -1044,6 +1067,16 @@ describe('Coordinator deregisterCoordinator', () => {
10441067 expect ( c . tailBuffers . has ( agentId ) ) . toBe ( false ) ;
10451068 expect ( c . decoders . has ( agentId ) ) . toBe ( false ) ;
10461069 } ) ;
1070+
1071+ it ( 'hasOrphanedTasks returns false after removeCoordinatedTask closes an orphaned task' , async ( ) => {
1072+ coordinator . registerCoordinator ( 'coord-1' , 'proj-1' ) ;
1073+ await coordinator . createTask ( { name : 'test' , prompt : 'do' , coordinatorTaskId : 'coord-1' } ) ;
1074+ coordinator . deregisterCoordinator ( 'coord-1' ) ;
1075+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( true ) ;
1076+ // Simulate UI closing the task
1077+ coordinator . removeCoordinatedTask ( 'task-1' ) ;
1078+ expect ( coordinator . hasOrphanedTasks ( ) ) . toBe ( false ) ;
1079+ } ) ;
10471080} ) ;
10481081
10491082// ─── per-task projectRoot tests ───────────────────────────────────────────────
0 commit comments