Repository navigation
Conversation
…s servers (stablyai#11210) OpenCode and other HTTP-hook-only agents never emit OSC 9999, so on a `--serve` runtime with no renderer their working/idle status reached the agent-hook cache (and worktree.ps) but never session.tabs — the only feed the desktop worktree-card dot reads. Mirror the stablyai#7970 OSC fix for the hook path: - getFreshRetainedAgentStatusForMobileTab also consults the agent-hook cache by pane key, so headless hook-only agents surface in the session.tabs projection. - classifyAgentTitle treats OpenCode's native `OC |` title as agent-owned so the hook working state isn't suppressed as a reclaimed shell. - the onAgentStatus hook listener resolves the pane PTY and calls touchMobileSessionSnapshotsForPty to republish, matching the OSC 9999 / synthetic-title push paths.
📝 WalkthroughWalkthroughThe runtime now falls back to fresh agent-hook snapshots when retained OSC 9999 status is unavailable, including support for OpenCode native titles. The agent-hook listener resolves the pane’s PTY and triggers mobile session snapshot republishing for headless operation. New tests cover fresh hook status, stale-status filtering, and republishing after hook payload changes. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…s-synchronisation # Conflicts: # src/main/runtime/orca-runtime.ts
|
An adjacent OMP case helps distinguish the boundary of this headless snapshot projection fix. Using Windows paired client 1.4.224 + Linux headless server 1.4.224 + fresh OMP 18.10.4, a pane split during an isolated This is upstream authority/state loss, unlike the original #11210 case where the host had correct hook state and only I have not tested this PR branch or reproduced the original OpenCode-only projection failure on 1.4.224. The maintainer's #11210 reply points to the unified store work in #19785. Please keep the host-retention and client-publication checks separate when determining which parts of this PR remain necessary; this OMP observation is not a request to expand a projection fix into a second lifecycle implementation. Detailed isolated reproduction: comment on #24436. AI assistance disclosure: prepared with an OpenAI coding assistant via OMP, using my reported behavior and local runtime diagnostics/source inspection. Reproduction and validation limits are stated above. |
ELI5
When Orca runs as a background server (no app window) and you connect from a laptop or phone, agents like OpenCode could be actively working while every worktree card showed no activity dot — remote views looked idle. This teaches the server to pass those agents’ working / needs-your-attention signals through to paired desktop and mobile clients, so the usual yellow spinner and amber dot appear exactly as they do locally. No new buttons or screens; existing indicators simply fill in where they were stuck blank.
Summary
On a remote Orca server running in headless
--servemode (no renderer window), the orange agent-activity dots never reach the paired desktop client for HTTP-hook-only agents like OpenCode — even though the agent is actively working andlast-status.jsonupdates live. The desktop worktree-card dot readsagentStatusByPaneKey, which for remote environments is populated only fromsession.tabssnapshots; in headless those snapshots never carried hook-only agent status. This mirrors the gap #7970 closed for OSC 9999, but no equivalent existed for the HTTP-hook path OpenCode uses.Fixes #11210.
Screenshots
Visual change: the working/idle activity dot (yellow spinner / amber "needs you") now appears on the remote worktree card and Agents feed for OpenCode (and other HTTP-hook-only agents) running on a headless
--serveserver, where it previously never appeared. No new UI element is introduced — existing indicators are now populated.(Screenshot to be attached from a paired Mac client on request; this change was verified on the live
--servehost viaworktree ps --jsonshowingstate: "working"whilesession.tabslackedtab.agentStatus.)Testing
pnpm typecheck(node + cli + web, clean)pnpm lint(full pipeline incl. oxlint, switch-exhaustiveness, reliability-gates, max-lines-ratchet, localization — clean)pnpm test— ran the affected scopes (src/main,src/shared): 19,692 passed. The 8 failures are pre-existing environmental integration tests unrelated to this change (Azure/Bitbucket/Gitea hosted-review real HTTP API calls, system-SSH transport, updater network check, one output-frame fuzz timeout on a slow CI box).pnpm build— not run in this dev environment (Electron production build); change is logic-only with no build-graph impact.src/main/runtime/headless-hook-agent-status.test.ts: hookworkingsurfaces insession.tabswithout graph-synced agentStatus; stale status (past 30 min) is not surfaced;touchMobileSessionSnapshotsForPtyrepublishes after a hook change.AI Review Report
Reviewed the three coordinated changes against the existing OSC 9999 / synthetic-title push paths they mirror.
Risks checked:
onAgentStatuslistener now resolves a pane→pty id and callstouchMobileSessionSnapshotsForPtyon every hook event. OpenCode throttles streamed parts to 250 ms server-side, andtouchMobileSessionSnapshotsForPtyuses the existing coalesced fanout (not an immediate emit), so the cost is bounded and matches the OSC/synthetic paths. No new per-event allocation beyond a pane-key map lookup.getFreshRetainedAgentStatusForMobileTabnow consults both the OSC retained store and the agent-hook cache. The hook cache is only read when the OSC store has no entry for the pane (the existingif (!retained)guard), so OSC-emitting agents are unaffected; the hook fallback applies only to hook-only agents. This complements (does not duplicate) upstream'sgetHookAgentRowForPane, which carries identity (providerSession/agentType) for native chat rather than live working/idle state.classifyAgentTitlenow also returns'agent'for OpenCode's nativeOC |title. Verified this only affects the two suppression filters insideorca-runtime.ts(used to decide whether to keep/suppress hook status), and that stale-clearing still works: when the shell reclaims the pane the title stops beingOC |and reverts to'neutral', clearing the dot.touchMobileSessionSnapshotsForPtywas madeprivate→ public; it is now also called from the hook listener inindex.ts. No other behavioral change.Cross-platform compatibility (macOS / Linux / Windows): the change is server-side runtime/IPC logic with no platform-specific code paths — no keyboard shortcuts, shortcut labels, file-path assumptions, shell behavior, or Electron platform APIs are touched. The pane-key/pty resolution and the agent-hook cache are platform-agnostic. Verified identical behavior is expected on all three platforms; the headless
--servetopology (the bug scenario) is Linux, while the desktop client may be macOS/Windows.Security Audit
getPtyIdForPaneKey(paneKey)resolves an internal pane key to a pty id via the existing trusted registry; the hook cache (getAgentStatusSnapshotFn) is already the trusted convergence point for SSH-relayed and local hook payloads. The new code only reads from it.exec/spawn/shell paths added.X-Orca-Agent-Hook-Token; the websocket E2EE handshake and runtime auth token are untouched. The change only re-routes already-authenticated in-process status data into an existing snapshot projection.touchMobileSessionSnapshotsForPty) and reuses the existingonAgentStatuscallback; no new renderer-facing IPC channel or new remotely-reachable RPC method is exposed. Remote/mobile clients receive status only through the existing authenticatedsession.tabssubscription.No follow-up security work required.
Notes
ingestRemote).pnpmshim was broken during verification; sub-pnpmsteps were run via acorepack-backed PATH shim. CI is unaffected.