@@ -59,6 +59,40 @@ function claudeSpawnActivity(input: {
5959 } ) ;
6060}
6161
62+ /** The completion the adapter synthesizes from a `<task-notification>` for an
63+ * agent it holds no spawn for: keyed by the call it knows the agent by, with
64+ * the notification's task id and the agent's final text under `data`. */
65+ function notificationReceipt ( input : {
66+ id : string ;
67+ toolCallId : string ;
68+ taskId : string ;
69+ text : string ;
70+ createdAt ?: string ;
71+ } ) : OrchestrationThreadActivity {
72+ return activity ( {
73+ id : input . id ,
74+ kind : "tool.completed" ,
75+ ...( input . createdAt ? { createdAt : input . createdAt } : { } ) ,
76+ payload : {
77+ itemType : "collab_agent_tool_call" ,
78+ toolCallId : input . toolCallId ,
79+ status : "completed" ,
80+ title : "Subagent task" ,
81+ detail : 'Agent "Fix missing-worktree bug trio" finished' ,
82+ data : {
83+ toolName : "Agent" ,
84+ input : { } ,
85+ result : {
86+ type : "tool_result" ,
87+ tool_use_id : input . toolCallId ,
88+ content : [ { type : "text" , text : input . text } ] ,
89+ } ,
90+ taskNotification : { taskId : input . taskId , status : "completed" } ,
91+ } ,
92+ } ,
93+ } ) ;
94+ }
95+
6296describe ( "projectSubagentActivity" , ( ) => {
6397 it ( "creates a roster row from a Claude Agent tool call" , ( ) => {
6498 const roster = projectSubagentActivity (
@@ -415,6 +449,116 @@ describe("projectSubagentActivity", () => {
415449 expect ( settled [ 0 ] ?. objective ) . toBe ( "Review" ) ;
416450 } ) ;
417451
452+ it ( "ignores a flag-only metadata patch that names no known agent" , ( ) => {
453+ const spawned = projectSubagentActivity (
454+ [ ] ,
455+ claudeSpawnActivity ( {
456+ id : "a1" ,
457+ kind : "tool.started" ,
458+ status : "inProgress" ,
459+ turnId : TURN_ID ,
460+ } ) ,
461+ ) ;
462+
463+ // A shell command the harness moved to the background reports the same
464+ // flag under its own tool call. It is not an agent and gets no row.
465+ const afterCommand = projectSubagentActivity (
466+ spawned ,
467+ activity ( {
468+ id : "a2" ,
469+ kind : "subagent.metadata" ,
470+ payload : { callId : "toolu_bash_background" , isBackgrounded : true } ,
471+ } ) ,
472+ ) ;
473+ expect ( afterCommand ) . toHaveLength ( 1 ) ;
474+
475+ // A resumed agent restates its depth and background flags under the call
476+ // that resumed it. Still one agent, and nothing to key a second row by.
477+ const afterResumeFlags = projectSubagentActivity (
478+ afterCommand ,
479+ activity ( {
480+ id : "a3" ,
481+ kind : "subagent.metadata" ,
482+ turnId : RESUME_TURN_ID ,
483+ payload : { callId : "toolu_01SendMessageResume" , treeDepth : 1 , isBackgrounded : true } ,
484+ } ) ,
485+ ) ;
486+ expect ( afterResumeFlags ) . toHaveLength ( 1 ) ;
487+
488+ // The same flags addressed to the spawn still land on its row.
489+ const flagged = projectSubagentActivity (
490+ afterResumeFlags ,
491+ activity ( {
492+ id : "a4" ,
493+ kind : "subagent.metadata" ,
494+ payload : { callId : SPAWN_TOOL_USE_ID , isBackgrounded : true } ,
495+ } ) ,
496+ ) ;
497+ expect ( flagged ) . toHaveLength ( 1 ) ;
498+ expect ( flagged [ 0 ] ?. isBackgrounded ) . toBe ( true ) ;
499+ expect ( flagged [ 0 ] ?. status ) . toBe ( "running" ) ;
500+ } ) ;
501+
502+ it ( "files a resumed agent's replayed report on its row by task id" , ( ) => {
503+ const spawned = projectSubagentActivity (
504+ [ ] ,
505+ claudeSpawnActivity ( {
506+ id : "a1" ,
507+ kind : "tool.started" ,
508+ status : "inProgress" ,
509+ turnId : TURN_ID ,
510+ } ) ,
511+ ) ;
512+ const linked = projectSubagentActivity (
513+ spawned ,
514+ activity ( {
515+ id : "a2" ,
516+ kind : "task.started" ,
517+ turnId : TURN_ID ,
518+ payload : {
519+ taskId : "a53e9dad4acb0ffce" ,
520+ toolUseId : SPAWN_TOOL_USE_ID ,
521+ taskType : "local_agent" ,
522+ subagentType : "claude" ,
523+ } ,
524+ } ) ,
525+ ) ;
526+
527+ // After a restart the adapter holds no spawn for the agent and files its
528+ // final report as a completion of the call that resumed it.
529+ const reported = projectSubagentActivity (
530+ linked ,
531+ notificationReceipt ( {
532+ id : "a3" ,
533+ toolCallId : "toolu_01SendMessageResume" ,
534+ taskId : "a53e9dad4acb0ffce" ,
535+ text : "## Report\n\nStep 4a done." ,
536+ createdAt : "2026-08-15T00:10:00.000Z" ,
537+ } ) ,
538+ ) ;
539+ expect ( reported ) . toHaveLength ( 1 ) ;
540+ expect ( reported [ 0 ] ) . toMatchObject ( {
541+ spawnCallId : SPAWN_TOOL_USE_ID ,
542+ status : "completed" ,
543+ resultBody : "## Report\n\nStep 4a done." ,
544+ objective : "Fix missing-worktree bug trio" ,
545+ } ) ;
546+
547+ // A report naming no known agent stands for itself: the output is kept.
548+ const orphan = projectSubagentActivity (
549+ reported ,
550+ notificationReceipt ( {
551+ id : "a4" ,
552+ toolCallId : "toolu_01Unknown" ,
553+ taskId : "unknown-task" ,
554+ text : "Lost agent output." ,
555+ createdAt : "2026-08-15T00:20:00.000Z" ,
556+ } ) ,
557+ ) ;
558+ expect ( orphan ) . toHaveLength ( 2 ) ;
559+ expect ( orphan [ 1 ] ?. resultBody ) . toBe ( "Lost agent output." ) ;
560+ } ) ;
561+
418562 it ( "still folds Codex-shaped collab items" , ( ) => {
419563 const roster = projectSubagentActivity (
420564 [ ] ,
0 commit comments