diff --git a/packages/app/src/components/agent-list.tsx b/packages/app/src/components/agent-list.tsx index 4232a63f1..0fd56320b 100644 --- a/packages/app/src/components/agent-list.tsx +++ b/packages/app/src/components/agent-list.tsx @@ -324,7 +324,7 @@ export function AgentList({ const handleAgentLongPress = useCallback( (agent: AggregatedAgent) => { - const isRunning = agent.status === "running" || agent.status === "initializing"; + const isRunning = agent.status === "running"; if (isRunning) { setActionAgent(agent); return; diff --git a/packages/app/src/hooks/use-agent-screen-state-machine.test.ts b/packages/app/src/hooks/use-agent-screen-state-machine.test.ts index b4e304e9b..f2da3318b 100644 --- a/packages/app/src/hooks/use-agent-screen-state-machine.test.ts +++ b/packages/app/src/hooks/use-agent-screen-state-machine.test.ts @@ -420,7 +420,7 @@ describe("deriveAgentScreenViewState", () => { expect(transitions.join(" -> ")).not.toContain("loading -> idle"); }); - it("keeps optimistic running status while authoritative agent is initializing", () => { + it("uses authoritative initializing status instead of optimistic running status", () => { const memory = createBaseMemory(); const input: AgentScreenMachineInput = { ...createBaseInput(), @@ -431,8 +431,8 @@ describe("deriveAgentScreenViewState", () => { const result = deriveAgentScreenViewState({ input, memory }); const ready = expectReadyState(result.state); - expect(ready.source).toBe("optimistic"); - expect(ready.agent.status).toBe("running"); + expect(ready.source).toBe("authoritative"); + expect(ready.agent.status).toBe("initializing"); }); it("hands off to authoritative once agent reaches running", () => { diff --git a/packages/app/src/hooks/use-agent-screen-state-machine.ts b/packages/app/src/hooks/use-agent-screen-state-machine.ts index 6e9766c84..9a6ea48e2 100644 --- a/packages/app/src/hooks/use-agent-screen-state-machine.ts +++ b/packages/app/src/hooks/use-agent-screen-state-machine.ts @@ -100,8 +100,7 @@ function updateInitialSyncFailureMemory(args: { function shouldUseOptimisticCreateFlowAgent(input: AgentScreenMachineInput): boolean { return ( - input.continuity.kind === "optimistic-create" && - (!input.agent || input.agent.status === "initializing" || input.agent.status === "idle") + input.continuity.kind === "optimistic-create" && (!input.agent || input.agent.status === "idle") ); } diff --git a/packages/app/src/screens/workspace/workspace-screen.tsx b/packages/app/src/screens/workspace/workspace-screen.tsx index 1004b8a5d..301866a3a 100644 --- a/packages/app/src/screens/workspace/workspace-screen.tsx +++ b/packages/app/src/screens/workspace/workspace-screen.tsx @@ -2404,7 +2404,7 @@ function WorkspaceScreenContent({ const agent = useSessionStore.getState().sessions[normalizedServerId]?.agents?.get(agentId) ?? null; const closePolicy = resolveCloseAgentTabPolicy(agent); - const isRunning = agent?.status === "running" || agent?.status === "initializing"; + const isRunning = agent?.status === "running"; if (isRunning && closePolicy.kind === "archive-on-close") { const confirmed = await confirmDialog({ diff --git a/packages/app/src/subagents/archive-subagent.test.ts b/packages/app/src/subagents/archive-subagent.test.ts index 68280d4ec..460653561 100644 --- a/packages/app/src/subagents/archive-subagent.test.ts +++ b/packages/app/src/subagents/archive-subagent.test.ts @@ -68,16 +68,15 @@ describe("resolveArchiveSubagentDialog", () => { }); }); - it("uses running copy for initializing subagents", () => { + it("does not use running copy for initializing subagents", () => { expect( resolveArchiveSubagentDialog({ title: "Starting child", status: "initializing", }), ).toEqual({ - title: "Archive running subagent?", - message: - "Starting child is still running. Archiving it will stop the subagent and remove it from the track.", + title: "Archive subagent?", + message: "Remove Starting child from the track. The subagent will be archived.", confirmLabel: "Archive", cancelLabel: "Cancel", destructive: true, diff --git a/packages/app/src/subagents/archive-subagent.ts b/packages/app/src/subagents/archive-subagent.ts index 26a431199..bc860bf1e 100644 --- a/packages/app/src/subagents/archive-subagent.ts +++ b/packages/app/src/subagents/archive-subagent.ts @@ -24,7 +24,7 @@ export function resolveArchiveSubagentDialog( input: ResolveArchiveSubagentDialogInput, ): ConfirmDialogInput { const subagentLabel = resolveSubagentLabel(input.title) ?? "this subagent"; - const isRunning = input.status === "running" || input.status === "initializing"; + const isRunning = input.status === "running"; return { title: isRunning ? "Archive running subagent?" : "Archive subagent?", diff --git a/packages/app/src/utils/sidebar-agent-state.test.ts b/packages/app/src/utils/sidebar-agent-state.test.ts index 74f02eba8..53130f3d4 100644 --- a/packages/app/src/utils/sidebar-agent-state.test.ts +++ b/packages/app/src/utils/sidebar-agent-state.test.ts @@ -35,7 +35,7 @@ describe("deriveSidebarStateBucket", () => { ).toBe("attention"); }); - it("treats initializing agents as running", () => { + it("does not count initializing agents as running", () => { expect( deriveSidebarStateBucket({ status: "initializing", @@ -43,6 +43,6 @@ describe("deriveSidebarStateBucket", () => { requiresAttention: false, attentionReason: null, }), - ).toBe("running"); + ).toBe("done"); }); }); diff --git a/packages/protocol/src/agent-state-bucket.test.ts b/packages/protocol/src/agent-state-bucket.test.ts index 86add2e4c..3c5d281b3 100644 --- a/packages/protocol/src/agent-state-bucket.test.ts +++ b/packages/protocol/src/agent-state-bucket.test.ts @@ -50,7 +50,7 @@ describe("deriveAgentStateBucket", () => { ).toBe("attention"); }); - it("treats initializing agents as running for workspace buckets", () => { + it("does not count initializing agents as running for workspace buckets", () => { expect( deriveAgentStateBucket({ status: "initializing", @@ -58,7 +58,7 @@ describe("deriveAgentStateBucket", () => { requiresAttention: false, attentionReason: null, }), - ).toBe("running"); + ).toBe("done"); }); }); diff --git a/packages/protocol/src/agent-state-bucket.ts b/packages/protocol/src/agent-state-bucket.ts index 9fe42bda8..2973152f1 100644 --- a/packages/protocol/src/agent-state-bucket.ts +++ b/packages/protocol/src/agent-state-bucket.ts @@ -26,7 +26,7 @@ export function deriveAgentStateBucket(input: AgentStateBucketInput): WorkspaceS if (input.status === "error" || input.attentionReason === "error") { return "failed"; } - if (input.status === "running" || input.status === "initializing") { + if (input.status === "running") { return "running"; } if (input.requiresAttention) { diff --git a/packages/server/src/server/session.workspaces.test.ts b/packages/server/src/server/session.workspaces.test.ts index 99d668119..e0392a124 100644 --- a/packages/server/src/server/session.workspaces.test.ts +++ b/packages/server/src/server/session.workspaces.test.ts @@ -4201,7 +4201,25 @@ test("buildWorkspaceDescriptorMap computes statusEnteredAt from runtime agent fi expect(descriptor.statusEnteredAt).toBe(updatedAt); } - // 3. Highest-priority across all buckets: a "needs_input" agent beats + // 3. A root agent that is still initializing does not make the workspace + // look like it is actively working. + { + const { session, workspace } = setupSession(); + const updatedAt = "2026-05-12T09:45:00.000Z"; + session.listAgentPayloads = async () => [ + makeAgent({ + id: "agent-initializing", + cwd: workspace.cwd, + status: "initializing", + updatedAt, + }), + ]; + const descriptor = await buildDescriptor(session, workspace.workspaceId); + expect(descriptor.status).toBe("done"); + expect(descriptor.statusEnteredAt).toBe(updatedAt); + } + + // 4. Highest-priority across all buckets: a "needs_input" agent beats // a "running" agent beats a "done" agent. statusEnteredAt is the winning // bucket's newest agent timestamp. { @@ -4235,7 +4253,7 @@ test("buildWorkspaceDescriptorMap computes statusEnteredAt from runtime agent fi expect(descriptor.statusEnteredAt).toBe(needsInputUpdatedAt); } - // 4. Same-bucket: keep the previous bucket entry time even when newer + // 5. Same-bucket: keep the previous bucket entry time even when newer // agents contribute to the same winning bucket. { const { session, workspace } = setupSession();