mirror of
https://github.com/stablyai/orca.git
synced 2026-09-25 16:02:38 +00:00
* feat(agent-status): publish the lead agent's own state beside the combined row state
Every status producer folded the main agent's state together with live child
work into one `state`, so a lead that had finished while a subagent still ran
read `working` and its own state was lost. The row now also carries
`lead: { state, outcome?, stateStartedAt }`, admitted by the one payload
normalizer on the relay wire, IPC and disk, and published from the Claude hook
lane, the structured host ingest and renderer bridge, Grok (now on the shared
fold) and Codex (own combine kept). The persisted child-only boundary flag is
derived from `lead` plus child evidence and no longer written; old rows map
onto `lead` at hydrate. Combined `state` and `workingMode` are unchanged for
every reader; a cross-lane parity table pins that, with the cancelled-turn
watch-loop story recorded as a known divergence.
* fix(agent-status): make Orca's inferred interrupt the primary source of a Claude lead cancellation
Current Claude Code sends no hook at all on a cancel and no is_interrupt on
Stop, so the cancellation enters the lead record from the server's inferred
interrupt and rides into the next real Stop; is_interrupt on a turn boundary
stays as the secondary source for builds that send it. Comments, the store
reference and the parity table say so; no suppression changes.
* docs(agent-status): the child-only boundary comment now describes the persisted shell fact
The old sentence said a hydrated row no longer carries the shell fact, which is
the opposite of the mechanism: claudeRunningNonAgentTask is persisted precisely
so hydration can read it, and only a pre-lead row lacks it — reading as
shell-free, the same assertion its legacy flag made at write time.
* rename the lead fact to mainAgent: the main agent's own state
* docs(agent-status): the inferred cancel comes from Ctrl+C, not Esc
* fix(agent-status): an inferred interrupt keeps an already settled main agent, and the row verdict docs name its inferred source
* fix(agent-status): a child-induced wait publishes the main agent state it displaced
* fix(agent-status): decide child-held Claude rows from the saved main agent fact
Restart seeds the Claude main agent from the row's saved mainAgent whenever it
settled and no shell held the row, instead of re-deriving a child-only shape.
OSC cannot settle or repaint a row child agents hold open, including a row
waiting on a child's permission prompt. A sticky child permission prompt still
records the main agent's own progress, and OSC repaints and inferred answers
keep the shell fact beside the main agent they preserve.
* fix(agent-status): keep a finished turn's main agent verdict and clock with that turn
A Claude SessionStart restarts the main agent's clock instead of inheriting the
previous session's last Stop. A Grok idle prompt or session end, and a late
Codex root Stop after an inferred cancel, restate the same finished turn, so
they keep its recorded verdict; only a new turn clears it.
* test(agent-status): publish the Grok verdict restatement past the late-event window
* docs(agent-status): describe hydrate seeding and the OSC refusal from the saved main agent fact
* fix(agent-status): push a held child permission row when its main agent changes
* fix(agent-status): keep the shell fact on a held child permission row so restart does not settle it
* docs(agent-status): note the held child permission row carries the shell fact and is pushed
* fix(agent-status): pair the Claude shell fact with the main agent at the one row-build point
Every non-hook rewrite (terminal-title repaint, inferred answer, held child
permission) had to re-carry the shell fact beside `mainAgent`, and each one that
forgot let a restart settle a row while a shell still ran. The row builder now
pairs the fact once: a listener event restates it, any other write keeps it only
while `mainAgent` is unchanged. Restart seeds a settled main agent only when the
row says no shell ran, and legacy child-only rows map to that explicitly.
A held child permission now also accepts the main agent event's background
evidence, as it already accepts its `mainAgent`, so the child's drain no longer
settles a row a shell still holds. The renderer keeps a previous `mainAgent`
only for writers that never carry one, so a hook row without it matches the
host snapshot.
* test(agent-status): pin that restart never seeds a main agent from a row silent about its shell
* docs(agent-status): the row builder pairs the shell fact with the main agent, and restart seeds only on an explicit no-shell
* test(agent-status): name the legacy-row case parameter for what it holds
* docs(agent-status): name which rows carry the main agent fact