mirror of
https://github.com/stablyai/orca.git
synced 2026-10-09 00:02:39 +00:00
* feat(agent-status): show Claude subagent child rows and gate premature done A Claude pane that spawned background subagents/teammates showed a green done check the moment the lead's turn ended, even while a background review loop was still running. Orca now tracks the pane's live children from Claude hook events and: - keeps the pane 'working' while at least one child is working (Stop is gated; Claude wakes the lead when a child finishes, so the pane resolves to done on the follow-up Stop with an empty roster) - renders the children as indented child rows under the pane's sidebar row (name/type + working/idle dot), reusing the existing lineage UI Tracking is lifecycle-primary: SubagentStart/SubagentStop/TeammateIdle (newly registered hooks) plus child-origin tool events (they carry agent_id) own the roster. Stop's background_tasks is folded only where unambiguous — verified live on Claude Code 2.1.207 that teammates report status "running" while idle-alive and their task ids never match lifecycle agent_ids, so the list cannot decide teammate working-ness. Child-origin events no longer overwrite the lead's tool/prompt caches (a live AskUserQuestion card survives child churn); a child's own PermissionRequest records waitingAgentId so only that child's progress or death clears the wait. The interrupted flag survives the gated window, inferred interrupts sync the lead record and refuse while a child works, and hydration reseeds the roster after a restart. * fix(agent-status): drop identity icon on subagent child rows The child's agentType carries its NAME (e.g. "pr-reviewer"), which is not an iconable agent and rendered the unknown "?" glyph. Nesting under the parent row already conveys identity. * fix(agent-status): restore displaced lead state and reconcile phantom subagents Four review findings from the adversarial pass on the subagent child-row feature: - Stash the lead state a child-induced wait displaces (ClaudeLeadTurnState.stateBeforeWait) and restore it when the wait clears, instead of inventing 'working' — a lead that had already stopped left the pane spinning forever after the roster drained, since the done-gate only ever downgrades done → working. - Tag snapshot-seeded and background_tasks-recreated roster entries (backgroundTasksAuthoritative) and demote them when a PRESENT background_tasks list omits their id. A phantom child seeded before a restart could otherwise gate the pane 'working' indefinitely in teams sessions, whose task list is never empty. Live activity clears the tag so lifecycle-tracked teammates keep their state. - Match teammate ids with a hyphen-free suffix after `a<name>-` so TeammateIdle for "lane" cannot idle "lane-hooks"'s rows or clear its pending permission wait. - Route turn-boundary events (Stop/StopFailure/UserPromptSubmit) that carry a KNOWN child agent_id through the child-driven re-emit instead of adopting them as lead state, and tie the prompt-cache new-turn reset to lead-origin events so child refreshes can't blank the prompt label. --------- Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>