diff --git a/src/Capacitor.Cli.Core/Harness/Claude/ClaudeChatRules.cs b/src/Capacitor.Cli.Core/Harness/Claude/ClaudeChatRules.cs index 4a28c5433..de65a7701 100644 --- a/src/Capacitor.Cli.Core/Harness/Claude/ClaudeChatRules.cs +++ b/src/Capacitor.Cli.Core/Harness/Claude/ClaudeChatRules.cs @@ -158,6 +158,7 @@ public IReadOnlyList Runs(CanonicalEvent evt, AcpEventEnvelope raw) { case "completed": outcome = RunOutcome.Done; break; case "failed": outcome = RunOutcome.Failed; break; case "killed": outcome = RunOutcome.Stopped; break; + case "stopped": outcome = RunOutcome.Stopped; break; default: return []; } return [new RunSignal.Finished(callId, agentId, outcome, evt.Timestamp)]; diff --git a/test/Capacitor.Cli.Core.Tests.Unit/Harness/Claude/ClaudeChatRulesTests.cs b/test/Capacitor.Cli.Core.Tests.Unit/Harness/Claude/ClaudeChatRulesTests.cs index 6bf814fcd..c1d32f9e7 100644 --- a/test/Capacitor.Cli.Core.Tests.Unit/Harness/Claude/ClaudeChatRulesTests.cs +++ b/test/Capacitor.Cli.Core.Tests.Unit/Harness/Claude/ClaudeChatRulesTests.cs @@ -554,6 +554,17 @@ public async Task A_notification_cut_off_before_its_closing_tag_still_finishes() await Assert.That(finished.Outcome).IsNull(); } + /// A resumed Claude Code reports a background agent the previous process left running this way: + /// keyed by the agent id alone, with a status of its own. + [Test] + public async Task A_notification_for_an_agent_the_previous_process_left_running_finishes_it_as_stopped() { + var line = """{"type":"user","timestamp":"2026-10-22T13:42:55.148Z","origin":{"kind":"task-notification"},"promptSource":"system","message":{"role":"user","content":"\na9202cd3d93195cce\n/tmp/a9202cd3d93195cce.output\nstopped\nBackground agent \"Review Task 12 (spec + quality)\" didn't finish before the previous session ended\nNo completion record was found for it in the previous session.\n"}}"""; + var finished = (RunSignal.Finished)R(line).Runs.Single(); + await Assert.That(finished.CallId).IsNull(); + await Assert.That(finished.AgentId).IsEqualTo("a9202cd3d93195cce"); + await Assert.That(finished.Outcome).IsEqualTo(RunOutcome.Stopped); + } + [Test] public async Task A_notification_status_is_matched_without_regard_to_case() { var finished = (RunSignal.Finished)R(Notification(originKind: true, status: "Completed")).Runs.Single();