Repository navigation
fix(native-chat): the desktop declares structured chat support to paired Orca servers - #24204
Conversation
…ity, not its own chat setting A host's experimentalStructuredNativeChat decided whether any paired client could reach agentSession.* at all, and whether session.tabs.* showed it structured tabs. That setting is the host user's own launch preference: whether a new agent opens as a chat or a terminal is decided by whoever launches it. Using it as admission control meant a client whose own preference was "structured chat" was refused on a host whose preference was "terminal", and chats opened while the setting was on were withheld from mobile once it was turned off. The gate now asks one thing: did the client advertise agent-session.structured.v1 (in-process callers negotiate nothing and are always admitted). Tab projection and restore follow the same rule. With the setting no longer gating anything, the separate cleanup gate (close, cancel, unsubscribe, release), which existed only so those kept working after the setting was switched off, is identical to the main gate and is folded into it. The settings listener that republished tabs when the setting changed is removed, since projection no longer depends on it. The host setting still picks the default for launches that start on the host itself (agent.launch from mobile, orchestration worker-start).
…red hosts The desktop renderer advertised agent-session.structured.v1 (and the Claude, turn-item and background-task capabilities that go with it) to its own main process but not to a paired Orca server. The server therefore refused every agentSession.* call from the desktop and stripped structured chat tabs out of the tab list it published to it, so a structured chat running on a paired server never appeared on the desktop, even though the renderer already mirrors a host's agent-session tabs and drives each one against the server that owns its workspace. The same renderer reads structured chats on either host, so the remote Electron list now carries the same structured-session capabilities as the local one, and the capability test pins that nothing is advertised only locally.
…nes and old servers keep terminals Hosts advertise agent-session.structured.client-launch-mode.v1: they admit structured sessions by client capability alone. A remote client that does not advertise it (phones released before agent.launch) asks createSupport to pick the launch mode, so the host keeps answering that with its own setting, exactly as before. Cleanup methods keep their own named gate so a future admission condition cannot make close or cancel refusable.
… brennanb2025/remote-structured-chat-drive
…n module protocol-version.ts is at its line budget; the list is what the desktop advertises to paired hosts, not the host's own contract.
Paired hosts and the desktop's own main process then answer createSupport by the workspace rather than by their own chat setting.
… brennanb2025/remote-structured-chat-drive
…chat setting says The structured chat setting decides only what new agents open as. With it off, this machine's structured chats used to be hidden while the host, which no longer reads the setting, still reported them to the workspace activation gate, so a workspace holding only a chat opened empty. The local chat mirror and its startup restore now run whatever the setting says, the continue-after-restart offer follows the chats that exist, and the setting's copy says it applies to new agents.
… brennanb2025/remote-structured-chat-drive
…ed-chat-capability-admission # Conflicts: # src/main/runtime/rpc/methods/structured-agent-session-admission.test.ts
… brennanb2025/remote-structured-chat-drive
Round 1 ran the local chat mirror for everyone so existing chats show whatever the setting says. That gave every desktop a permanent session-tabs listener, which turns on the runtime's phone replication paths, plus two full session-tab censuses at startup, and made the browser client mirror its remote host a second time. The runtime now says whether it holds structured chats: its structured host is built only when saved chats were restored at startup or a client created one here, and it announces the moment one is built. The mirror, the startup restore and the continue-after-restart offer run only when the setting launches chats or the host holds some, and never in the browser client. A chat a paired client creates here with the setting off still appears at once. The chat behaviour settings show wherever chats exist, and the setting's copy says it picks what new agents open as. The toggle-off teardown this made dead is removed.
… brennanb2025/remote-structured-chat-drive
… brennanb2025/remote-structured-chat-drive
… brennanb2025/remote-structured-chat-drive # Conflicts: # src/main/ipc/desktop-renderer-runtime-capabilities.test.ts # src/shared/protocol-version.ts
… not once its host is built Session history, resume preparation, terminal resume commands and replay-safe phone launches all build the structured host for users who never had a chat, which turned on the chat mirror and the structured-only settings rows until the next restart. The signal is now derived from the host's records (or a records file still owed its import) and pushed when the first chat is restored or created. A throwing listener no longer fails the install that fired it.
… brennanb2025/remote-structured-chat-drive
… brennanb2025/remote-structured-chat-drive
…at on this host starts with A chat on a paired server starts with the server's saved model and options, which the desktop could not read, so its picker showed a guess. createSupport's answer, which the desktop already waits for before a paired launch, now also carries that seed as a new optional field (older clients ignore it). Create and createSupport read it through one resolver so they cannot drift.
… brennanb2025/remote-structured-chat-drive
…nto its own module Merging main left protocol-version.ts one line over the max-lines limit on this branch. The list of capabilities the desktop advertises to a paired host moves, unchanged, into electron-remote-runtime-client-capabilities.ts, the module the next PR in the stack already uses for it; importers point there.
… brennanb2025/remote-structured-chat-drive # Conflicts: # src/main/ipc/desktop-renderer-runtime-capabilities.test.ts # src/shared/electron-remote-runtime-client-capabilities.ts
…ed-chat-capability-admission # Conflicts: # src/main/ipc/desktop-renderer-runtime-capabilities.test.ts
…paired server receives Every paired transport sends the shared remote base plus the Electron list, so the divergence test now compares that union with the renderer's local list instead of the declared Electron list. A capability added only to the shared base can no longer slip past it. The two base-only capabilities it surfaced are recorded: skills.install-result.v2 has no local caller; the authoritative-inventory label is read by the local tabs sync but dropped by main, and is marked unsettled. The turn-item and both background-task-stop capabilities were already sent through the shared base, so the Electron list no longer repeats them. The wire set is unchanged; this PR's real change on the wire is structured.v1, the Claude structured capability and the client launch-mode capability.
… mode, so retrying an existing chat works with the setting off
… brennanb2025/remote-structured-chat-drive
…eateSupport answer; a launch-mode client gets supported plus the seed
Review status: ready for review (step 2 of 3)The problem: a structured Claude chat running on a paired Orca server (started on the server itself, or from a phone) never showed up on the desktop. The desktop never told paired servers that it can show structured chats, so the servers hid every one of them from it. What changes for you: chats that already run on a paired server now appear in that workspace on your desktop. You can read them, send messages, stop them and close them there, and they show up in Agent Session History. Starting a new agent in a paired-server workspace still opens a terminal until #24205. Nothing changes for workspaces on this computer. Fixed during review (head
Deferred (low severity or existing before this PR; none blocks this PR):
Verified:
Not verified:
|
|
| STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY, | ||
| CLAUDE_STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY, |
There was a problem hiding this comment.
Paired chats can route locally
If a local and paired host publish the same worktree ID and the paired workspace is not active, these capabilities make the paired chat visible, but its pane chooses an RPC target from the worktree ID rather than the chat’s host. The ambiguous ID yields no remote environment, so the pane targets the local runtime. Reading or sending to the paired chat then reaches the wrong host.
Knowledge Base Used: Agent workspaces and sessions
| // Unsettled, not a decision: the local tabs sync reads the census's `authoritative` label | ||
| // (local-structured-session-tabs-sync/inventory-refresh.ts), which main drops without this. | ||
| SESSION_TABS_AUTHORITATIVE_INVENTORY_RUNTIME_CAPABILITY |
There was a problem hiding this comment.
Parity test accepts unresolved mismatch
The new parity test accepts the missing local authoritative-inventory capability as an exception even though the comment calls it “unsettled.” Without that capability, main omits the authoritative label from local session.tabs.listAll replies, while the renderer reads it to mark ordinary refreshes authoritative. Recording the mismatch as an accepted exception lets the test pass without protecting that local behavior.
Knowledge Base Used: Desktop application platform
There was a problem hiding this comment.
ℹ️ No critical issues — one open question on a recorded capability divergence, plus a stale test comment.
Reviewed changes
- The paired-server capability list gains structured chat.
ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIESnow advertisesagent-session.structured.v1, its.claude.v1companion, andagent-session.structured.client-launch-mode.v1, so a #24203 server shows the desktop its structured chats and serves the desktop's requests on them. The local (DESKTOP_RENDERER_RUNTIME_CLIENT_CAPABILITIES) behavior is unchanged, and the CLI/browser/mobile lists are untouched. - The divergence test now models the paired host.
PAIRED_HOST_RECEIVESisremoteRuntimeClientCapabilities(ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES), which matches how every paired transport wraps the list (remote-runtime-request-connection.ts:240,remote-runtime-shared-control-connection.ts:216,remote-runtime-request-socket.ts:67,remote-runtime-subscription-transport.ts:69), and the test asserts the desktop list is a subset of it withREMOTE_ONLY_BY_DECISIONas the only difference.
ℹ️ Nitpicks
src/main/runtime/rpc/methods/structured-agent-session-send-compatibility.test.ts:51appendsSTRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITYtoELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES, which now already contains it, and the "gains the structured surface as its own capability" comment is stale. Harmless — the append can be dropped.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
| // Unsettled, not a decision: the local tabs sync reads the census's `authoritative` label | ||
| // (local-structured-session-tabs-sync/inventory-refresh.ts), which main drops without this. | ||
| SESSION_TABS_AUTHORITATIVE_INVENTORY_RUNTIME_CAPABILITY |
There was a problem hiding this comment.
This records SESSION_TABS_AUTHORITATIVE_INVENTORY_RUNTIME_CAPABILITY as remote-only, but the comment says the local tabs sync reads the census's authoritative label. Since the renderer advertises DESKTOP_RENDERER_RUNTIME_CLIENT_CAPABILITIES to its own main, the label is stripped from every local response, so that branch is inert locally. Is that intended, or should the capability also join the local list?
Technical details
# The local authoritative-inventory label path is unreachable
## Affected sites
- `src/main/ipc/desktop-renderer-runtime-capabilities.test.ts:61-63` — records the divergence the comment itself describes
- `src/main/runtime/rpc/methods/session-tabs-inventory.ts:47` — `projectInventory` keeps `authoritative` only when `clientUnderstandsAuthoritativeInventory(context)`
- `src/main/ipc/runtime.ts:83,125` — the renderer's own `runtime:call` / `runtime:subscribe` contexts use `DESKTOP_RENDERER_RUNTIME_CLIENT_CAPABILITIES`
- `src/renderer/src/runtime/local-structured-session-tabs-sync/inventory-refresh.ts:71` and `subscription.ts:102` — read `result.authoritative` / `event.authoritative`
## Required outcome
- Decide whether the local tabs sync is meant to receive the host's `authoritative` label. If yes, add the capability to `DESKTOP_RENDERER_RUNTIME_CLIENT_CAPABILITIES`; if no, the label branches (and the `inventory-refresh.ts:56-57` rationale) are dead for local calls and should be removed or re-scoped to the remote transport.
## Open questions for the human
- Is the response-label path deliberately remote-only, with local cleanup driven solely by the explicit `options.authoritative` repair lane?…ability-admission' into brennanb2025/remote-structured-chat-drive
…tructured-chat-drive # Conflicts: # src/main/ipc/desktop-renderer-runtime-capabilities.test.ts # src/shared/electron-remote-runtime-client-capabilities.ts
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Important Review skippedReview was skipped as selected files did not have any reviewable changes. ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review. 📝 WalkthroughWalkthroughThe Electron remote runtime client now advertises structured agent-session, Claude structured-session, and client-selected launch-mode capabilities. Desktop renderer capability tests update the recorded remote-only decisions, check launch-mode behavior for both a paired host and the renderer’s main process, and verify capability differences against the paired host. Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to The new capabilities reach paired servers, and no merge-blocking issue was established. Merge after normal checks. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The expanded functionality remains behind pairing authentication and existing session controls. No introduced security vulnerability was established, but session authority and recovery behavior for newly eligible desktop connections were not fully verified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
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 |
…tructured-chat-drive
…at owns the workspace (#24205) * fix(native-chat): a host admits structured sessions by client capability, not its own chat setting A host's experimentalStructuredNativeChat decided whether any paired client could reach agentSession.* at all, and whether session.tabs.* showed it structured tabs. That setting is the host user's own launch preference: whether a new agent opens as a chat or a terminal is decided by whoever launches it. Using it as admission control meant a client whose own preference was "structured chat" was refused on a host whose preference was "terminal", and chats opened while the setting was on were withheld from mobile once it was turned off. The gate now asks one thing: did the client advertise agent-session.structured.v1 (in-process callers negotiate nothing and are always admitted). Tab projection and restore follow the same rule. With the setting no longer gating anything, the separate cleanup gate (close, cancel, unsubscribe, release), which existed only so those kept working after the setting was switched off, is identical to the main gate and is folded into it. The settings listener that republished tabs when the setting changed is removed, since projection no longer depends on it. The host setting still picks the default for launches that start on the host itself (agent.launch from mobile, orchestration worker-start). * fix(native-chat): the desktop declares structured chat support to paired hosts The desktop renderer advertised agent-session.structured.v1 (and the Claude, turn-item and background-task capabilities that go with it) to its own main process but not to a paired Orca server. The server therefore refused every agentSession.* call from the desktop and stripped structured chat tabs out of the tab list it published to it, so a structured chat running on a paired server never appeared on the desktop, even though the renderer already mirrors a host's agent-session tabs and drives each one against the server that owns its workspace. The same renderer reads structured chats on either host, so the remote Electron list now carries the same structured-session capabilities as the local one, and the capability test pins that nothing is advertised only locally. * feat(native-chat): open structured chats on the paired server that owns the workspace With the structured-chat default on, an agent launched in a workspace that lives on a paired Orca server always opened as a terminal (or the terminal-backed chat view). Three things kept it off the structured path: the launch check refused every host but this machine, a remote workspace was handed to the host-published terminal path before the structured route was even considered, and the structured launch pipeline sent create and every follow-up call to this machine's runtime. A workspace's owning runtime is fixed, so the pipeline now derives it from the workspace instead of assuming this machine (structured-agent-session-owner.ts, the same derivation the chat pane already uses to read a session). The launch intent carries that target; the pre-create support check, create, the publication check and fence read, the launch prompt send, held option picks, the "focus this chat" marker, the placeholder tab's host, and tab close/purge all use it. The launch check now accepts a paired server and asks that server's own capabilities (read from the status the client already cached for it) rather than this machine's. An SSH workspace stays terminal-backed: no Orca runtime runs there. The host still answers createSupport before anything is created, so an older server that refuses shows the failure in the chat tab. A chat the user closed before its create landed is now also retired on the paired server when it publishes, as the local sync already does. Orchestration workers placed on another runtime are unchanged: federation creates terminal agents only. * fix(native-chat): negotiate client-chosen launch mode so released phones and old servers keep terminals Hosts advertise agent-session.structured.client-launch-mode.v1: they admit structured sessions by client capability alone. A remote client that does not advertise it (phones released before agent.launch) asks createSupport to pick the launch mode, so the host keeps answering that with its own setting, exactly as before. Cleanup methods keep their own named gate so a future admission condition cannot make close or cancel refusable. * refactor(runtime): keep the Electron client capability list in its own module protocol-version.ts is at its line budget; the list is what the desktop advertises to paired hosts, not the host's own contract. * fix(native-chat): the desktop declares it picks each launch mode itself Paired hosts and the desktop's own main process then answer createSupport by the workspace rather than by their own chat setting. * fix(native-chat): pin each structured chat to the host it was launched on - Route: a paired server opens a chat only when it advertises the client-chosen launch mode; an older server keeps its terminal. Its capabilities come from the store's host status, not the compatibility cache that is empty after boot or reconnect. - A launch command override is this machine's: the route applies it only locally, and a host's createSupport refuses on its own override. - The owning host is resolved once, from the same value the route used, and carried on the launch intent, its persisted record (legacy records load as local), the provisional tab and every mirrored chat tab. Close, purge, retry and reload read it instead of re-deriving it from a worktree id two hosts can share; an owner that cannot be named refuses. - Cancellation tombstones record their host: only that host's authoritative inventory retires one, restored cleanup closes it there, and a paired host's tombstone expires after 30 days if it never answers. - A paired server's frame settles launches it published, as the local inventory already does for this machine. * fix(native-chat): a paired server that declines a chat opens its terminal instead createSupport only reads, so both of its non-answers are settled before anything is created: - A paired server that answers it cannot run the chat (a WSL repo, a Claude account mismatch, its own launch command override) closes the chat tab and opens the terminal the route would have chosen, with a notice saying why. This machine's own decline stays a failed chat. - A host that could not be asked closes the chat tab and leaves one failure toast, instead of a lingering "could not confirm" chat. * test(native-chat): a provisional chat carries its launch's host and hands pre-create failures on * chore(native-chat): justify the two type assertions this change's lines touch * test(native-chat): state why each staged test fixture is cast * fix(native-chat): chats that already exist keep showing whatever the chat setting says The structured chat setting decides only what new agents open as. With it off, this machine's structured chats used to be hidden while the host, which no longer reads the setting, still reported them to the workspace activation gate, so a workspace holding only a chat opened empty. The local chat mirror and its startup restore now run whatever the setting says, the continue-after-restart offer follows the chats that exist, and the setting's copy says it applies to new agents. * fix(native-chat): the browser client keeps its host terminal on paired servers A browser client whose own preferences turn structured chat on took the structured route for every paired-server workspace, but its handshake never says it reads structured sessions, so the server refused the chat and the user got a failed chat tab where a host terminal used to open. The route for a paired host now also asks what this client advertises to it: the desktop's list does, the browser client's does not. Its handshake list is now a named constant the route reads, so the two cannot drift. The chat setting's copy now says it runs on paired Orca servers too; WSL and SSH hosts still use terminal chat. * fix(native-chat): a retried launch a paired server declines opens its terminal too A launch restored after a reload settles only through its Retry, so a declining paired server left a failed chat there while a first launch got the server's terminal and a notice. The chat's Retry now hands the same pre-create failures to the same replacement, carrying the prompt the launch had staged. * refactor(native-chat): a paired host's cancelled-chat record ends on its 30-day TTL The paired census re-read a host's whole inventory after every authoritative frame to retire tombstones, and a tombstone restored after a reload needed a second such frame, so in practice it retired nothing. A tombstone guards a random session id and is inert once stale; the chat is already closed on its host whenever a frame shows it. The census, its trigger in the mirror layer and its cleanup are removed; the owner-scoped tombstones, close-on-sight, the TTL and publication marking from frames stay. * fix(native-chat): a chat's pane and status read from the host recorded on its tab The chat pane and its sidebar status still derived the host from the workspace id, which two hosts can share; a paired chat in a non-active same-id workspace was read from this machine. Both now read the owner stamped on the tab, as close, purge and publication already do. * fix(native-chat): "Resume in chat" follows the terminal resume's host rule Agent Session History offered "Resume in chat" for a conversation recorded on this machine into a paired server's workspace, where its transcript does not exist. A chat now resumes a conversation only on the host that recorded it, as the terminal resume does, and that host is the one asked whether it can resume history. * fix(native-chat): the chat setting says older paired servers keep terminal chat * test(native-chat): pin that a host advertises the client-chosen launch mode * fix(native-chat): mirror this machine's chats only where it holds them Round 1 ran the local chat mirror for everyone so existing chats show whatever the setting says. That gave every desktop a permanent session-tabs listener, which turns on the runtime's phone replication paths, plus two full session-tab censuses at startup, and made the browser client mirror its remote host a second time. The runtime now says whether it holds structured chats: its structured host is built only when saved chats were restored at startup or a client created one here, and it announces the moment one is built. The mirror, the startup restore and the continue-after-restart offer run only when the setting launches chats or the host holds some, and never in the browser client. A chat a paired client creates here with the setting off still appears at once. The chat behaviour settings show wherever chats exist, and the setting's copy says it picks what new agents open as. The toggle-off teardown this made dead is removed. * test(native-chat): route a paired-server launch over the capability lists both sides really advertise * test(native-chat): record install listeners without a cast * fix(native-chat): a paired server admits a chat before any of it exists here The desktop opened a paired server's chat tab, launch record, queued prompt and focus intent before asking the server, so a "no" needed a replacement that undid and redid all of it, and every piece it missed was a bug: the workspace deselected, the caller told "failed" while a terminal ran its prompt, the caller's arguments and other queued prompts lost, and a create whose reply was lost treated as never sent. A paired launch now asks the server first and commits nothing until it answers. Admitted opens the chat as before. Declined runs the caller's own launch as the server's terminal, with the existing notice (a resume fails instead, having no terminal equivalent). Unreachable opens nothing and names the server in one toast. The new-tab launcher reports the host's surface for paired workspaces, as it did before paired chats, with the prompt delivery of whichever surface got the prompt. The replacement and its error classes are gone, and the probe inside a launch is back to its old meaning: a "no" is a failed chat with Retry, and no answer leaves "Could not confirm" with Retry and the prompt kept, here as on this machine. * fix(native-chat): mirror this machine's chats only once it holds one, not once its host is built Session history, resume preparation, terminal resume commands and replay-safe phone launches all build the structured host for users who never had a chat, which turned on the chat mirror and the structured-only settings rows until the next restart. The signal is now derived from the host's records (or a records file still owed its import) and pushed when the first chat is restored or created. A throwing listener no longer fails the install that fired it. * fix(native-chat): a fork's reveal never seeds a terminal beside the surface the launcher opens Forking into a paired-server workspace revealed it as if nothing would open there, so the reveal created a blank host terminal beside the forked chat (and beside a forked agent terminal on main). The launcher always opens the fork's surface itself, so the reveal now says so for every surface, as the fix-checks launch already does. * fix(native-chat): a declined direct launch keeps the caller's CLI args; an unreachable resume toasts once When a paired server declines a "Fix checks" chat in a new workspace, the terminal that opens instead now carries the recipe's saved CLI arguments, launch platform and launch source, as the terminal route did. "Resume in chat" to a server that cannot be reached showed the admission's "Could not reach" toast and the vault's generic one; the admission marks its failure notified and the vault adds nothing. * fix(native-chat): a declined background create opens its terminal without switching workspaces Since #23974 a worktree create the user moved away from must not pull them onto the new workspace. When a paired server declined that create's chat, the fallback terminal opened as a new agent tab, whose host create selects the workspace. The create now opens its own agent terminal the way main's background branch does: in place from the request's startup plan (so its CLI args carry), without selecting the workspace. A create the user is still watching keeps the new-tab fallback. * test(native-chat): name the launch's host in main's new outbox fence test Main's new staging-failure test calls settleStructuredAgentLaunchPrompt without the target this PR made required; it is a local launch, as in the sibling tests. * fix(native-chat): a paired server's new chat shows no model until the server reports the one it started A chat on a paired server starts with the server's saved model and options, but the picker showed this desktop's saved selection (or the catalog default) until the server reported a model, and a pick made in that window was remembered on the server under that guessed model. A paired launch now carries no desktop seed, and until the server reports its model the picker names no model and takes no picks. Local chats are unchanged. * test(native-chat): seed the paired repo without a cast The repo literal already satisfies Repo, so the changed-lines cast gate has nothing to excuse. * feat(native-chat): createSupport reports the saved selection a new chat on this host starts with A chat on a paired server starts with the server's saved model and options, which the desktop could not read, so its picker showed a guess. createSupport's answer, which the desktop already waits for before a paired launch, now also carries that seed as a new optional field (older clients ignore it). Create and createSupport read it through one resolver so they cannot drift. * fix(native-chat): a paired server's new chat shows the selection the server will start it with The paired server now names its saved model and options in the admission answer the desktop already waits for. That seed goes into the launch intent and its persisted record, so the picker shows the server's model at once, stays pickable like a local chat, and remembers picks on the server under that model; a reload shows the same. The locked picker remains only for a server too old to name a seed. Also moves host admission and launch-outcome tracking into their own modules: the latest main merge left structured-agent-session-launch.ts over the max-lines limit. * test(native-chat): expect the launch intent's new seed argument in exact-call assertions * refactor(protocol): move the Electron remote client capability list into its own module Merging main left protocol-version.ts one line over the max-lines limit on this branch. The list of capabilities the desktop advertises to a paired host moves, unchanged, into electron-remote-runtime-client-capabilities.ts, the module the next PR in the stack already uses for it; importers point there. * fix(native-chat): a paired chat with no saved server model is pickable; Retry shows the server's current seed A server whose user never saved a chat model sends no seed, and the desktop showed a locked, model-only picker for it, although that is the common case: no server that can admit a paired chat predates the seed field. Such a chat now behaves like a local chat with no saved model: the CLI default, pickable. The lock and its snapshot helper are gone. Retry kept the first admission's seed while the create probe, which already runs on every attempt, reported the server's current one and dropped it. The probe's seed now replaces a paired launch's seed and the picker's, so a retried chat shows what its create will run. * test(cross-version): stub the launch seed resolver createSupport now reads * test(protocol): pin the desktop capability divergence against what a paired server receives Every paired transport sends the shared remote base plus the Electron list, so the divergence test now compares that union with the renderer's local list instead of the declared Electron list. A capability added only to the shared base can no longer slip past it. The two base-only capabilities it surfaced are recorded: skills.install-result.v2 has no local caller; the authoritative-inventory label is read by the local tabs sync but dropped by main, and is marked unsettled. The turn-item and both background-task-stop capabilities were already sent through the shared base, so the Electron list no longer repeats them. The wire set is unchanged; this PR's real change on the wire is structured.v1, the Claude structured capability and the client launch-mode capability. * fix(native-chat): the desktop tells its own host it picks each launch mode, so retrying an existing chat works with the setting off * docs(native-chat): name the real exit for the released-phone createSupport rule * fix(native-chat): the route reads the capabilities a paired host actually receives The renderer decided whether a paired host would admit a chat from the desktop's Electron list, but every desktop transport sends that list plus the shared remote base. They agreed only because the route's checks happened to sit in both. The route input is now built with the same remoteRuntimeClientCapabilities the transports use (the browser client already sends its list as is), and a test pins each against the real handshake. * test(cross-version): a released client still gets the host-setting createSupport answer; a launch-mode client gets supported plus the seed * test(native-chat): let main's child-records test resolve each chat's owner Main's new test mocks worktree-runtime-owner with only the runtime environment id, but the status projection in this PR also resolves each structured chat's owner from the worktree. The mock keeps the module's real exports and overrides only what the test pins. * fix(deps): take #24204's lockfile that the merge reverted * test(native-chat): let the Codex child-approval e2e unit test resolve each chat's owner Its worktree-runtime-owner mock exported only the runtime environment id, but this PR's status projection also resolves each structured chat's owner from the worktree. The mock now keeps the module's real exports and overrides only that id, as structured-child-records-switch does. * test(native-chat): move the close-race launch cases into their own file Merging main added launch tests on both sides and took structured-agent-session-launch.test.ts past the 800-line limit. The three cases where a tab close races a launch move to structured-agent-session-launch-close-race.test.ts, with the same setup the other split launch suites copy.
…24962) * fix(opencode): bind legacy attach status to its TUI pane Adapt the official v1 TUI API to the existing pane reporter and learn structural session identity only after execution-host admission. Preserve known creators, gate new reports to capable hosts, and register the legacy TUI entry without changing user settings or overlay targets. Credit werlang for the same-directory investigation in #22838 and #22847; no source from that PR is copied. (cherry picked from commit d9eeb028a23a66b78b08538a5ebf6052499ec24f) * fix(opencode): fence legacy TUI viewers before creator attribution Use the execution host's existing admission policy on the physical TUI pane and launch token before rewriting to a session creator or mutating the launch-token cache. Preserve live viewers, frozen server stamps and OpenCode 2 behavior. Add HTTP regressions for retired panes, closed tabs, replaced tokens and relay retirement, plus current-launch, alias and compatibility controls. Follow-up to #22838 and @werlang's original #22847; preserves the original intentional creator attribution without copying that PR's source. * fix(opencode): preserve current plugin exports in legacy TUI wrapper Keep the current server, setup, id and other default export entries when adding the legacy TUI entry. Cover their preservation and seed the ACL fixtures with the separate installed TUI/config bytes. This completes the current-main port of the legacy identity replacement for issue #22838, carrying @werlang's original PR #22847 contribution. * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c * Skip store notifications when refreshed work items are unchanged (#24530) An identical forced refresh previously returned an empty Zustand patch, creating a new root state and notifying every subscriber. It now returns the current state after renewing the existing freshness timestamp. Real row or metadata changes still publish once. * Read project activity once while sorting the sidebar (#24549) Reuse the existing pure recent rank once per actual entry tuple within each synchronous sort; discard the lookup after sorting. * Skip impossible link and tag matches in docs search results (#24646) * Skip impossible HTML matches when formatting docs search results After the existing link-removal phase, skip the unchanged HTML regex only when the current string has no closing delimiter. * Skip impossible link and tag matches in docs search results Skip the five unchanged link regexes when their protected-code input lacks ]; skip the unchanged HTML regex when its post-link input lacks >. * Decode complete transcript lines without copying their bytes (#24546) Decode each single owned Buffer synchronously; preserve concatenation for multipart records and remove a redundant tail array copy. * Clear unused speech worker timers after errors and exit (#24924) Call the existing idle timer cleanup when private current-worker state is cleared; keep current-worker guards, transcript/error order, deliberate warmth and stop deadline unchanged. * Reuse documentation search excerpts during result navigation (#24574) Memoize the existing pure excerpt renderer by complete raw text for the current result array, retaining original rendering as a miss fallback. * Append subagent handoffs without recopying their message list (#24672) Append each message reference to its private call-local scope list; retain the final merge and existing ordering. * Cancel plugin retry timers when their fetch is replaced (#24700) Reuse the existing timer clear block immediately after the fetch generation advances; preserve live retries and all state publications. * Avoid rebuilding visible file paths for single-row selection (#24743) Skip the visible path array only for keyboard replacement selection; the existing replacement branch never reads that order. * Reuse prepared reads while searching saved agent conversations (#24535) Use schema-complete session columns to enable the existing bounded statement cache without caching result rows. * Reuse discovered mobile chunks during static traversal (#24774) Iterate the existing live visited Set in FIFO discovery order instead of maintaining a second shifted queue; both actual callers own untouched esbuild JSON metadata. * Skip unused image-size calculations in mobile web browser requests (#24941) Use the existing mobile density budget only for mobile view; pass the existing constant to the existing assembler for web/default mode, where that argument is discarded. No cache, policy, request or native path changes. * Skip diff analysis after a result has been discarded (#24711) Move the unchanged pure render-limit calculation after both existing generation and section-token rejection fences. * Skip late browser grab toasts after their surface closes (#24727) Reuse the existing mounted-owner ref at the toast presentation entry while preserving all admitted extraction/screenshot and clipboard completion. * Classify native chat waiting messages once (#24771) Use the existing native filter traversal to populate a fresh waiting array, keeping the original predicate, policy, projection and output ordering while classifying each actual private slot once. * Skip discarded Kanban pruning for an empty selection (#24782) Guard only the existing open pruning branch when both its private selected Set and nullable anchor are empty; retain all original pre-guard projections and nonempty/anchor-only/public-helper behavior. * Index discovered test files once during shard selection validation (#24532) Verified selection plans previously validated each selected filename with a scan of all discovered files. One per-call Set now handles membership checks. Exact source/discovery checks, nonempty selection, fallback to all tests, shard balancing and manifests remain intact. * Clear the watchdog benchmark heartbeat when CPU sampling fails (#24802) Move the existing initial CPU observation and histogram enable inside the existing try/finally so their failures clear the sampler's owned heartbeat, preserving successful operation order and original errors. * Reuse the parsed notification when leasing a push delivery (#24645) * Reuse the parsed notification when leasing a push delivery Pass the notification already parsed for the dismissal check into the existing private delivery builder. * Reuse the parsed notification when leasing a push delivery Pass the notification already parsed for the dismissal check into the existing private delivery builder. * Update README downloads badge * Let retired-cache GC observations settle across the existing six-turn budget (#24967) * Collect test-selection evidence when full unit tests fail (#24955) * Collect advisory unit-selection evidence from failed full runs * Trigger checks after retargeting the evidence fix to main * Check each project repository once while filtering mobile cards (#24540) Reuse exact raw source/slug matching decisions within one project filter call, preserving the matcher, membership, negative matches, output order and identity. * Skip renderer callbacks after their request has ended (#24631) Reuse the existing pending-request identity check before starting its deferred renderer callback. * Decode single-piece saved-session tails without copying them (#24632) Decode the existing owned Buffer directly when the EOF tail has one piece; preserve the existing concatenation for multiple pieces. * Avoid irrelevant scroll-action searches in Mac snapshots (#24731) Check the current pure action name before searching for vertical scroll actions in the same immutable array. * Stop copying every retained browser page before attachment (#24553) Find the first page/generation match directly in the existing insertion-ordered Map instead of copying all page references into an array. * Reuse event byte sizes when relay watchers notify several clients (#24558) Store the existing grouped numeric byte-size array on the already call-local watcher batch sizing object, for reuse by later chunking clients. * Stop building unused import candidates in the test planner (#24611) Replace the existing ordered extension map/find with a loop that forms each candidate only when its existing lookup is reached. * docs(terminal): explain local macOS/Linux shell startup files Document the actual login/interactive shell startup-file order and existing shell setup behavior. Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(editor): recognize Ruby task and configuration files Add Ruby task/configuration filenames to the existing generated language associations. Co-authored-by: ggbdpq <ggbdpq@gmail.com> Co-authored-by: Neil <neil@stably.ai> * Speed up large Markdown Find and render oversized tables (#24948) * Speed up large Markdown Find and render oversized tables * Poll table preview geometry outside hidden renderers * Preserve Markdown navigation through refresh and tab restoration * Confirm Markdown restoration when refreshed content is ready * Trace table refresh positions and update Unicode search reference * Recognize queued measurement scrolls before restoring Markdown anchors * Rebuild Markdown Find ranges after renderer components change * fix(source-control): generate clean OpenCode messages locally and over SSH (#24613) * fix(source-control): generate clean OpenCode answers on local and SSH hosts Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: 64bb15e3f20799a21f108c849b0bdff83c692712 fix(source-control): generate clean OpenCode answers on local and SSH hosts Use configured models and JSON answer/error events, preserve run-first arguments, and handle the precise v2 variant rejection. Hydrate SSH execution-host PATH through the existing bounded login environment resolver before direct spawning. Credits: andy-murr (PR #5197 SSH environment intent) and coelho-doti (PR #13065 argument-order intent). Original-commit: 1b60ec5d11132a5fed0695faea5de782a228a8e5 fix(source-control): retry inline OpenCode model and variant options Original-commit: 98fdecc7a33ef1571dbf2854f309e4bfa1ec4300 Preserve OpenCode named errors without a data message Restacked-from: 98fdecc7a33ef1571dbf2854f309e4bfa1ec4300 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776) * fix(ci): run mobile typechecks without concurrent dependency refresh * test(ci): check effective Linux E2E package list * test(ci): preserve the mobile production compiler barrier --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * test(terminal): restore the live fish fixture prerequisites (#24947) A restored pane waits for the initial status replay before subscribing to PTY output. This fixture never settled that replay, so fish printed its mode-2031 arm before the renderer connected. Its PTY API also omitted the reset-input listener required by the serializer, aborting attachment. Settle and dispose the existing startup-snapshot registration and provide the same reset-listener mock used by the other PTY tests. The real fish child-stdin assertions and timeouts remain unchanged. No production change. * fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640) Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: f707cde14ab8cb2670b4076916cdfb7e28c79983 fix(shortcuts): defer TUI editing chords in terminal-first mode Original-commit: 0c6348e49e0d968e0170961d294a018adceaa9f3 docs(shortcuts): describe deferred preview terminal chords Original-commit: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Align worktree history shortcut metadata with terminal conflict policy Restacked-from: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * Register supervised Qoder China and Qwen Code (#24616) * Add Qoder session history and search with real CLI coverage * Allow the real Qoder marker file to end with a newline * Keep Qoder tool output out of history previews and search * Keep Qoder search pages readable by older clients * Verify persisted Qoder history after a real generated and resumed task * Negotiate Qoder filters before searching an older execution host * Combine search client imports for the CI plugin gate * Keep the relay search oracle aligned with legacy agent filtering * Register supervised Qoder China and Qwen lifecycle integration * Cover Qoder China mobile assets and mixed-host resume gates * Verify Qoder provider tags against the older released wire parser * Verify China and Qwen keep independent Windows hook scripts * Verify Qoder registrations against the installed older Windows release * test(qoder): align search capability contracts and pin old-host fencing * fix(qoder): rank exact picker identities and command aliases first * test(qoder): preserve the regional CLI shared icon expectation Keep the full bundled-asset and no-remote-image checks, with an explicit shared-logo basename for Qoder China. The map also works with older catalog type unions. * fix(qoder): align China catalog entry with fallback order --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * Use the measured pnpm lookup policy automatically in hosted root CI (#24951) * Select lookup automatically for the measured hosted root-install profile * Record hosted automatic-mode cold cache publication proof * fix: bound remote generation setup and honor OpenCode option terminators Count execution-host profile resolution inside the existing request deadline, cancel its waiter promptly, and pass only the remaining time to the child. Shared bounded profile probes keep their existing cache lifetime; the SSH transport margin is unchanged. Read OpenCode output format from active final-argv options before -- so literal prompt arguments cannot select the JSON finalizer. Fresh exact-source controls reproduce nine failures before; 139 related checks pass after, including primary/fallback delays, deadline boundaries, cancellation, parser metadata, and SSH lanes. Node typecheck and strict changed-file lint pass. * Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692) * feat(antigravity): bridge IDE history into new CLI conversations * fix(antigravity): preserve fresh-launch model and environment for IDE references * fix(antigravity): forward IDE history opt-in through desktop IPC * fix(antigravity): rebuild remote IDE reference startup on its host * fix(antigravity): register IDE continuation action labels * fix(antigravity): confine IDE references and bound metadata reads * fix(antigravity): localize IDE continuation badges * Preserve scanner service cache assertions and refresh Antigravity opening metadata * Preserve Antigravity opening joins and target folder runtime authority * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c * fix(opencode): enforce deadline through executable startup Keep synchronous Windows PATH resolution and child startup within the existing request budget. --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(persistence): preserve projectGroupOrder on restart for flat folder-scan groups Retain saved project ranks when the project remains in its folder-scan group. Co-authored-by: lurunzi <lurunzi@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(runtime): reclaim temp files orphaned by interrupted mobile store writes Reuse the existing stale temporary-file cleanup policy when each mobile store opens. Co-authored-by: LDH1103 <ldh517525@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(terminal): show actionable copy for missing folder workspace paths Show the existing folder-path failure with concrete recovery instructions. Co-authored-by: Wayn_Liu <wayntingliu@gmail.com> Co-authored-by: Neil <neil@stably.ai> * docs: reference local orca.yaml and .worktreeinclude Document the existing workspace configuration, include/copy rules and sharing behavior. Co-authored-by: Neil <neil@stably.ai> * fix(orchestration): allow model selection for OMP workers Pass an explicitly requested model through the existing OMP worker launch catalog. Co-authored-by: Neil <neil@stably.ai> * fix(cli): preserve primitive success results in JSON output Check for an object before inspecting screenshot fields so primitive success results remain printable. Related: https://github.com/stablyai/orca/pull/14735 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: VXNCXNX <VXNCXNX@users.noreply.github.com> * Show loaded file changes before deleting a workspace Expose up to ten already loaded changed paths without altering deletion counts, hydration or authorization. Related: https://github.com/stablyai/orca/pull/22778 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Michiel de Gooijer <mdgooijer@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(keybindings): record and match Option+digit shortcuts on macOS Use the physical digit key for explicitly assigned Mac Option+digit shortcuts while retaining modifier checks. Co-authored-by: marcuslannister <marcus@lannister.cc> Co-authored-by: Neil <neil@stably.ai> * fix(editor): don't throw closing a stale active file Recover stale active-file selection within the owning workspace before choosing a surviving editor. Related: https://github.com/stablyai/orca/pull/24715 Co-authored-by: m4air <m4air@m4airs-Air.localdomain> Co-authored-by: Neil <neil@stably.ai> * Fix Project Settings targeting for multiple local checkouts Carry the selected checkout identity into the existing project Settings action. Co-authored-by: fsmeier <1506919+fsmeier@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> * feat(documents): open CSV and TSV files from the OS Extend existing OS document associations and delivery to CSV/TSV, preserving restoration and authorization. Co-authored-by: Neil <neil@stably.ai> * feat(cli): link GitHub and GitLab items on worktree create and set Expose and validate the existing workspace link fields, preserving omitted values and provider identity checks. Related: https://github.com/stablyai/orca/pull/22609 Co-authored-by: marco song <marco.song@mvlchain.io> Co-authored-by: SongMarco <20613630+SongMarco@users.noreply.github.com> Co-authored-by: Luca Critelli <lucacri@gmail.com> Co-authored-by: Neil <neil@stably.ai> * feat(sidebar): include folder workspaces in keyboard navigation Use the rendered sidebar row order and host identity when cycling through folder and Git workspaces. Related: https://github.com/stablyai/orca/pull/10555 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: JeongUk Park <jeongph.dev@gmail.com> * fix(build): turn off MSBuild file tracking for Windows native rebuilds Default Windows native rebuilds to TrackFileAccess=false while preserving explicit caller preferences. Co-authored-by: B1nh M1nh <43268322+b1nhm1nh@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> * Fix Ctrl+M in Linux and Windows terminals Keep the Minimize menu item but disable its accelerator registration on Linux and Windows. Co-authored-by: Zhichang Yu <yuzhichang@gmail.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Related contribution: https://github.com/stablyai/orca/pull/24143 * fix(startup): read a nushell login PATH from $env.PATH Use Nushell login command syntax and preserve the actual login PATH value. Related: https://github.com/stablyai/orca/pull/22677 Co-authored-by: Kh05ifr4nD <meandSSH0219@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(cursor): run local hooks through sh for non-POSIX login shells Keep POSIX hook syntax inside one quoted sh command so the login shell can invoke it safely. Related: https://github.com/stablyai/orca/pull/22663 Co-authored-by: Kh05ifr4nD <meandSSH0219@gmail.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * Fix word wrap for both panes in side-by-side diffs Forward wrapping to both diff panes through the existing editor option path and clean up listeners. Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * fix(monaco): highlight Svelte block closers inside markup Return Svelte block closers to the existing markup tokenizer state. Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * fix(repos): keep active clone dialog open on outside clicks Ignore accidental outside dismissal only while cloning; Escape, Close and Back still cancel. Related: https://github.com/stablyai/orca/pull/24581, https://github.com/stablyai/orca/pull/23430 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance> * fix(editor): keep chat visible after closing Markdown tabs Count remaining unified chat tabs before clearing workspace selection during editor close. Related: https://github.com/stablyai/orca/pull/24273, https://github.com/stablyai/orca/pull/23760 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Honor typed starting numbers in chat ordered lists Forward the existing parsed ordered-list start attribute to both chat Markdown renderers. Related: https://github.com/stablyai/orca/pull/19765 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Frederic Barthelemy <git@fbartho.com> * Normalize base source once while checking changed-code diagnostics (#24557) Reuse the exact existing moved-code matching algorithm with run-local lazy normalization of immutable base source blocks across diagnostics. * Support real OpenCode sessions in native Chat (#24647) * Use bounded OpenCode context for vault session continuation OpenCode database and synthetic row paths are not text transcripts. Use the vault preview or captured pane context, preserving actual transcript paths containing a hash and supporting both OpenCode lanes and Windows paths. Adapted the intent of #11859 and extended it to actual installed v2 vault rows. Co-authored-by: mrcha033 <mrcha033@users.noreply.github.com> * Read real OpenCode sessions in terminal-backed native Chat Reuse the bounded AI Vault SQLite worker for v1 and v2 session pages and live updates. Keep terminal input as the real execution path and pace OpenCode Stop through its two-Escape interrupt. Co-authored-by: xodmd45-ctrl <xodmd45-ctrl@users.noreply.github.com> * fix(opencode): publish approval cards for permission requests * Send OpenCode native approval through its Enter selector * Resolve mobile Chat readability for folder workspaces * Bound OpenCode part batches and preserve v2 image attachments * Prefer live migrated OpenCode sessions over legacy copies * Consolidate mobile Chat eligibility test imports * Consolidate OpenCode SQLite protocol type imports * Update native chat settings contract for both OpenCode agents * fix(native-chat): reconcile bounded OpenCode transcript reads * fix(native-chat): dispatch OpenCode questions safely * fix(native-chat): keep native discovery and transcript windows current * feat(accounts): link standalone GLM Coding Plans (#24618) * feat(accounts): link standalone GLM Coding Plans Adapt the reviewed GLM accounts contribution to current main, retain Antigravity behavior, guard late credential results, expose storage protection, and redact quota errors. Co-authored-by: Luchong <lu740528977@gmail.com> * fix(accounts): retain GLM credential results during quota refresh * fix(accounts): make GLM credential editing desktop-only * fix(accounts): mirror the host GLM site in paired clients * fix(accounts): report unknown GLM host details and split web settings tests Apply the independently reviewed Accounts correction from697284a without the v2 adapter commits. Preserve the saved-key store and serialized write behavior. * fix(zcode): ship required GLM account translation entries * chore: record GLM reconciliation hook validation * chore: validate installed GLM commit hooks * test: complete GLM account fixtures and web API inventory --------- Co-authored-by: Luchong <lu740528977@gmail.com> * fix(native-chat): route transcript requests through shared SQLite worker * fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776) * fix(ci): run mobile typechecks without concurrent dependency refresh * test(ci): check effective Linux E2E package list * test(ci): preserve the mobile production compiler barrier --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * test(terminal): restore the live fish fixture prerequisites (#24947) A restored pane waits for the initial status replay before subscribing to PTY output. This fixture never settled that replay, so fish printed its mode-2031 arm before the renderer connected. Its PTY API also omitted the reset-input listener required by the serializer, aborting attachment. Settle and dispose the existing startup-snapshot registration and provide the same reset-listener mock used by the other PTY tests. The real fish child-stdin assertions and timeouts remain unchanged. No production change. * fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640) Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: f707cde14ab8cb2670b4076916cdfb7e28c79983 fix(shortcuts): defer TUI editing chords in terminal-first mode Original-commit: 0c6348e49e0d968e0170961d294a018adceaa9f3 docs(shortcuts): describe deferred preview terminal chords Original-commit: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Align worktree history shortcut metadata with terminal conflict policy Restacked-from: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * Register supervised Qoder China and Qwen Code (#24616) * Add Qoder session history and search with real CLI coverage * Allow the real Qoder marker file to end with a newline * Keep Qoder tool output out of history previews and search * Keep Qoder search pages readable by older clients * Verify persisted Qoder history after a real generated and resumed task * Negotiate Qoder filters before searching an older execution host * Combine search client imports for the CI plugin gate * Keep the relay search oracle aligned with legacy agent filtering * Register supervised Qoder China and Qwen lifecycle integration * Cover Qoder China mobile assets and mixed-host resume gates * Verify Qoder provider tags against the older released wire parser * Verify China and Qwen keep independent Windows hook scripts * Verify Qoder registrations against the installed older Windows release * test(qoder): align search capability contracts and pin old-host fencing * fix(qoder): rank exact picker identities and command aliases first * test(qoder): preserve the regional CLI shared icon expectation Keep the full bundled-asset and no-remote-image checks, with an explicit shared-logo basename for Qoder China. The map also works with older catalog type unions. * fix(qoder): align China catalog entry with fallback order --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * Use the measured pnpm lookup policy automatically in hosted root CI (#24951) * Select lookup automatically for the measured hosted root-install profile * Record hosted automatic-mode cold cache publication proof * fix(native-chat): keep OpenCode history usable at read limits Continue past failed database probes while preserving discovery cancellation. Verify rows displaced by a capped tail before deciding whether to replace history. Represent oversized v1/v2 rows with the existing omission text and stable cursors. * Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692) * feat(antigravity): bridge IDE history into new CLI conversations * fix(antigravity): preserve fresh-launch model and environment for IDE references * fix(antigravity): forward IDE history opt-in through desktop IPC * fix(antigravity): rebuild remote IDE reference startup on its host * fix(antigravity): register IDE continuation action labels * fix(antigravity): confine IDE references and bound metadata reads * fix(antigravity): localize IDE continuation badges * Preserve scanner service cache assertions and refresh Antigravity opening metadata * Preserve Antigravity opening joins and target folder runtime authority * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c --------- Co-authored-by: mrcha033 <mrcha033@users.noreply.github.com> Co-authored-by: xodmd45-ctrl <xodmd45-ctrl@users.noreply.github.com> Co-authored-by: Luchong <lu740528977@gmail.com> Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * Drain removal fixture jobs before resetting and deleting their records (#24977) * Reuse measured Electron preparation for current Terminal Perf refs (#24968) * feat(jcode): add Jcode as a supported TUI agent with managed hooks Ports PR #10521 onto current main: agent catalog, managed hook service, agent-status listener, session resume, AI Vault parser, per-pane daemon isolation, and Source Control AI support. Co-authored-by: Neil <neil@stably.ai> * feat(jcode): evidence-backed status pipeline (turn_start, live pre_tool, questions) Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): register vault fixture, dynamic model discovery, script refresher Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): keep finished-turn detail so completion notifications fire Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): show the prompt in agent rows instead of jcode's repainting title Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): pre-warm the per-pane daemon so a cold runtime dir cannot time out Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): stop the OSC color skip from crashing every pane connect Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * refactor(jcode): fold three reverse-scan copies into one, reuse the shared hook POST The jcode journal reader, the Claude transcript reader and the Command Code transcript reader each carried their own copy of the same reverse chunked line scan; they now share one tested helper. jcode's managed hook script drops its hand-rolled curl for buildPosixAgentHookPostCommand, which also gains it the raw-JSON transport and the --noproxy guard the bespoke copy was missing. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): narrow dynamic reads with predicates, pin the Windows hook shape CI's anti-slop audit rejects Reflect.get: parse dynamic input into a named type instead. Adds Windows script-shape tests too, since Windows is the platform this change could not be exercised on directly. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): measure the gate against the synchronous path, not the clock The absolute 1s bound was the flake CI shard 3/8 hit: it is tight enough to catch a synchronous gate on an idle laptop and too tight on a loaded runner. Measuring the same POST both ways on the same machine makes the claim a ratio, which is what the test is actually about. Mutation-checked: a synchronous gate reads 6120ms against a 1517ms observer. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): drop the wall-clock gate assertion The bound was machine-speed sensitive and flaked on CI shard 3/8 at 1525ms. The structural assertions (detached gate branch, foreground observer branch) and the no-hang stdin drain cover the same contract without a timer. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): address CodeRabbit review on #22539 - Windows posted no payload at all: the shared builder reads `payload@-` from stdin, which the gate has already drained and observer hooks never receive, so every Windows event was dropped. Write the env var to a temp file and pipe it. - The daemon pre-warm never fired for daemon-host spawns, which is the default local path; it now runs there too, and from the final env so the daemon gets the hook port and token. - A failed runtime-dir mkdir took down every local terminal, jcode or not. - removeJcodeManagedHooks matched the raw line, so a user hook whose comment mentioned the managed script was deleted; matching on Windows never worked. - A managed entry left by a copied home or a platform switch is now repointed instead of being reported as user-owned forever. - The OSC colour skip only checked launchAgent, so a command- or telemetry-named jcode pane still leaked the reply into its composer. - `['hooks']` and a commented scalar are recognised, instead of appending a second [hooks] table that makes jcode reject the whole config. - A failed tool's error is marked as tool output rather than agent prose. - The vault keeps a session's stored name, counts its tokens, and skips background_task and [Scheduled task] turns. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): read the journal once per turn, key prompts by byte offset The jcode prompt reader ran a synchronous bounded file scan plus a JSON parse on every hook event. jcode blocks on pre_tool, so a turn that ran four tools charged the user eight scans of latency it did not need — the prompt cannot change inside a turn. - Cache the journal read per pane, refreshed on the turn boundary that can change it. The cache holds the whole evidence record, since hasExplicitUserPrompt needs the transcript-evidence flag and not just the text, and it joins the existing pane-scoped lifecycle (close, rename, reset) rather than living in a module singleton. - Key a journal prompt by its absolute byte offset instead of its region-local line index. The backward scan windows the file from EOF, so appending shifted every boundary and reminted the key for a prompt that never moved; a repeated turn_end then slipped past the same-hash dedupe as a second done event with duplicate telemetry. - Pin the platform in the daemon pre-warm tests. The pre-warm is a no-op off POSIX, so the dedupe and retry cases would have passed vacuously on a Windows runner. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): quote the managed hook path, drop tools from patch prompts Three fixes, all on paths this PR could not exercise locally. The managed hook command was stored as a bare path. jcode tokenizes that string shell-style before exec'ing it directly (parse_hook_command, crates/jcode-terminal-launch/src/lib.rs): unquoted whitespace splits, and every unquoted backslash is consumed as an escape. So on Windows `C:\Users\me\.orca\agent-hooks\jcode-hook.cmd` reached exec as `C:Usersme.orcaagent-hooksjcode-hook.cmd` and no hook fired at all, and a POSIX home with a space split into two arguments. Store the path single-quoted (verbatim, backslashes included), falling back to double quotes for a path containing a single quote. Existing bare entries are already repointed by the stale-key path, and getStatus accepts both forms so the repair is not reported as a user-owned hook. The quoting helper was previously dead code that only tests called; the three production sites now use it. isJcodeManagedCommand also normalizes separators, since a `/`-only needle never matched a Windows entry. Commit-message generation feeds a staged patch to `jcode run` as the prompt — attacker-influenced text — while jcode's default profile exposes shell, read, write, and MCP. Pass `--tool-profile none`, which resolves to an empty allowed-tool set in jcode's config (base_allowed_tools), matching the read-only posture claude (plan) and codex (read-only) already take. docs/reference/jcode-hook-events.md was never actually in this PR: the repo ignores docs/** and tracks reference docs by allow-list only, so the captured-payload evidence four source comments point at was silently dropped. Allow-list it. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): pin the tool-profile flag in the generation plan too The argv assertion lives in two places; --tool-profile none only landed in one, so the plan test still expected the unrestricted argv. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(text-generation): refuse an oversized argv prompt on Linux too The pre-spawn size guard only ran on Windows. Linux caps a single argv entry at MAX_ARG_STRLEN (32 pages, 128 KiB on a 4-KiB-page host) and execve fails with E2BIG past it, so an agent that delivers the whole prompt as one argument — jcode, and the other argv-delivery agents — failed on a large staged diff with an error the user could not act on. The cap is per-argument and in bytes, which is why it is not the Windows line budget: 40k chars trips Windows and is nowhere near the Linux limit, so folding them together would have refused prompts Linux runs fine. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): register in main's remote-installer guard, drop our duplicate Rebasing onto 853 commits of main surfaced two things the earlier branch had hidden. main already owns a guard for the issue-#7253 bug class (`remote-hook-service-registry-coverage.test.ts`). This branch had added a second, near-identical one — a parallel implementation of a test that already existed, which is what AGENTS.md's reuse rule is about. Deleted ours and registered jcode in main's, which is the one that has kept pace with every agent added since. Also fixes a missing separator in the mobile icon map. `pnpm tc` does not cover `mobile/`, so only the session-route closure suite caught it. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): decompose the four files jcode pushed over max-lines Adding an agent tipped four modules past their line budget. AGENTS.md forbids a `max-lines` disable or a per-file bump, so each is split on a real seam rather than silenced: - agent-catalog.tsx keeps `AgentIcon`, which 70+ files import, and the rows move out. The rows alone exceed the 300-line budget a `.ts` file gets, so they follow the primary/secondary split this repo already uses for commit-message agent specs. - getAgentResumeArgv -> agent-resume-argv.ts, re-exported so the 18 call sites keep one import path. - isDiscoverableSessionFile/pathSegments -> session-file-discovery.ts. - remoteCodexSources -> remote-session-scanner-codex-sources.ts; Codex is the one remote agent with two CODEX_HOME roots. Also: - Records the readiness-census baseline jcode now needs. main added that gate while this branch was out; the fixture is the recorded 74-case matrix, not a hand-written one. - Restores two entries a rebase resolution silently dropped from config/tsconfig.cli.json (gitlab/project-ref-parser, startup/shell-path-probe). Nothing to do with jcode; losing them was a conflict-resolution mistake on this branch. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * feat(native-chat): open structured chats on the paired Orca server that owns the workspace (#24205) * fix(native-chat): a host admits structured sessions by client capability, not its own chat setting A host's experimentalStructuredNativeChat decided whether any paired client could reach agentSession.* at all, and whether session.tabs.* showed it structured tabs. That setting is the host user's own launch preference: whether a new agent opens as a chat or a terminal is decided by whoever launches it. Using it as admission control meant a client whose own preference was "structured chat" was refused on a host whose preference was "terminal", and chats opened while the setting was on were withheld from mobile once it was turned off. The gate now asks one thing: did the client advertise agent-session.structured.v1 (in-process callers negotiate nothing and are always admitted). Tab projection and restore follow the same rule. With the setting no longer gating anything, the separate cleanup gate (close, cancel, unsubscribe, release), which existed only so those kept working after the setting was switched off, is identical to the main gate and is folded into it. The settings listener that republished tabs when the setting changed is removed, since projection no longer depends on it. The host setting still picks the default for launches that start on the host itself (agent.launch from mobile, orchestration worker-start). * fix(native-chat): the desktop declares structured chat support to paired hosts The desktop renderer advertised agent-session.structured.v1 (and the Claude, turn-item and background-task capabilities that go with it) to its own main process but not to a paired Orca server. The server therefore refused every agentSession.* call from the desktop and stripped structured chat tabs out of the tab list it published to it, so a structured chat running on a paired server never appeared on the desktop, even though the renderer already mirrors a host's agent-session tabs and drives each one against the server that owns its workspace. The same renderer reads structured chats on either host, so the remote Electron list now carries the same structured-session capabilities as the local one, and the capability test pins that nothing is advertised only locally. * feat(native-chat): open structured chats on the paired server that owns the workspace With the structured-chat default on, an agent launched in a workspace that lives on a paired Orca server always opened as a terminal (or the terminal-backed chat view). Three things kept it off the structured path: the launch check refused every host but this machine, a remote workspace was handed to the host-published terminal path before the structured route was even considered, and the structured launch pipeline sent create and every follow-up call to this machine's runtime. A workspace's owning runtime is fixed, so the pipeline now derives it from the workspace instead of assuming this machine (structured-agent-session-owner.ts, the same derivation the chat pane already uses to read a session). The launch intent carries that target; the pre-create support check, create, the publication check and fence read, the launch prompt send, held option picks, the "focus this chat" marker, the placeholder tab's host, and tab close/purge all use it. The launch check now accepts a paired server and asks that server's own capabilities (read from the status the client already cached for it) rather than this machine's. An SSH workspace stays terminal-backed: no Orca runtime runs there. The host still answers createSupport before anything is created, so an older server that refuses shows the failure in the chat tab. A chat the user closed before its create landed is now also retired on the paired server when it publishes, as the local sync already does. Orchestration workers placed on another runtime are unchanged: federation creates terminal agents only. * fix(native-chat): negotiate client-chosen launch mode so released phones and old servers keep terminals Hosts advertise agent-session.structured.client-launch-mode.v1: they admit structured sessions by client capability alone. A remote client that does not advertise it (phones released before agent.launch) asks createSupport to pick the launch mode, so the host keeps answering that with its own setting, exactly as before. Cleanup methods keep their own named gate so a future admission condition cannot make close or cancel refusable. * refactor(runtime): keep the Electron client capability list in its own module protocol-version.ts is at its line budget; the list is what the desktop advertises to paired hosts, not the host's own contract. * fix(native-chat): the desktop declares it picks each launch mode itself Paired hosts and the desktop's own main process then answer createSupport by the workspace rather than by their own chat setting. * fix(native-chat): pin each structured chat to the host it was launched on - Route: a paired server opens a chat only when it advertises the client-chosen launch mode; an older server keeps its terminal. Its capabilities come from the store's host status, not the compatibility cache that is empty after boot or reconnect. - A launch command override is this machine's: the route applies it only locally, and a host's createSupport refuses on its own override. - The owning host is resolved once, from the same value the route used, and carried on the launch intent, its persisted record (legacy records load as local), the provisional tab and every mirrored chat tab. Close, purge, retry and reload read it instead of re-deriving it from a worktree id two hosts can share; an owner that cannot be named refuses. - Cancellation tombstones record their host: only that host's authoritative inventory retires one, restored cleanup closes it there, and a paired host's tombstone expires after 30 days if it never answers. - A paired server's frame settles launches it published, as the local inventory already does for this machine. * fix(native-chat): a paired server that declines a chat opens its terminal instead createSupport only reads, so both of its non-answers are settled before anything is created: - A paired server that answers it cannot run the chat (a WSL repo, a Claude account mismatch, its own launch command override) closes the chat tab and opens the terminal the route would have chosen, with a notice saying why. This machine's own decline stays a failed chat. - A host that could not be asked closes the chat tab and leaves one failure toast, instead of a lingering "could not confirm" chat. * test(native-chat): a provisional chat carries its launch's host and hands pre-create failures on * chore(native-chat): justify the two type assertions this change's lines touch * test(native-chat): state why each staged test fixture is cast * fix(native-chat): chats that already exist keep showing whatever the chat setting says The structured chat setting decides only what new agents open as. With it off, this machine's structured chats used to be hidden while the host, which no longer reads the setting, still reported them to the workspace activation gate, so a workspace holding only a chat opened empty. The local chat mirror and its startup restore now run whatever the setting says, the continue-after-restart offer follows the chats that exist, and the setting's copy says it applies to new agents. * fix(native-chat): the browser client keeps its host terminal on paired servers A browser client whose own preferences turn structured chat on took the structured route for every paired-server workspace, but its handshake never says it reads structured sessions, so the server refused the chat and the user got a failed chat tab where a host terminal used to open. The route for a paired host now also asks what this client advertises to it: the desktop's list does, the browser client's does not. Its handshake list is now a named constant the route reads, so the two cannot drift. The chat setting's copy now says it runs on paired Orca servers too; WSL and SSH hosts still use terminal chat. * fix(native-chat): a retried launch a paired server declines opens its terminal too A launch restored after a reload settles only through its Retry, so a declining paired server left a failed chat there while a first launch got the server's terminal and a notice. The chat's Retry now hands the same pre-create failures to the same replacement, carrying the prompt the launch had staged. * refactor(native-chat): a paired host's cancelled-chat record ends on its 30-day TTL The paired census re-read a host's whole inventory after every authoritative frame to retire tombstones, and a tombstone restored after a reload needed a second such frame, so in practice it retired nothing. A tombstone guards a random session id and is inert once stale; the chat is already closed on its host whenever a frame shows it. The census, its trigger in the mirror layer and its cleanup are removed; the owner-scoped tombstones, close-on-sight, the TTL and publication marking from frames stay. * fix(native-chat): a chat's pane and status read from the host recorded on its tab The chat pane and its sidebar status still derived the host from the workspace id, which two hosts can share; a paired chat in a non-active same-id workspace was read from this machine. Both now read the owner stamped on the tab, as close, purge and publication already do. * fix(native-chat): "Resume in chat" follows the terminal resume's host rule Agent Session History offered "Resume in chat" for a conversation recorded on this machine into a paired server's workspace, where its transcript does not exist. A chat now resumes a conversation only on the host that recorded it, as the terminal resume does, and that host is the one asked whether it can resume history. * fix(native-chat): the chat setting says older paired servers keep terminal chat * test(native-chat): pin that a host advertises the client-chosen launch mode * fix(native-chat): mirror this machine's chats only where it holds them Round 1 ran the local chat mirror for everyone so existing chats show whatever the setting says. That gave every desktop a permanent session-tabs listener, which turns on the runtime's phone replication paths, plus two full session-tab censuses at startup, and made the browser client mirror its remote host a second time. The runtime now says whether it holds structured chats: its structured host is built only when saved chats were restored at startup or a client created one here, and it announces the moment one is built. The mirror, the startup restore and the continue-after-restart offer run only when the setting launches chats or the host holds some, and never in the browser client. A chat a paired client creates here with the setting off still appears at once. The chat behaviour settings show wherever chats exist, and the setting's copy says it picks what new agents open as. The toggle-off teardown this made dead is removed. * test(native-chat): route a paired-server launch over the capability lists both sides really advertise * test(native-chat): record install listeners without a cast * fix(native-chat): a paired server admits a chat before any of it exists here The desktop opened a paired server's chat tab, launch record, queued prompt and focus intent before asking the server, so a "no" needed a replacement that undid and redid all of it, and every piece it missed was a bug: the workspace deselected, the caller told "failed" while a terminal ran its prompt, the caller's arguments and other queued prompts lost, and a create whose reply was lost treated as never sent. A paired launch now asks the server first and commits nothing until it answers. Admitted opens the chat as before. Declined runs the caller's own launch as the server's terminal, with the existing notice (a resume fails instead, having no terminal equivalent). Unreachable opens nothing and names the server in one toast. The new-tab launcher reports the host's surface for paired workspaces, as it did before paired chats, with the prompt delivery of whichever surface got the prompt. The replacement and its error classes are gone, and the probe inside a launch is back to its old meaning: a "no" is a failed chat with Retry, and no answer leaves "Could not confirm" with Retry and the prompt kept, here as on this machine. * fix(native-chat): mirror this machine's chats only once it holds one, not once its host is built Session history, resume preparation, terminal resume commands and replay-safe phone launches all build the structured host for users who never had a chat, which turned on the chat mirror and the structured-only settings rows until the next restart. The signal is now derived from the host's records (or a records file still owed its import) and pushed when the first chat is restored or created. A throwing listener no longer fails the install that fired it. * fix(native-chat): a fork's reveal never seeds a terminal beside the surface the launcher opens Forking into a paired-server workspace revealed it as if nothing would open there, so the reveal created a blank host terminal beside the forked chat (and beside a forked agent terminal on main). The launcher always opens the fork's surface itself, so the reveal now says so for every surface, as the fix-checks launch already does. * fix(native-chat): a declined direct launch keeps the caller's CLI args; an unreachable resume toasts once When a paired server declines a "Fix checks" chat in a new workspace, the terminal that opens instead now carries the recipe's saved CLI arguments, launch platform and launch source, as the terminal route did. "Resume in chat" to a server that cannot be reached showed the admission's "Could not reach" toast and the vault's generic one; the admission marks its failure notified and the vault adds nothing. * fix(native-chat): a declined background create opens its terminal without switching workspaces Since #23974 a worktree create the user moved away from must not pull them onto the new workspace. When a paired server declined that create's chat, the fallback terminal opened as a new agent tab, whose host create selects the workspace. The create now opens its own agent terminal the way main's background branch does: in place from the request's startup plan (so its CLI args carry), without selecting the workspace. A create the user is still watching keeps the new-tab fallback. * test(native-chat): name the launch's host in main's new outbox fence test Main's new staging-failure test calls settleStructuredAgentLaunchPrompt without the target this PR made required; it is a local launch, as in the sibling tests. * fix(native-chat): a paired server's new chat shows no model until the server reports the one it started A chat on a paired server starts with the server's saved model and options, but the picker showed this desktop's saved selection (or the catalog default) until the server reported a model, and a pick made in that window was remembered on the server under that guessed model. A paired launch now carries no desktop seed, and until the server reports its model the picker names no model and takes no picks. Local chats are unchanged. * test(native-chat): seed the paired repo without a cast The repo literal already satisfies Repo, so the changed-lines cast gate has nothing to excuse. * feat(native-chat): createSupport reports the saved selection a new chat on this host starts with A chat on a paired server starts with the server's saved model and options, which the desktop could not read, so its picker showed a guess. createSupport's answer, which the desktop already waits for before a paired launch, now also carries that seed as a new optional field (older clients ignore it). Create and createSupport read it through one resolver so they cannot drift. * fix(native-chat): a paired server's new chat shows the selection the server will start it with The paired server now names its saved model and options in the admission answer the desktop already waits for. That seed goes into the launch intent and its persisted record, so the picker shows the server's model at once, stays pickable like a local chat, and remembers picks on the server under that model; a reload shows the same. The locked picker remains only for a server too old to name a seed. Also moves host admission and launch-outcome tracking into their own modules: the latest main merge left structured-agent-session-launch.ts over the max-lines limit. * test(native-chat): expect the launch intent's new seed argument in exact-call assertions * refactor(protocol): move the Electron remote client capability list into its own module Merging main left protocol-version.ts one line over the max-lines limit on this branch. The list of capabilities the desktop advertises to a paired host moves, unchanged, into electron-remote-runtime-client-capabilities.ts, the module the next PR in the stack already uses for it; importers point there. * fix(native-chat): a paired chat with no saved server model is pickable; Retry shows the server's current seed A server whose user never saved a chat model sends no seed, and the desktop showed a locked, model-only picker for it, although that is the common case: no server that can admit a paired chat predates the seed field. Such a chat now behaves like a local chat with no saved model: the CLI default, pickable. The lock and its snapshot helper are gone. Retry kept the first admission's seed while the create probe, which already runs on every attempt, reported the server's current one and dropped it. The probe's seed now replaces a paired launch's seed and the picker's, so a retried chat shows what its create will run. * test(cross-version): stub the launch seed resolver createSupport now reads * test(protocol): pin the desktop capability divergence against what a paired server receives Every paired transport sends the shared remote base plus the Electron list, so the divergence test now compares that union with the renderer's local list instead of the declared Electron list. A capability added only to the shared base can no longer slip past it. The two base-only capabilities it surfaced are recorded: skills.install-result.v2 has no local caller; the authoritative-inventory label is read by the local tabs sync but dropped by main, and is marked unsettled. The turn-item and both background-task-stop capabilities were already sent through the shared base, so the Electron list no longer repeats them. The wire set is unchanged; this PR's real change on the wire is structured.v1, the Claude structured capability and the client launch-mode capability. * fix(native-chat): the desktop tells its own host it picks each launch mode, so retrying an existing chat works with the setting off * docs(native-chat): name the real exit for the released-phone createSupport rule * fix(native-chat): the route reads the capabilities a paired host actually receives The renderer decided whether a paired host would admit a chat from the desktop's Electron list, but every desktop transport sends that list plus the shared remote base. They agreed only because the route's checks happened to sit in both. The route input is now built with the same remoteRuntimeClientCapabilities the transports use (the browser client already sends its list as is), and a test pins each against the real handshake. * test(cross-version): a released client still gets the host-setting createSupport answer; a launch-mode client gets supported plus the seed * test(native-chat): let main's child-records test resolve each chat's owner Main's new test mocks worktree-runtime-owner with only the runtime environment id, but the status projection in this PR also resolves each structured chat's owner from the worktree. The mock keeps the module's real exports and overrides only what the test pins. * fix(deps): take #24204's lockfile that the merge reverted * test(native-chat): let the Codex child-approval e2e unit test resolve each chat's owner Its worktree-runtime-owner mock exported only the runtime environment id, but this PR's status projection also resolves each structured chat's owner from the worktree. The mock now keeps the module's real exports and overrides only that id, as structured-child-records-switch does. * test(native-chat): move the close-race launch cases into their own file Merging main added launch tests on both sides and took structured-agent-session-launch.test.ts past the 800-line limit. The three cases where a tab close races a launch move to structured-agent-session-launch-close-race.test.ts, with the same setup the other split launch suites copy. * feat(cli): add --unread/--read to orca worktree set Pass validated read/unread flags through the existing workspace metadata update. Contributor attribution correction: the earlier Ctrl+M squash message placed its related link after the co-author footer, so GitHub did not recognize all contributors. Preserve that credit here for https://github.com/stablyai/orca/pull/24100 and its related contribution https://github.com/stablyai/orca/pull/24143 . Related CLI link validation retained from https://github.com/stablyai/orca/pull/20036 . Co-authored-by: Raz Shlomo <1237333…
…use (#24271) * fix(notebook): cancel kernel starts when the notebook closes (#24858) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(markdown): reduce Find memory for ordinary text (#24635) * fix(markdown): avoid offset arrays for ASCII Find * test(markdown): pin ASCII Find memory budget --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(clipboard): decode uploaded images without joining all chunks (#24653) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(mobile): release file previews after their tabs close (#24655) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(editor): expire saved-file snapshots while the editor is idle (#24657) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(ai-vault): bound transcript text before joining message blocks (#24659) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(terminal): release retired status sources from the agent type cache (#24669) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(jira): expire cached attachment images while idle (#24678) * fix(jira): expire cached attachment images while idle * test(jira): preserve cache bounds and site expiry after clears --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(mobile): merge terminal backlogs without rescanning growing strings (#24680) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(terminal): release retired scrollback layouts from status routing (#24686) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(files): release expired mobile path inventories while idle (#24694) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(jira): discard detail replies after closing an issue (#24835) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(browser): avoid a redundant copy of live screencast images (#24851) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(terminal): release closed layouts while reveal frames are paused (#24721) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(quick-open): release expired legacy file inventories while idle (#24805) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(ssh): keep terminal buffers out of failed workspace sync status (#24833) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(native-chat): the desktop declares structured chat support to paired Orca servers (#24204) * fix(native-chat): a host admits structured sessions by client capability, not its own chat setting A host's experimentalStructuredNativeChat decided whether any paired client could reach agentSession.* at all, and whether session.tabs.* showed it structured tabs. That setting is the host user's own launch preference: whether a new agent opens as a chat or a terminal is decided by whoever launches it. Using it as admission control meant a client whose own preference was "structured chat" was refused on a host whose preference was "terminal", and chats opened while the setting was on were withheld from mobile once it was turned off. The gate now asks one thing: did the client advertise agent-session.structured.v1 (in-process callers negotiate nothing and are always admitted). Tab projection and restore follow the same rule. With the setting no longer gating anything, the separate cleanup gate (close, cancel, unsubscribe, release), which existed only so those kept working after the setting was switched off, is identical to the main gate and is folded into it. The settings listener that republished tabs when the setting changed is removed, since projection no longer depends on it. The host setting still picks the default for launches that start on the host itself (agent.launch from mobile, orchestration worker-start). * fix(native-chat): the desktop declares structured chat support to paired hosts The desktop renderer advertised agent-session.structured.v1 (and the Claude, turn-item and background-task capabilities that go with it) to its own main process but not to a paired Orca server. The server therefore refused every agentSession.* call from the desktop and stripped structured chat tabs out of the tab list it published to it, so a structured chat running on a paired server never appeared on the desktop, even though the renderer already mirrors a host's agent-session tabs and drives each one against the server that owns its workspace. The same renderer reads structured chats on either host, so the remote Electron list now carries the same structured-session capabilities as the local one, and the capability test pins that nothing is advertised only locally. * fix(native-chat): negotiate client-chosen launch mode so released phones and old servers keep terminals Hosts advertise agent-session.structured.client-launch-mode.v1: they admit structured sessions by client capability alone. A remote client that does not advertise it (phones released before agent.launch) asks createSupport to pick the launch mode, so the host keeps answering that with its own setting, exactly as before. Cleanup methods keep their own named gate so a future admission condition cannot make close or cancel refusable. * refactor(runtime): keep the Electron client capability list in its own module protocol-version.ts is at its line budget; the list is what the desktop advertises to paired hosts, not the host's own contract. * fix(native-chat): the desktop declares it picks each launch mode itself Paired hosts and the desktop's own main process then answer createSupport by the workspace rather than by their own chat setting. * chore(native-chat): justify the two type assertions this change's lines touch * fix(native-chat): chats that already exist keep showing whatever the chat setting says The structured chat setting decides only what new agents open as. With it off, this machine's structured chats used to be hidden while the host, which no longer reads the setting, still reported them to the workspace activation gate, so a workspace holding only a chat opened empty. The local chat mirror and its startup restore now run whatever the setting says, the continue-after-restart offer follows the chats that exist, and the setting's copy says it applies to new agents. * test(native-chat): pin that a host advertises the client-chosen launch mode * fix(native-chat): mirror this machine's chats only where it holds them Round 1 ran the local chat mirror for everyone so existing chats show whatever the setting says. That gave every desktop a permanent session-tabs listener, which turns on the runtime's phone replication paths, plus two full session-tab censuses at startup, and made the browser client mirror its remote host a second time. The runtime now says whether it holds structured chats: its structured host is built only when saved chats were restored at startup or a client created one here, and it announces the moment one is built. The mirror, the startup restore and the continue-after-restart offer run only when the setting launches chats or the host holds some, and never in the browser client. A chat a paired client creates here with the setting off still appears at once. The chat behaviour settings show wherever chats exist, and the setting's copy says it picks what new agents open as. The toggle-off teardown this made dead is removed. * test(native-chat): record install listeners without a cast * fix(native-chat): mirror this machine's chats only once it holds one, not once its host is built Session history, resume preparation, terminal resume commands and replay-safe phone launches all build the structured host for users who never had a chat, which turned on the chat mirror and the structured-only settings rows until the next restart. The signal is now derived from the host's records (or a records file still owed its import) and pushed when the first chat is restored or created. A throwing listener no longer fails the install that fired it. * feat(native-chat): createSupport reports the saved selection a new chat on this host starts with A chat on a paired server starts with the server's saved model and options, which the desktop could not read, so its picker showed a guess. createSupport's answer, which the desktop already waits for before a paired launch, now also carries that seed as a new optional field (older clients ignore it). Create and createSupport read it through one resolver so they cannot drift. * refactor(protocol): move the Electron remote client capability list into its own module Merging main left protocol-version.ts one line over the max-lines limit on this branch. The list of capabilities the desktop advertises to a paired host moves, unchanged, into electron-remote-runtime-client-capabilities.ts, the module the next PR in the stack already uses for it; importers point there. * test(cross-version): stub the launch seed resolver createSupport now reads * test(protocol): pin the desktop capability divergence against what a paired server receives Every paired transport sends the shared remote base plus the Electron list, so the divergence test now compares that union with the renderer's local list instead of the declared Electron list. A capability added only to the shared base can no longer slip past it. The two base-only capabilities it surfaced are recorded: skills.install-result.v2 has no local caller; the authoritative-inventory label is read by the local tabs sync but dropped by main, and is marked unsettled. The turn-item and both background-task-stop capabilities were already sent through the shared base, so the Electron list no longer repeats them. The wire set is unchanged; this PR's real change on the wire is structured.v1, the Claude structured capability and the client launch-mode capability. * fix(native-chat): the desktop tells its own host it picks each launch mode, so retrying an existing chat works with the setting off * docs(native-chat): name the real exit for the released-phone createSupport rule * test(cross-version): a released client still gets the host-setting createSupport answer; a launch-mode client gets supported plus the seed * fix(ai-vault): release expired host results while idle (#24766) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(orchestration): avoid loading task descriptions during promotion (#24781) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(codex): run Windows Codex on the real ~/.codex (#24356) Co-authored-by: Orca Worker <orca-worker@localhost> * fix(mobile): release callbacks retained by canceled streams (#24625) * fix(mobile): release callbacks retained by canceled streams * test(mobile): cover delayed frames after stream cancellation Preserve late-ready cleanup while rejecting canceled scrollback and terminal routing; cover unsent cancellation across browser, client events and session tabs. * test(mobile): model unavailable queued stream transport The encrypted sender rejects writes until connection setup completes. Keep existing session-tab unsubscribe attempts and assert canceled queued openers are never replayed. --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: m4air <m4air@Mac.localdomain> * fix(mobile): reduce base64 allocations for encrypted text frames (#24665) * fix(mobile): reduce base64 allocations for encrypted text frames * Correct screencast encoder comment after byte-codec extraction --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: m4air <m4air@Mac.localdomain> * fix(cursor): resume exact conversation after startup status replay (#24670) * fix(cursor): restore exact conversation after startup snapshot * fix(terminal): preserve ready snapshot reattach and isolate bridge fixtures * test(cursor): seed the real startup bridge after module resets * test(terminal): settle startup snapshots in remote restore fixtures Signed-off-by: Neil <neil@stably.ai> --------- Signed-off-by: Neil <neil@stably.ai> * fix(claude): inspect child tool IDs without rebuilding their output (#24707) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: m4air <m4air@Mac.localdomain> * fix(native-chat): remove the "still starting" notice that flashed on chat launch (#24564) * fix(native-chat): remove the "still starting" notice that flashed on chat launch Every structured chat passes through a starting phase, and the pane showed "<agent> is still starting. Messages wait until it is ready; close this chat to give up on it." for it. A 5 s grace period only narrowed the flash to starts that finish just past it. A message sent while the agent starts already counts as working, so the chat's working indicator and Stop cover that state; the notice only repeated it. Removes the notice, its copy in every locale, the delayed-status hook that existed only for it, and the per-child key the chat read only to reset it. * docs(agents): no pop-up notices for transient or internal states Records the rule the removed startup notice broke, so agents building UI show transient states through existing surfaces instead of new messages. * docs(agents): allow the common delayed loading placeholder The rule against delaying a flashing message should not forbid a quiet skeleton or spinner that waits a moment before appearing. * fix(native-chat): stop publishing which provider child is starting hostExecutionChild existed only to re-key the removed starting notice's delay. Older clients read it as optional, so omitting it only changes when their notice appears after a still-starting child is replaced. * docs(agents): narrow the status-notice rule's wording Ban 'execution host' rather than ordinary host copy, scope 'confirming' to a connection, and keep the no-delay rule where the common pattern delays. * docs(agents): let a control's own busy state wait, per the style guide The status-notice rule covers notices and status lines; a delayed in-place label swap like "Saving…" stays as STYLEGUIDE.md describes. * docs(agents): keep the status-message guideline out of the repo * fix(native-chat): no loading flash on open, one report for a failed start, no "Not reported" caption (#24588) * fix(native-chat): stop the loading flash, the doubled launch failure, and the "Not reported" caption - A structured chat no longer paints "Start a chat" or the full-pane "Loading conversation..." text before its first read settles; the pane stays blank until the history (or its absence) is known. A chat this view just started keeps its empty state through publish. - A failed chat start is said once, by the chat's own Retry line. The "Could not open <agent> chat" toast that fired beside it, and again on every failed Retry, is removed; the raw error still goes to the log. - The Fast mode switch in the options menu no longer carries a "Not reported" / "Default" caption. * fix(native-chat): show a quiet spinner if a chat's first read lasts The blank pane stayed blank with no cue for as long as the first read took, including a slow remote read or a pending resume. The pane now holds a textless spinner (announced as "Loading chat") that a CSS animation delay keeps invisible for the first 250 ms, so a quick read still paints nothing. A cancelled launch no longer holds the pane in that state; it shows what the chat shows when not launching. * test(native-chat): a refused new-tab chat start reports in its chat, not a toast The new-tab launch opens (or reuses) the chat tab before the start can fail, so its Retry line is the one report. The guard tests now pin that the chat tab exists and no toast fires, for both a refused start and one whose outcome could not be confirmed. * fix(native-chat): leave a failed resume's pane blank beside its Retry line A resumed chat whose start failed or could not be confirmed kept the loading spinner turning forever above "Chat could not be started.", though nothing was reading its history. The spinner now shows only while a read or the resuming launch is in flight. Also log a chat tab that throws while opening during worktree creation, and drop a comment that still described the removed launch-failure toast. * fix(native-chat): plain wording for chat errors and status rows (#24594) * fix(native-chat): plain wording for chat errors and status rows Replaces Orca-internal words (host, journal, transcript, outbox, process, unverifiable, "no contact", byte budgets) in native chat refusals, status rows, the skills menu, subagent and background-task state labels and the history-load error with plain language, and routes the two hard-coded English composer errors through translate(). Copy only; no behaviour change. * fix(native-chat): match chat copy to what happens and to the sidebar's words - The held-message row says Orca keeps checking, which it does: the idle sweep retries the unproven stop and a landed retry sends what waited. - An unsettled earlier message reads as unconfirmed, not undelivered. - The skills-unavailable line names SSH chats, its only cause. - Subagent and background-task rows say "no recent update", the sidebar's words for the same state, and "status unavailable" after a count; the row no longer repeats the state as a reason. * test(native-chat): find the repair row by its own text, not the old wording * fix(native-chat): word the history-repair and too-large rows in the reader's language Both rows were finished English the host wrote into the chat, so nothing could translate them. Each now names itself with a presentation, the way the compaction row does, and the chat says it through translate(). The English text stays on the row for clients that predate these presentations and for the phone. * fix(native-chat): say composer send errors with the chat's notice sentences The composer's two errors had their own wording file beside the sentence table every other chat notice uses. The send outcome now carries notice parts, worded by the same function as the rest. A refused redelivery says "Orca couldn't confirm your message reached the agent. Check the chat, then send it again if needed." (the same sentence the failed-send rework uses), and a message this client couldn't store says "Couldn't save your message. Try again." * fix(native-chat): drop the retry line, keep one name for a lost task, and say only true causes - The history error pane no longer adds "Orca keeps trying to load this chat." under its title: the read still retries on its own, but the pane says only that the chat didn't load. - A write refused as unsupported asks for an Orca update only when no reason came back, which means the host is older. A named reason (a location or agent that can't run there, no chat host, a client missing the capability) now reads "This isn't available in this chat.", since updating doesn't fix it. - A task Orca lost track of is "no recent update" everywhere; after a count it reads "2 agents with no recent update" instead of a second name. - The skills menu announces the same sentence it shows, including in SSH chats. - The row for messages held behind a previous agent reads "{{agent}} from before may still be running. Your messages will send once it stops." * fix(native-chat): a chat whose host can't run it says its history didn't load A history read refused as unsupported with a named reason left the error pane saying only "This isn't available in this chat.", which never said the chat failed to load and named nothing the reader asked for. A read now says "This chat's history couldn't be loaded."; other writes keep the shorter sentence. * Avoid repeated pnpm archive downloads in cache producers (#24927) * Let measured cache producers keep stores without downloading them * Check that restore-only callers do not publish a producer path * Enable the measured producer mode and record hosted comparisons * fix(usage): include OpenCode cached input in totals Normalize OpenCode cache reads and writes consistently across usage views, persistence and telemetry. Continues #20187. Co-authored-by: griffinmartin <griffinmartin@users.noreply.github.com> * fix(opencode): atomically install status plugin entrypoints Retain complete status plugin files during replacement, symlinks and existing permissions, including legacy Windows directory permission recovery. Fixes #24121. Continues #24131; permission-recovery review credited to pullfrog. Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> * fix(opencode): select tmux status on the execution host Track the attested tmux selected pane in the canonical status store and fence retired refreshes after asynchronous root resolution. Fixes #10039. * feat(accounts): link standalone GLM Coding Plans (#24618) * feat(accounts): link standalone GLM Coding Plans Adapt the reviewed GLM accounts contribution to current main, retain Antigravity behavior, guard late credential results, expose storage protection, and redact quota errors. Co-authored-by: Luchong <lu740528977@gmail.com> * fix(accounts): retain GLM credential results during quota refresh * fix(accounts): make GLM credential editing desktop-only * fix(accounts): mirror the host GLM site in paired clients * fix(accounts): report unknown GLM host details and split web settings tests Apply the independently reviewed Accounts correction from697284a without the v2 adapter commits. Preserve the saved-key store and serialized write behavior. * fix(zcode): ship required GLM account translation entries * chore: record GLM reconciliation hook validation * chore: validate installed GLM commit hooks * test: complete GLM account fixtures and web API inventory --------- Co-authored-by: Luchong <lu740528977@gmail.com> * fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776) * fix(ci): run mobile typechecks without concurrent dependency refresh * test(ci): check effective Linux E2E package list * test(ci): preserve the mobile production compiler barrier --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * test(terminal): restore the live fish fixture prerequisites (#24947) A restored pane waits for the initial status replay before subscribing to PTY output. This fixture never settled that replay, so fish printed its mode-2031 arm before the renderer connected. Its PTY API also omitted the reset-input listener required by the serializer, aborting attachment. Settle and dispose the existing startup-snapshot registration and provide the same reset-listener mock used by the other PTY tests. The real fish child-stdin assertions and timeouts remain unchanged. No production change. * fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640) Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: f707cde14ab8cb2670b4076916cdfb7e28c79983 fix(shortcuts): defer TUI editing chords in terminal-first mode Original-commit: 0c6348e49e0d968e0170961d294a018adceaa9f3 docs(shortcuts): describe deferred preview terminal chords Original-commit: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Align worktree history shortcut metadata with terminal conflict policy Restacked-from: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * Register supervised Qoder China and Qwen Code (#24616) * Add Qoder session history and search with real CLI coverage * Allow the real Qoder marker file to end with a newline * Keep Qoder tool output out of history previews and search * Keep Qoder search pages readable by older clients * Verify persisted Qoder history after a real generated and resumed task * Negotiate Qoder filters before searching an older execution host * Combine search client imports for the CI plugin gate * Keep the relay search oracle aligned with legacy agent filtering * Register supervised Qoder China and Qwen lifecycle integration * Cover Qoder China mobile assets and mixed-host resume gates * Verify Qoder provider tags against the older released wire parser * Verify China and Qwen keep independent Windows hook scripts * Verify Qoder registrations against the installed older Windows release * test(qoder): align search capability contracts and pin old-host fencing * fix(qoder): rank exact picker identities and command aliases first * test(qoder): preserve the regional CLI shared icon expectation Keep the full bundled-asset and no-remote-image checks, with an explicit shared-logo basename for Qoder China. The map also works with older catalog type unions. * fix(qoder): align China catalog entry with fallback order --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * Use the measured pnpm lookup policy automatically in hosted root CI (#24951) * Select lookup automatically for the measured hosted root-install profile * Record hosted automatic-mode cold cache publication proof * Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692) * feat(antigravity): bridge IDE history into new CLI conversations * fix(antigravity): preserve fresh-launch model and environment for IDE references * fix(antigravity): forward IDE history opt-in through desktop IPC * fix(antigravity): rebuild remote IDE reference startup on its host * fix(antigravity): register IDE continuation action labels * fix(antigravity): confine IDE references and bound metadata reads * fix(antigravity): localize IDE continuation badges * Preserve scanner service cache assertions and refresh Antigravity opening metadata * Preserve Antigravity opening joins and target folder runtime authority * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c * Skip store notifications when refreshed work items are unchanged (#24530) An identical forced refresh previously returned an empty Zustand patch, creating a new root state and notifying every subscriber. It now returns the current state after renewing the existing freshness timestamp. Real row or metadata changes still publish once. * Read project activity once while sorting the sidebar (#24549) Reuse the existing pure recent rank once per actual entry tuple within each synchronous sort; discard the lookup after sorting. * Skip impossible link and tag matches in docs search results (#24646) * Skip impossible HTML matches when formatting docs search results After the existing link-removal phase, skip the unchanged HTML regex only when the current string has no closing delimiter. * Skip impossible link and tag matches in docs search results Skip the five unchanged link regexes when their protected-code input lacks ]; skip the unchanged HTML regex when its post-link input lacks >. * Decode complete transcript lines without copying their bytes (#24546) Decode each single owned Buffer synchronously; preserve concatenation for multipart records and remove a redundant tail array copy. * Clear unused speech worker timers after errors and exit (#24924) Call the existing idle timer cleanup when private current-worker state is cleared; keep current-worker guards, transcript/error order, deliberate warmth and stop deadline unchanged. * Reuse documentation search excerpts during result navigation (#24574) Memoize the existing pure excerpt renderer by complete raw text for the current result array, retaining original rendering as a miss fallback. * Append subagent handoffs without recopying their message list (#24672) Append each message reference to its private call-local scope list; retain the final merge and existing ordering. * Cancel plugin retry timers when their fetch is replaced (#24700) Reuse the existing timer clear block immediately after the fetch generation advances; preserve live retries and all state publications. * Avoid rebuilding visible file paths for single-row selection (#24743) Skip the visible path array only for keyboard replacement selection; the existing replacement branch never reads that order. * Reuse prepared reads while searching saved agent conversations (#24535) Use schema-complete session columns to enable the existing bounded statement cache without caching result rows. * Reuse discovered mobile chunks during static traversal (#24774) Iterate the existing live visited Set in FIFO discovery order instead of maintaining a second shifted queue; both actual callers own untouched esbuild JSON metadata. * Skip unused image-size calculations in mobile web browser requests (#24941) Use the existing mobile density budget only for mobile view; pass the existing constant to the existing assembler for web/default mode, where that argument is discarded. No cache, policy, request or native path changes. * Skip diff analysis after a result has been discarded (#24711) Move the unchanged pure render-limit calculation after both existing generation and section-token rejection fences. * Skip late browser grab toasts after their surface closes (#24727) Reuse the existing mounted-owner ref at the toast presentation entry while preserving all admitted extraction/screenshot and clipboard completion. * Classify native chat waiting messages once (#24771) Use the existing native filter traversal to populate a fresh waiting array, keeping the original predicate, policy, projection and output ordering while classifying each actual private slot once. * Skip discarded Kanban pruning for an empty selection (#24782) Guard only the existing open pruning branch when both its private selected Set and nullable anchor are empty; retain all original pre-guard projections and nonempty/anchor-only/public-helper behavior. * Index discovered test files once during shard selection validation (#24532) Verified selection plans previously validated each selected filename with a scan of all discovered files. One per-call Set now handles membership checks. Exact source/discovery checks, nonempty selection, fallback to all tests, shard balancing and manifests remain intact. * Clear the watchdog benchmark heartbeat when CPU sampling fails (#24802) Move the existing initial CPU observation and histogram enable inside the existing try/finally so their failures clear the sampler's owned heartbeat, preserving successful operation order and original errors. * Reuse the parsed notification when leasing a push delivery (#24645) * Reuse the parsed notification when leasing a push delivery Pass the notification already parsed for the dismissal check into the existing private delivery builder. * Reuse the parsed notification when leasing a push delivery Pass the notification already parsed for the dismissal check into the existing private delivery builder. * Update README downloads badge * Let retired-cache GC observations settle across the existing six-turn budget (#24967) * Collect test-selection evidence when full unit tests fail (#24955) * Collect advisory unit-selection evidence from failed full runs * Trigger checks after retargeting the evidence fix to main * Check each project repository once while filtering mobile cards (#24540) Reuse exact raw source/slug matching decisions within one project filter call, preserving the matcher, membership, negative matches, output order and identity. * Skip renderer callbacks after their request has ended (#24631) Reuse the existing pending-request identity check before starting its deferred renderer callback. * Decode single-piece saved-session tails without copying them (#24632) Decode the existing owned Buffer directly when the EOF tail has one piece; preserve the existing concatenation for multiple pieces. * Avoid irrelevant scroll-action searches in Mac snapshots (#24731) Check the current pure action name before searching for vertical scroll actions in the same immutable array. * Stop copying every retained browser page before attachment (#24553) Find the first page/generation match directly in the existing insertion-ordered Map instead of copying all page references into an array. * Reuse event byte sizes when relay watchers notify several clients (#24558) Store the existing grouped numeric byte-size array on the already call-local watcher batch sizing object, for reuse by later chunking clients. * Stop building unused import candidates in the test planner (#24611) Replace the existing ordered extension map/find with a loop that forms each candidate only when its existing lookup is reached. * docs(terminal): explain local macOS/Linux shell startup files Document the actual login/interactive shell startup-file order and existing shell setup behavior. Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(editor): recognize Ruby task and configuration files Add Ruby task/configuration filenames to the existing generated language associations. Co-authored-by: ggbdpq <ggbdpq@gmail.com> Co-authored-by: Neil <neil@stably.ai> * Speed up large Markdown Find and render oversized tables (#24948) * Speed up large Markdown Find and render oversized tables * Poll table preview geometry outside hidden renderers * Preserve Markdown navigation through refresh and tab restoration * Confirm Markdown restoration when refreshed content is ready * Trace table refresh positions and update Unicode search reference * Recognize queued measurement scrolls before restoring Markdown anchors * Rebuild Markdown Find ranges after renderer components change * fix(source-control): generate clean OpenCode messages locally and over SSH (#24613) * fix(source-control): generate clean OpenCode answers on local and SSH hosts Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: 64bb15e3f20799a21f108c849b0bdff83c692712 fix(source-control): generate clean OpenCode answers on local and SSH hosts Use configured models and JSON answer/error events, preserve run-first arguments, and handle the precise v2 variant rejection. Hydrate SSH execution-host PATH through the existing bounded login environment resolver before direct spawning. Credits: andy-murr (PR #5197 SSH environment intent) and coelho-doti (PR #13065 argument-order intent). Original-commit: 1b60ec5d11132a5fed0695faea5de782a228a8e5 fix(source-control): retry inline OpenCode model and variant options Original-commit: 98fdecc7a33ef1571dbf2854f309e4bfa1ec4300 Preserve OpenCode named errors without a data message Restacked-from: 98fdecc7a33ef1571dbf2854f309e4bfa1ec4300 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776) * fix(ci): run mobile typechecks without concurrent dependency refresh * test(ci): check effective Linux E2E package list * test(ci): preserve the mobile production compiler barrier --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * test(terminal): restore the live fish fixture prerequisites (#24947) A restored pane waits for the initial status replay before subscribing to PTY output. This fixture never settled that replay, so fish printed its mode-2031 arm before the renderer connected. Its PTY API also omitted the reset-input listener required by the serializer, aborting attachment. Settle and dispose the existing startup-snapshot registration and provide the same reset-listener mock used by the other PTY tests. The real fish child-stdin assertions and timeouts remain unchanged. No production change. * fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640) Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: f707cde14ab8cb2670b4076916cdfb7e28c79983 fix(shortcuts): defer TUI editing chords in terminal-first mode Original-commit: 0c6348e49e0d968e0170961d294a018adceaa9f3 docs(shortcuts): describe deferred preview terminal chords Original-commit: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Align worktree history shortcut metadata with terminal conflict policy Restacked-from: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * Register supervised Qoder China and Qwen Code (#24616) * Add Qoder session history and search with real CLI coverage * Allow the real Qoder marker file to end with a newline * Keep Qoder tool output out of history previews and search * Keep Qoder search pages readable by older clients * Verify persisted Qoder history after a real generated and resumed task * Negotiate Qoder filters before searching an older execution host * Combine search client imports for the CI plugin gate * Keep the relay search oracle aligned with legacy agent filtering * Register supervised Qoder China and Qwen lifecycle integration * Cover Qoder China mobile assets and mixed-host resume gates * Verify Qoder provider tags against the older released wire parser * Verify China and Qwen keep independent Windows hook scripts * Verify Qoder registrations against the installed older Windows release * test(qoder): align search capability contracts and pin old-host fencing * fix(qoder): rank exact picker identities and command aliases first * test(qoder): preserve the regional CLI shared icon expectation Keep the full bundled-asset and no-remote-image checks, with an explicit shared-logo basename for Qoder China. The map also works with older catalog type unions. * fix(qoder): align China catalog entry with fallback order --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * Use the measured pnpm lookup policy automatically in hosted root CI (#24951) * Select lookup automatically for the measured hosted root-install profile * Record hosted automatic-mode cold cache publication proof * fix: bound remote generation setup and honor OpenCode option terminators Count execution-host profile resolution inside the existing request deadline, cancel its waiter promptly, and pass only the remaining time to the child. Shared bounded profile probes keep their existing cache lifetime; the SSH transport margin is unchanged. Read OpenCode output format from active final-argv options before -- so literal prompt arguments cannot select the JSON finalizer. Fresh exact-source controls reproduce nine failures before; 139 related checks pass after, including primary/fallback delays, deadline boundaries, cancellation, parser metadata, and SSH lanes. Node typecheck and strict changed-file lint pass. * Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692) * feat(antigravity): bridge IDE history into new CLI conversations * fix(antigravity): preserve fresh-launch model and environment for IDE references * fix(antigravity): forward IDE history opt-in through desktop IPC * fix(antigravity): rebuild remote IDE reference startup on its host * fix(antigravity): register IDE continuation action labels * fix(antigravity): confine IDE references and bound metadata reads * fix(antigravity): localize IDE continuation badges * Preserve scanner service cache assertions and refresh Antigravity opening metadata * Preserve Antigravity opening joins and target folder runtime authority * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c * fix(opencode): enforce deadline through executable startup Keep synchronous Windows PATH resolution and child startup within the existing request budget. --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(persistence): preserve projectGroupOrder on restart for flat folder-scan groups Retain saved project ranks when the project remains in its folder-scan group. Co-authored-by: lurunzi <lurunzi@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(runtime): reclaim temp files orphaned by interrupted mobile store writes Reuse the existing stale temporary-file cleanup policy when each mobile store opens. Co-authored-by: LDH1103 <ldh517525@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(terminal): show actionable copy for missing folder workspace paths Show the existing folder-path failure with concrete recovery instructions. Co-authored-by: Wayn_Liu <wayntingliu@gmail.com> Co-authored-by: Neil <neil@stably.ai> * docs: reference local orca.yaml and .worktreeinclude Document the existing workspace configuration, include/copy rules and sharing behavior. Co-authored-by: Neil <neil@stably.ai> * fix(orchestration): allow model selection for OMP workers Pass an explicitly requested model through the existing OMP worker launch catalog. Co-authored-by: Neil <neil@stably.ai> * fix(cli): preserve primitive success results in JSON output Check for an object before inspecting screenshot fields so primitive success results remain printable. Related: https://github.com/stablyai/orca/pull/14735 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: VXNCXNX <VXNCXNX@users.noreply.github.com> * Show loaded file changes before deleting a workspace Expose up to ten already loaded changed paths without altering deletion counts, hydration or authorization. Related: https://github.com/stablyai/orca/pull/22778 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Michiel de Gooijer <mdgooijer@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(keybindings): record and match Option+digit shortcuts on macOS Use the physical digit key for explicitly assigned Mac Option+digit shortcuts while retaining modifier checks. Co-authored-by: marcuslannister <marcus@lannister.cc> Co-authored-by: Neil <neil@stably.ai> * fix(editor): don't throw closing a stale active file Recover stale active-file selection within the owning workspace before choosing a surviving editor. Related: https://github.com/stablyai/orca/pull/24715 Co-authored-by: m4air <m4air@m4airs-Air.localdomain> Co-authored-by: Neil <neil@stably.ai> * Fix Project Settings targeting for multiple local checkouts Carry the selected checkout identity into the existing project Settings action. Co-authored-by: fsmeier <1506919+fsmeier@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> * feat(documents): open CSV and TSV files from the OS Extend existing OS document associations and delivery to CSV/TSV, preserving restoration and authorization. Co-authored-by: Neil <neil@stably.ai> * feat(cli): link GitHub and GitLab items on worktree create and set Expose and validate the existing workspace link fields, preserving omitted values and provider identity checks. Related: https://github.com/stablyai/orca/pull/22609 Co-authored-by: marco song <marco.song@mvlchain.io> Co-authored-by: SongMarco <20613630+SongMarco@users.noreply.github.com> Co-authored-by: Luca Critelli <lucacri@gmail.com> Co-authored-by: Neil <neil@stably.ai> * feat(sidebar): include folder workspaces in keyboard navigation Use the rendered sidebar row order and host identity when cycling through folder and Git workspaces. Related: https://github.com/stablyai/orca/pull/10555 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: JeongUk Park <jeongph.dev@gmail.com> * fix(build): turn off MSBuild file tracking for Windows native rebuilds Default Windows native rebuilds to TrackFileAccess=false while preserving explicit caller preferences. Co-authored-by: B1nh M1nh <43268322+b1nhm1nh@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> * Fix Ctrl+M in Linux and Windows terminals Keep the Minimize menu item but disable its accelerator registration on Linux and Windows. Co-authored-by: Zhichang Yu <yuzhichang@gmail.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Related contribution: https://github.com/stablyai/orca/pull/24143 * fix(startup): read a nushell login PATH from $env.PATH Use Nushell login command syntax and preserve the actual login PATH value. Related: https://github.com/stablyai/orca/pull/22677 Co-authored-by: Kh05ifr4nD <meandSSH0219@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(cursor): run local hooks through sh for non-POSIX login shells Keep POSIX hook syntax inside one quoted sh command so the login shell can invoke it safely. Related: https://github.com/stablyai/orca/pull/22663 Co-authored-by: Kh05ifr4nD <meandSSH0219@gmail.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * Fix word wrap for both panes in side-by-side diffs Forward wrapping to both diff panes through the existing editor option path and clean up listeners. Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * fix(monaco): highlight Svelte block closers inside markup Return Svelte block closers to the existing markup tokenizer state. Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * fix(repos): keep active clone dialog open on outside clicks Ignore accidental outside dismissal only while cloning; Escape, Close and Back still cancel. Related: https://github.com/stablyai/orca/pull/24581, https://github.com/stablyai/orca/pull/23430 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance> * fix(editor): keep chat visible after closing Markdown tabs Count remaining unified chat tabs before clearing workspace selection during editor close. Related: https://github.com/stablyai/orca/pull/24273, https://github.com/stablyai/orca/pull/23760 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Honor typed starting numbers in chat ordered lists Forward the existing parsed ordered-list start attribute to both chat Markdown renderers. Related: https://github.com/stablyai/orca/pull/19765 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Frederic Barthelemy <git@fbartho.com> * Normalize base source once while checking changed-code diagnostics (#24557) Reuse the exact existing moved-code matching algorithm with run-local lazy normalization of immutable base source blocks across diagnostics. * Support real OpenCode sessions in native Chat (#24647) * Use bounded OpenCode context for vault session continuation OpenCode database and synthetic row paths are not text transcripts. Use the vault preview or captured pane context, preserving actual transcript paths containing a hash and supporting both OpenCode lanes and Windows paths. Adapted the intent of #11859 and extended it to actual installed v2 vault rows. Co-authored-by: mrcha033 <mrcha033@users.noreply.github.com> * Read real OpenCode sessions in terminal-backed native Chat Reuse the bounded AI Vault SQLite worker for v1 and v2 session pages and live updates. Keep terminal input as the real execution path and pace OpenCode Stop through its two-Escape interrupt. Co-authored-by: xodmd45-ctrl <xodmd45-ctrl@users.noreply.github.com> * fix(opencode): publish approval cards for permission requests * Send OpenCode native approval through its Enter selector * Resolve mobile Chat readability for folder workspaces * Bound OpenCode part batches and preserve v2 image attachments * Prefer live migrated OpenCode sessions over legacy copies * Consolidate mobile Chat eligibility test imports * Consolidate OpenCode SQLite protocol type imports * Update native chat settings contract for both OpenCode agents * fix(native-chat): reconcile bounded OpenCode transcript reads * fix(native-chat): dispatch OpenCode questions safely * fix(native-chat): keep native discovery and transcript windows current * feat(accounts): link standalone GLM Coding Plans (#24618) * feat(accounts): link standalone GLM Coding Plans Adapt the reviewed GLM accounts contribution to current main, retain Antigravity behavior, guard late credential results, expose storage protection, and redact quota errors. Co-authored-by: Luchong <lu740528977@gmail.com> * fix(accounts): retain GLM credential results during quota refresh * fix(accounts): make GLM credential editing desktop-only * fix(accounts): mirror the host GLM site in paired clients * fix(accounts): report unknown GLM host details and split web settings tests Apply the independently reviewed Accounts correction from697284a without the v2 adapter commits. Preserve the saved-key store and serialized write behavior. * fix(zcode): ship required GLM account translation entries * chore: record GLM reconciliation hook validation * chore: validate installed GLM commit hooks * test: complete GLM account fixtures and web API inventory --------- Co-authored-by: Luchong <lu740528977@gmail.com> * fix(native-chat): route transcript requests through shared SQLite worker * fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776) * fix(ci): run mobile typechecks without concurrent dependency refresh * test(ci): check effective Linux E2E package list * test(ci): preserve the mobile production compiler barrier --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * test(terminal): restore the live fish fixture prerequisites (#24947) A restored pane waits for the initial status replay before subscribing to PTY output. This fixture never settled that replay, so fish printed its mode-2031 arm before the renderer connected. Its PTY API also omitted the reset-input listener required by the serializer, aborting attachment. Settle and dispose the existing startup-snapshot registration and provide the same reset-listener mock used by the other PTY tests. The real fish child-stdin assertions and timeouts remain unchanged. No production change. * fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640) Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: f707cde14ab8cb2670b4076916cdfb7e28c79983 fix(shortcuts): defer TUI editing chords in terminal-first mode Original-commit: 0c6348e49e0d968e0170961d294a018adceaa9f3 docs(shortcuts): describe deferred preview terminal chords Original-commit: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Align worktree history shortcut metadata with terminal conflict policy Restacked-from: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * Register supervised Qoder China and Qwen Code (#24616) * Add Qoder session history and search with real CLI coverage * Allow the real Qoder marker file to end with a newline * Keep Qoder tool output out of history previews and search * Keep Qoder search pages readable by older clients * Verify persisted Qoder history after a real generated and resumed task * Negotiate Qoder filters before searching an older execution host * Combine search client imports for the CI plugin gate * Keep the relay search oracle aligned with legacy agent filtering * Register supervised Qoder China and Qwen lifecycle integration * Cover Qoder China mobile assets and mixed-host resume gates * Verify Qoder provider tags against the older released wire parser * Verify China and Qwen keep independent Windows hook scripts * Verify Qoder registrations against the installed older Windows release * test(qoder): align search capability contracts and pin old-host fencing * fix(qoder): rank exact picker identities and command aliases first * test(qoder): preserve the regional CLI shared icon expectation Keep the full bundled-asset and no-remote-image checks, with an explicit shared-logo basename for Qoder China. The map also works with older catalog type unions. * fix(qoder): align China catalog entry with fallback order --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * Use the measured pnpm lookup policy automatically in hosted root CI (#24951) * Select lookup automatically for the measured hosted root-install profile * Record hosted automatic-mode cold cache publication proof * fix(native-chat): keep OpenCode history usable at read limits Continue past failed database probes while preserving discovery cancellation. Verify rows displaced by a capped tail before deciding whether to replace history. Represent oversized v1/v2 rows with the existing omission text and stable cursors. * Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692) * feat(antigravity): bridge IDE history into new CLI conversations * fix(antigravity): preserve fresh-launch model and environment for IDE references * fix(antigravity): forward IDE history opt-in through desktop IPC * fix(antigravity): rebuild remote IDE reference startup on its host * fix(antigravity): register IDE continuation action labels * fix(antigravity): confine IDE references and bound metadata reads * fix(antigravity): localize IDE continuation badges * Preserve scanner service cache assertions and refresh Antigravity opening metadata * Preserve Antigravity opening joins and target folder runtime authority * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c --------- Co-authored-by: mrcha033 <mrcha033@users.noreply.github.com> Co-authored-by: xodmd45-ctrl <xodmd45-ctrl@users.noreply.github.com> Co-authored-by: Luchong <lu740528977@gmail.com> Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * Drain removal fixture jobs before resetting and deleting their records (#24977) * Reuse measured Electron preparation for current Terminal Perf refs (#24968) * feat(jcode): add Jcode as a supported TUI agent with managed hooks Ports PR #10521 onto current main: agent catalog, managed hook service, agent-status listener, session resume, AI Vault parser, per-pane daemon isolation, and Source Control AI support. Co-authored-by: Neil <neil@stably.ai> * feat(jcode): evidence-backed status pipeline (turn_start, live pre_tool, questions) Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): register vault fixture, dynamic model discovery, script refresher Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): keep finished-turn detail so completion notifications fire Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): show the prompt in agent rows instead of jcode's repainting title Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): pre-warm the per-pane daemon so a cold runtime dir cannot time out Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): stop the OSC color skip from crashing every pane connect Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * refactor(jcode): fold three reverse-scan copies into one, reuse the shared hook POST The jcode journal reader, the Claude transcript reader and the Command Code transcript reader each carried their own copy of the same reverse chunked line scan; they now share one tested helper. jcode's managed hook script drops its hand-rolled curl for buildPosixAgentHookPostCommand, which also gains it the raw-JSON transport and the --noproxy guard the bespoke copy was missing. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): narrow dynamic reads with predicates, pin the Windows hook shape CI's anti-slop audit rejects Reflect.get: parse dynamic input into a named type instead. Adds Windows script-shape tests too, since Windows is the platform this change could not be exercised on directly. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): measure the gate against the synchronous path, not the clock The absolute 1s bound was the flake CI shard 3/8 hit: it is tight enough to catch a synchronous gate on an idle laptop and too tight on a loaded runner. Measuring the same POST both ways on the same machine makes the claim a ratio, which is what the test is actually about. Mutation-checked: a synchronous gate reads 6120ms against a 1517ms observer. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): drop the wall-clock gate assertion The bound was machine-speed sensitive and flaked on CI shard 3/8 at 1525ms. The structural assertions (detached gate branch, foreground observer branch) and the no-hang stdin drain cover the same contract without a timer. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): address CodeRabbit review on #22539 - Windows posted no payload at all: the shared builder reads `payload@-` from stdin, which the gate has already drained and observer hooks never receive, so every Windows event was dropped. Write the env var to a temp file and pipe it. - The daemon pre-warm never fired for daemon-host spawns, which is the default local path; it now runs there too, and from the final env so the daemon gets the hook port and token. - A failed runtime-dir mkdir took down every local terminal, jcode or not. - removeJcodeManagedHooks matched the raw line, so a user hook whose comment mentioned the managed script was deleted; matching on Windows never worked. - A managed entry left by a copied home or a platform switch is now repointed instead of being reported as user-owned forever. - The OSC colour skip only checked launchAgent, so a command- or telemetry-named jcode pane still leaked the reply into its composer. - `['hooks']` and a commented scalar are recognised, instead of appending a second [hooks] table that makes jcode reject the whole config. - A failed tool's error is marked as tool output rather than agent prose. - The vault keeps a session's stored name, counts its tokens, and skips background_task and [Scheduled task] turns. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): read the journal once per turn, key prompts by byte offset The jcode prompt reader ran a synchronous bounded file scan plus a JSON parse on every hook event. jcode blocks on pre_tool, so a turn that ran four tools charged the user eight scans of latency it did not need — the prompt cannot change inside a turn. - Cache the journal read per pane, refreshed on the turn boundary that can change it. The cache holds the whole evidence record, since hasExplicitUserPrompt needs the transcript-evidence flag and not just the text, and it joins the existing pane-scoped lifecycle (close, rename, reset) rather than living in a module singleton. - Key a journal prompt by its absolute byte offset instead of its region-local line index. The backward scan windows the file from EOF, so appending shifted every boundary and reminted the key for a prompt that never moved; a repeated turn_end then slipped past the same-hash dedupe as a second done event with duplicate telemetry. - Pin the platform in the daemon pre-warm tests. The pre-warm is a no-op off POSIX, so the dedupe and retry cases would have passed vacuously on a Windows runner. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): quote the managed hook path, drop tools from patch prompts Three fixes, all on paths this PR could not exercise locally. The managed hook command was stored as a bare path. jcode tokenizes that string shell-style before exec'ing it directly (parse_hook_command, crates/jcode-terminal-launch/src/lib.rs): unquoted whitespace splits, and every unquoted backslash is consumed as an escape. So on Windows `C:\Users\me\.orca\agent-hooks\jcode-hook.cmd` reached exec as `C:Usersme.orcaagent-hooksjcode-hook.cmd` and no hook fired at all, and a POSIX home with a space split into two arguments. Store the path single-quoted (verbatim, backslashes included), falling back to double quotes for a path containing a single quote. Existing bare entries are already repointed by the stale-key path, and getStatus accepts both forms so the repair is not reported as a user-owned hook. The quoting helper was previously dead code that only tests called; the three production sites now use it. isJcodeManagedCommand also normalizes separators, since a `/`-only needle never matched a Windows entry. Commit-message generation feeds a staged patch to `jcode run` as the prompt — attacker-influenced text — while jcode's default profile exposes shell, read, write, and MCP. Pass `--tool-profile none`, which resolves to an empty allowed-tool set in jcode's config (base_allowed_t…
Brings #24257's merge of main (e02adc5). Main's #24204 now advertises the structured-chat capabilities to paired hosts, so the renderer claims nothing locally except this branch's agent.launch prompt-unconfirmed capability, kept local-only by decision until remote launches move over; the capability test now records exactly that.
…ts (#22682) * Skip diff analysis after a result has been discarded (#24711) Move the unchanged pure render-limit calculation after both existing generation and section-token rejection fences. * Skip late browser grab toasts after their surface closes (#24727) Reuse the existing mounted-owner ref at the toast presentation entry while preserving all admitted extraction/screenshot and clipboard completion. * Classify native chat waiting messages once (#24771) Use the existing native filter traversal to populate a fresh waiting array, keeping the original predicate, policy, projection and output ordering while classifying each actual private slot once. * Skip discarded Kanban pruning for an empty selection (#24782) Guard only the existing open pruning branch when both its private selected Set and nullable anchor are empty; retain all original pre-guard projections and nonempty/anchor-only/public-helper behavior. * Index discovered test files once during shard selection validation (#24532) Verified selection plans previously validated each selected filename with a scan of all discovered files. One per-call Set now handles membership checks. Exact source/discovery checks, nonempty selection, fallback to all tests, shard balancing and manifests remain intact. * Clear the watchdog benchmark heartbeat when CPU sampling fails (#24802) Move the existing initial CPU observation and histogram enable inside the existing try/finally so their failures clear the sampler's owned heartbeat, preserving successful operation order and original errors. * Reuse the parsed notification when leasing a push delivery (#24645) * Reuse the parsed notification when leasing a push delivery Pass the notification already parsed for the dismissal check into the existing private delivery builder. * Reuse the parsed notification when leasing a push delivery Pass the notification already parsed for the dismissal check into the existing private delivery builder. * Update README downloads badge * Let retired-cache GC observations settle across the existing six-turn budget (#24967) * Collect test-selection evidence when full unit tests fail (#24955) * Collect advisory unit-selection evidence from failed full runs * Trigger checks after retargeting the evidence fix to main * Check each project repository once while filtering mobile cards (#24540) Reuse exact raw source/slug matching decisions within one project filter call, preserving the matcher, membership, negative matches, output order and identity. * Skip renderer callbacks after their request has ended (#24631) Reuse the existing pending-request identity check before starting its deferred renderer callback. * Decode single-piece saved-session tails without copying them (#24632) Decode the existing owned Buffer directly when the EOF tail has one piece; preserve the existing concatenation for multiple pieces. * Avoid irrelevant scroll-action searches in Mac snapshots (#24731) Check the current pure action name before searching for vertical scroll actions in the same immutable array. * Stop copying every retained browser page before attachment (#24553) Find the first page/generation match directly in the existing insertion-ordered Map instead of copying all page references into an array. * Reuse event byte sizes when relay watchers notify several clients (#24558) Store the existing grouped numeric byte-size array on the already call-local watcher batch sizing object, for reuse by later chunking clients. * Stop building unused import candidates in the test planner (#24611) Replace the existing ordered extension map/find with a loop that forms each candidate only when its existing lookup is reached. * docs(terminal): explain local macOS/Linux shell startup files Document the actual login/interactive shell startup-file order and existing shell setup behavior. Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * fix(editor): recognize Ruby task and configuration files Add Ruby task/configuration filenames to the existing generated language associations. Co-authored-by: ggbdpq <ggbdpq@gmail.com> Co-authored-by: Neil <neil@stably.ai> * Speed up large Markdown Find and render oversized tables (#24948) * Speed up large Markdown Find and render oversized tables * Poll table preview geometry outside hidden renderers * Preserve Markdown navigation through refresh and tab restoration * Confirm Markdown restoration when refreshed content is ready * Trace table refresh positions and update Unicode search reference * Recognize queued measurement scrolls before restoring Markdown anchors * Rebuild Markdown Find ranges after renderer components change * fix(source-control): generate clean OpenCode messages locally and over SSH (#24613) * fix(source-control): generate clean OpenCode answers on local and SSH hosts Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: 64bb15e3f20799a21f108c849b0bdff83c692712 fix(source-control): generate clean OpenCode answers on local and SSH hosts Use configured models and JSON answer/error events, preserve run-first arguments, and handle the precise v2 variant rejection. Hydrate SSH execution-host PATH through the existing bounded login environment resolver before direct spawning. Credits: andy-murr (PR #5197 SSH environment intent) and coelho-doti (PR #13065 argument-order intent). Original-commit: 1b60ec5d11132a5fed0695faea5de782a228a8e5 fix(source-control): retry inline OpenCode model and variant options Original-commit: 98fdecc7a33ef1571dbf2854f309e4bfa1ec4300 Preserve OpenCode named errors without a data message Restacked-from: 98fdecc7a33ef1571dbf2854f309e4bfa1ec4300 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776) * fix(ci): run mobile typechecks without concurrent dependency refresh * test(ci): check effective Linux E2E package list * test(ci): preserve the mobile production compiler barrier --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * test(terminal): restore the live fish fixture prerequisites (#24947) A restored pane waits for the initial status replay before subscribing to PTY output. This fixture never settled that replay, so fish printed its mode-2031 arm before the renderer connected. Its PTY API also omitted the reset-input listener required by the serializer, aborting attachment. Settle and dispose the existing startup-snapshot registration and provide the same reset-listener mock used by the other PTY tests. The real fish child-stdin assertions and timeouts remain unchanged. No production change. * fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640) Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: f707cde14ab8cb2670b4076916cdfb7e28c79983 fix(shortcuts): defer TUI editing chords in terminal-first mode Original-commit: 0c6348e49e0d968e0170961d294a018adceaa9f3 docs(shortcuts): describe deferred preview terminal chords Original-commit: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Align worktree history shortcut metadata with terminal conflict policy Restacked-from: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * Register supervised Qoder China and Qwen Code (#24616) * Add Qoder session history and search with real CLI coverage * Allow the real Qoder marker file to end with a newline * Keep Qoder tool output out of history previews and search * Keep Qoder search pages readable by older clients * Verify persisted Qoder history after a real generated and resumed task * Negotiate Qoder filters before searching an older execution host * Combine search client imports for the CI plugin gate * Keep the relay search oracle aligned with legacy agent filtering * Register supervised Qoder China and Qwen lifecycle integration * Cover Qoder China mobile assets and mixed-host resume gates * Verify Qoder provider tags against the older released wire parser * Verify China and Qwen keep independent Windows hook scripts * Verify Qoder registrations against the installed older Windows release * test(qoder): align search capability contracts and pin old-host fencing * fix(qoder): rank exact picker identities and command aliases first * test(qoder): preserve the regional CLI shared icon expectation Keep the full bundled-asset and no-remote-image checks, with an explicit shared-logo basename for Qoder China. The map also works with older catalog type unions. * fix(qoder): align China catalog entry with fallback order --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * Use the measured pnpm lookup policy automatically in hosted root CI (#24951) * Select lookup automatically for the measured hosted root-install profile * Record hosted automatic-mode cold cache publication proof * fix: bound remote generation setup and honor OpenCode option terminators Count execution-host profile resolution inside the existing request deadline, cancel its waiter promptly, and pass only the remaining time to the child. Shared bounded profile probes keep their existing cache lifetime; the SSH transport margin is unchanged. Read OpenCode output format from active final-argv options before -- so literal prompt arguments cannot select the JSON finalizer. Fresh exact-source controls reproduce nine failures before; 139 related checks pass after, including primary/fallback delays, deadline boundaries, cancellation, parser metadata, and SSH lanes. Node typecheck and strict changed-file lint pass. * Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692) * feat(antigravity): bridge IDE history into new CLI conversations * fix(antigravity): preserve fresh-launch model and environment for IDE references * fix(antigravity): forward IDE history opt-in through desktop IPC * fix(antigravity): rebuild remote IDE reference startup on its host * fix(antigravity): register IDE continuation action labels * fix(antigravity): confine IDE references and bound metadata reads * fix(antigravity): localize IDE continuation badges * Preserve scanner service cache assertions and refresh Antigravity opening metadata * Preserve Antigravity opening joins and target folder runtime authority * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c * fix(opencode): enforce deadline through executable startup Keep synchronous Windows PATH resolution and child startup within the existing request budget. --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(persistence): preserve projectGroupOrder on restart for flat folder-scan groups Retain saved project ranks when the project remains in its folder-scan group. Co-authored-by: lurunzi <lurunzi@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(runtime): reclaim temp files orphaned by interrupted mobile store writes Reuse the existing stale temporary-file cleanup policy when each mobile store opens. Co-authored-by: LDH1103 <ldh517525@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(terminal): show actionable copy for missing folder workspace paths Show the existing folder-path failure with concrete recovery instructions. Co-authored-by: Wayn_Liu <wayntingliu@gmail.com> Co-authored-by: Neil <neil@stably.ai> * docs: reference local orca.yaml and .worktreeinclude Document the existing workspace configuration, include/copy rules and sharing behavior. Co-authored-by: Neil <neil@stably.ai> * fix(orchestration): allow model selection for OMP workers Pass an explicitly requested model through the existing OMP worker launch catalog. Co-authored-by: Neil <neil@stably.ai> * fix(cli): preserve primitive success results in JSON output Check for an object before inspecting screenshot fields so primitive success results remain printable. Related: https://github.com/stablyai/orca/pull/14735 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: VXNCXNX <VXNCXNX@users.noreply.github.com> * Show loaded file changes before deleting a workspace Expose up to ten already loaded changed paths without altering deletion counts, hydration or authorization. Related: https://github.com/stablyai/orca/pull/22778 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Michiel de Gooijer <mdgooijer@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(keybindings): record and match Option+digit shortcuts on macOS Use the physical digit key for explicitly assigned Mac Option+digit shortcuts while retaining modifier checks. Co-authored-by: marcuslannister <marcus@lannister.cc> Co-authored-by: Neil <neil@stably.ai> * fix(editor): don't throw closing a stale active file Recover stale active-file selection within the owning workspace before choosing a surviving editor. Related: https://github.com/stablyai/orca/pull/24715 Co-authored-by: m4air <m4air@m4airs-Air.localdomain> Co-authored-by: Neil <neil@stably.ai> * Fix Project Settings targeting for multiple local checkouts Carry the selected checkout identity into the existing project Settings action. Co-authored-by: fsmeier <1506919+fsmeier@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> * feat(documents): open CSV and TSV files from the OS Extend existing OS document associations and delivery to CSV/TSV, preserving restoration and authorization. Co-authored-by: Neil <neil@stably.ai> * feat(cli): link GitHub and GitLab items on worktree create and set Expose and validate the existing workspace link fields, preserving omitted values and provider identity checks. Related: https://github.com/stablyai/orca/pull/22609 Co-authored-by: marco song <marco.song@mvlchain.io> Co-authored-by: SongMarco <20613630+SongMarco@users.noreply.github.com> Co-authored-by: Luca Critelli <lucacri@gmail.com> Co-authored-by: Neil <neil@stably.ai> * feat(sidebar): include folder workspaces in keyboard navigation Use the rendered sidebar row order and host identity when cycling through folder and Git workspaces. Related: https://github.com/stablyai/orca/pull/10555 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: JeongUk Park <jeongph.dev@gmail.com> * fix(build): turn off MSBuild file tracking for Windows native rebuilds Default Windows native rebuilds to TrackFileAccess=false while preserving explicit caller preferences. Co-authored-by: B1nh M1nh <43268322+b1nhm1nh@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> * Fix Ctrl+M in Linux and Windows terminals Keep the Minimize menu item but disable its accelerator registration on Linux and Windows. Co-authored-by: Zhichang Yu <yuzhichang@gmail.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Related contribution: https://github.com/stablyai/orca/pull/24143 * fix(startup): read a nushell login PATH from $env.PATH Use Nushell login command syntax and preserve the actual login PATH value. Related: https://github.com/stablyai/orca/pull/22677 Co-authored-by: Kh05ifr4nD <meandSSH0219@gmail.com> Co-authored-by: Neil <neil@stably.ai> * fix(cursor): run local hooks through sh for non-POSIX login shells Keep POSIX hook syntax inside one quoted sh command so the login shell can invoke it safely. Related: https://github.com/stablyai/orca/pull/22663 Co-authored-by: Kh05ifr4nD <meandSSH0219@gmail.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * Fix word wrap for both panes in side-by-side diffs Forward wrapping to both diff panes through the existing editor option path and clean up listeners. Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * fix(monaco): highlight Svelte block closers inside markup Return Svelte block closers to the existing markup tokenizer state. Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Neil <neil@stably.ai> * fix(repos): keep active clone dialog open on outside clicks Ignore accidental outside dismissal only while cloning; Escape, Close and Back still cancel. Related: https://github.com/stablyai/orca/pull/24581, https://github.com/stablyai/orca/pull/23430 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance> * fix(editor): keep chat visible after closing Markdown tabs Count remaining unified chat tabs before clearing workspace selection during editor close. Related: https://github.com/stablyai/orca/pull/24273, https://github.com/stablyai/orca/pull/23760 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Wooseong Kim <innocarpe@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Honor typed starting numbers in chat ordered lists Forward the existing parsed ordered-list start attribute to both chat Markdown renderers. Related: https://github.com/stablyai/orca/pull/19765 Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Frederic Barthelemy <git@fbartho.com> * Normalize base source once while checking changed-code diagnostics (#24557) Reuse the exact existing moved-code matching algorithm with run-local lazy normalization of immutable base source blocks across diagnostics. * Support real OpenCode sessions in native Chat (#24647) * Use bounded OpenCode context for vault session continuation OpenCode database and synthetic row paths are not text transcripts. Use the vault preview or captured pane context, preserving actual transcript paths containing a hash and supporting both OpenCode lanes and Windows paths. Adapted the intent of #11859 and extended it to actual installed v2 vault rows. Co-authored-by: mrcha033 <mrcha033@users.noreply.github.com> * Read real OpenCode sessions in terminal-backed native Chat Reuse the bounded AI Vault SQLite worker for v1 and v2 session pages and live updates. Keep terminal input as the real execution path and pace OpenCode Stop through its two-Escape interrupt. Co-authored-by: xodmd45-ctrl <xodmd45-ctrl@users.noreply.github.com> * fix(opencode): publish approval cards for permission requests * Send OpenCode native approval through its Enter selector * Resolve mobile Chat readability for folder workspaces * Bound OpenCode part batches and preserve v2 image attachments * Prefer live migrated OpenCode sessions over legacy copies * Consolidate mobile Chat eligibility test imports * Consolidate OpenCode SQLite protocol type imports * Update native chat settings contract for both OpenCode agents * fix(native-chat): reconcile bounded OpenCode transcript reads * fix(native-chat): dispatch OpenCode questions safely * fix(native-chat): keep native discovery and transcript windows current * feat(accounts): link standalone GLM Coding Plans (#24618) * feat(accounts): link standalone GLM Coding Plans Adapt the reviewed GLM accounts contribution to current main, retain Antigravity behavior, guard late credential results, expose storage protection, and redact quota errors. Co-authored-by: Luchong <lu740528977@gmail.com> * fix(accounts): retain GLM credential results during quota refresh * fix(accounts): make GLM credential editing desktop-only * fix(accounts): mirror the host GLM site in paired clients * fix(accounts): report unknown GLM host details and split web settings tests Apply the independently reviewed Accounts correction from697284a without the v2 adapter commits. Preserve the saved-key store and serialized write behavior. * fix(zcode): ship required GLM account translation entries * chore: record GLM reconciliation hook validation * chore: validate installed GLM commit hooks * test: complete GLM account fixtures and web API inventory --------- Co-authored-by: Luchong <lu740528977@gmail.com> * fix(native-chat): route transcript requests through shared SQLite worker * fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776) * fix(ci): run mobile typechecks without concurrent dependency refresh * test(ci): check effective Linux E2E package list * test(ci): preserve the mobile production compiler barrier --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * test(terminal): restore the live fish fixture prerequisites (#24947) A restored pane waits for the initial status replay before subscribing to PTY output. This fixture never settled that replay, so fish printed its mode-2031 arm before the renderer connected. Its PTY API also omitted the reset-input listener required by the serializer, aborting attachment. Settle and dispose the existing startup-snapshot registration and provide the same reset-listener mock used by the other PTY tests. The real fish child-stdin assertions and timeouts remain unchanged. No production change. * fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640) Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes. Original-commit: f707cde14ab8cb2670b4076916cdfb7e28c79983 fix(shortcuts): defer TUI editing chords in terminal-first mode Original-commit: 0c6348e49e0d968e0170961d294a018adceaa9f3 docs(shortcuts): describe deferred preview terminal chords Original-commit: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Align worktree history shortcut metadata with terminal conflict policy Restacked-from: be62c1b6c6b305cb8091161c1ccdd943a6e1d470 Restacked-onto: f7b1f9d8be14d12244957ee0b710a3482ec62383 * Register supervised Qoder China and Qwen Code (#24616) * Add Qoder session history and search with real CLI coverage * Allow the real Qoder marker file to end with a newline * Keep Qoder tool output out of history previews and search * Keep Qoder search pages readable by older clients * Verify persisted Qoder history after a real generated and resumed task * Negotiate Qoder filters before searching an older execution host * Combine search client imports for the CI plugin gate * Keep the relay search oracle aligned with legacy agent filtering * Register supervised Qoder China and Qwen lifecycle integration * Cover Qoder China mobile assets and mixed-host resume gates * Verify Qoder provider tags against the older released wire parser * Verify China and Qwen keep independent Windows hook scripts * Verify Qoder registrations against the installed older Windows release * test(qoder): align search capability contracts and pin old-host fencing * fix(qoder): rank exact picker identities and command aliases first * test(qoder): preserve the regional CLI shared icon expectation Keep the full bundled-asset and no-remote-image checks, with an explicit shared-logo basename for Qoder China. The map also works with older catalog type unions. * fix(qoder): align China catalog entry with fallback order --------- Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> * Use the measured pnpm lookup policy automatically in hosted root CI (#24951) * Select lookup automatically for the measured hosted root-install profile * Record hosted automatic-mode cold cache publication proof * fix(native-chat): keep OpenCode history usable at read limits Continue past failed database probes while preserving discovery cancellation. Verify rows displaced by a capped tail before deciding whether to replace history. Represent oversized v1/v2 rows with the existing omission text and stable cursors. * Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692) * feat(antigravity): bridge IDE history into new CLI conversations * fix(antigravity): preserve fresh-launch model and environment for IDE references * fix(antigravity): forward IDE history opt-in through desktop IPC * fix(antigravity): rebuild remote IDE reference startup on its host * fix(antigravity): register IDE continuation action labels * fix(antigravity): confine IDE references and bound metadata reads * fix(antigravity): localize IDE continuation badges * Preserve scanner service cache assertions and refresh Antigravity opening metadata * Preserve Antigravity opening joins and target folder runtime authority * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c --------- Co-authored-by: mrcha033 <mrcha033@users.noreply.github.com> Co-authored-by: xodmd45-ctrl <xodmd45-ctrl@users.noreply.github.com> Co-authored-by: Luchong <lu740528977@gmail.com> Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example> Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * Drain removal fixture jobs before resetting and deleting their records (#24977) * Reuse measured Electron preparation for current Terminal Perf refs (#24968) * feat(jcode): add Jcode as a supported TUI agent with managed hooks Ports PR #10521 onto current main: agent catalog, managed hook service, agent-status listener, session resume, AI Vault parser, per-pane daemon isolation, and Source Control AI support. Co-authored-by: Neil <neil@stably.ai> * feat(jcode): evidence-backed status pipeline (turn_start, live pre_tool, questions) Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): register vault fixture, dynamic model discovery, script refresher Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): keep finished-turn detail so completion notifications fire Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): show the prompt in agent rows instead of jcode's repainting title Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): pre-warm the per-pane daemon so a cold runtime dir cannot time out Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): stop the OSC color skip from crashing every pane connect Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * refactor(jcode): fold three reverse-scan copies into one, reuse the shared hook POST The jcode journal reader, the Claude transcript reader and the Command Code transcript reader each carried their own copy of the same reverse chunked line scan; they now share one tested helper. jcode's managed hook script drops its hand-rolled curl for buildPosixAgentHookPostCommand, which also gains it the raw-JSON transport and the --noproxy guard the bespoke copy was missing. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): narrow dynamic reads with predicates, pin the Windows hook shape CI's anti-slop audit rejects Reflect.get: parse dynamic input into a named type instead. Adds Windows script-shape tests too, since Windows is the platform this change could not be exercised on directly. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): measure the gate against the synchronous path, not the clock The absolute 1s bound was the flake CI shard 3/8 hit: it is tight enough to catch a synchronous gate on an idle laptop and too tight on a loaded runner. Measuring the same POST both ways on the same machine makes the claim a ratio, which is what the test is actually about. Mutation-checked: a synchronous gate reads 6120ms against a 1517ms observer. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): drop the wall-clock gate assertion The bound was machine-speed sensitive and flaked on CI shard 3/8 at 1525ms. The structural assertions (detached gate branch, foreground observer branch) and the no-hang stdin drain cover the same contract without a timer. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): address CodeRabbit review on #22539 - Windows posted no payload at all: the shared builder reads `payload@-` from stdin, which the gate has already drained and observer hooks never receive, so every Windows event was dropped. Write the env var to a temp file and pipe it. - The daemon pre-warm never fired for daemon-host spawns, which is the default local path; it now runs there too, and from the final env so the daemon gets the hook port and token. - A failed runtime-dir mkdir took down every local terminal, jcode or not. - removeJcodeManagedHooks matched the raw line, so a user hook whose comment mentioned the managed script was deleted; matching on Windows never worked. - A managed entry left by a copied home or a platform switch is now repointed instead of being reported as user-owned forever. - The OSC colour skip only checked launchAgent, so a command- or telemetry-named jcode pane still leaked the reply into its composer. - `['hooks']` and a commented scalar are recognised, instead of appending a second [hooks] table that makes jcode reject the whole config. - A failed tool's error is marked as tool output rather than agent prose. - The vault keeps a session's stored name, counts its tokens, and skips background_task and [Scheduled task] turns. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): read the journal once per turn, key prompts by byte offset The jcode prompt reader ran a synchronous bounded file scan plus a JSON parse on every hook event. jcode blocks on pre_tool, so a turn that ran four tools charged the user eight scans of latency it did not need — the prompt cannot change inside a turn. - Cache the journal read per pane, refreshed on the turn boundary that can change it. The cache holds the whole evidence record, since hasExplicitUserPrompt needs the transcript-evidence flag and not just the text, and it joins the existing pane-scoped lifecycle (close, rename, reset) rather than living in a module singleton. - Key a journal prompt by its absolute byte offset instead of its region-local line index. The backward scan windows the file from EOF, so appending shifted every boundary and reminted the key for a prompt that never moved; a repeated turn_end then slipped past the same-hash dedupe as a second done event with duplicate telemetry. - Pin the platform in the daemon pre-warm tests. The pre-warm is a no-op off POSIX, so the dedupe and retry cases would have passed vacuously on a Windows runner. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): quote the managed hook path, drop tools from patch prompts Three fixes, all on paths this PR could not exercise locally. The managed hook command was stored as a bare path. jcode tokenizes that string shell-style before exec'ing it directly (parse_hook_command, crates/jcode-terminal-launch/src/lib.rs): unquoted whitespace splits, and every unquoted backslash is consumed as an escape. So on Windows `C:\Users\me\.orca\agent-hooks\jcode-hook.cmd` reached exec as `C:Usersme.orcaagent-hooksjcode-hook.cmd` and no hook fired at all, and a POSIX home with a space split into two arguments. Store the path single-quoted (verbatim, backslashes included), falling back to double quotes for a path containing a single quote. Existing bare entries are already repointed by the stale-key path, and getStatus accepts both forms so the repair is not reported as a user-owned hook. The quoting helper was previously dead code that only tests called; the three production sites now use it. isJcodeManagedCommand also normalizes separators, since a `/`-only needle never matched a Windows entry. Commit-message generation feeds a staged patch to `jcode run` as the prompt — attacker-influenced text — while jcode's default profile exposes shell, read, write, and MCP. Pass `--tool-profile none`, which resolves to an empty allowed-tool set in jcode's config (base_allowed_tools), matching the read-only posture claude (plan) and codex (read-only) already take. docs/reference/jcode-hook-events.md was never actually in this PR: the repo ignores docs/** and tracks reference docs by allow-list only, so the captured-payload evidence four source comments point at was silently dropped. Allow-list it. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * test(jcode): pin the tool-profile flag in the generation plan too The argv assertion lives in two places; --tool-profile none only landed in one, so the plan test still expected the unrestricted argv. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(text-generation): refuse an oversized argv prompt on Linux too The pre-spawn size guard only ran on Windows. Linux caps a single argv entry at MAX_ARG_STRLEN (32 pages, 128 KiB on a 4-KiB-page host) and execve fails with E2BIG past it, so an agent that delivers the whole prompt as one argument — jcode, and the other argv-delivery agents — failed on a large staged diff with an error the user could not act on. The cap is per-argument and in bytes, which is why it is not the Windows line budget: 40k chars trips Windows and is nowhere near the Linux limit, so folding them together would have refused prompts Linux runs fine. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): register in main's remote-installer guard, drop our duplicate Rebasing onto 853 commits of main surfaced two things the earlier branch had hidden. main already owns a guard for the issue-#7253 bug class (`remote-hook-service-registry-coverage.test.ts`). This branch had added a second, near-identical one — a parallel implementation of a test that already existed, which is what AGENTS.md's reuse rule is about. Deleted ours and registered jcode in main's, which is the one that has kept pace with every agent added since. Also fixes a missing separator in the mobile icon map. `pnpm tc` does not cover `mobile/`, so only the session-route closure suite caught it. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * fix(jcode): decompose the four files jcode pushed over max-lines Adding an agent tipped four modules past their line budget. AGENTS.md forbids a `max-lines` disable or a per-file bump, so each is split on a real seam rather than silenced: - agent-catalog.tsx keeps `AgentIcon`, which 70+ files import, and the rows move out. The rows alone exceed the 300-line budget a `.ts` file gets, so they follow the primary/secondary split this repo already uses for commit-message agent specs. - getAgentResumeArgv -> agent-resume-argv.ts, re-exported so the 18 call sites keep one import path. - isDiscoverableSessionFile/pathSegments -> session-file-discovery.ts. - remoteCodexSources -> remote-session-scanner-codex-sources.ts; Codex is the one remote agent with two CODEX_HOME roots. Also: - Records the readiness-census baseline jcode now needs. main added that gate while this branch was out; the fixture is the recorded 74-case matrix, not a hand-written one. - Restores two entries a rebase resolution silently dropped from config/tsconfig.cli.json (gitlab/project-ref-parser, startup/shell-path-probe). Nothing to do with jcode; losing them was a conflict-resolution mistake on this branch. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> * feat(native-chat): open structured chats on the paired Orca server that owns the workspace (#24205) * fix(native-chat): a host admits structured sessions by client capability, not its own chat setting A host's experimentalStructuredNativeChat decided whether any paired client could reach agentSession.* at all, and whether session.tabs.* showed it structured tabs. That setting is the host user's own launch preference: whether a new agent opens as a chat or a terminal is decided by whoever launches it. Using it as admission control meant a client whose own preference was "structured chat" was refused on a host whose preference was "terminal", and chats opened while the setting was on were withheld from mobile once it was turned off. The gate now asks one thing: did the client advertise agent-session.structured.v1 (in-process callers negotiate nothing and are always admitted). Tab projection and restore follow the same rule. With the setting no longer gating anything, the separate cleanup gate (close, cancel, unsubscribe, release), which existed only so those kept working after the setting was switched off, is identical to the main gate and is folded into it. The settings listener that republished tabs when the setting changed is removed, since projection no longer depends on it. The host setting still picks the default for launches that start on the host itself (agent.launch from mobile, orchestration worker-start). * fix(native-chat): the desktop declares structured chat support to paired hosts The desktop renderer advertised agent-session.structured.v1 (and the Claude, turn-item and background-task capabilities that go with it) to its own main process but not to a paired Orca server. The server therefore refused every agentSession.* call from the desktop and stripped structured chat tabs out of the tab list it published to it, so a structured chat running on a paired server never appeared on the desktop, even though the renderer already mirrors a host's agent-session tabs and drives each one against the server that owns its workspace. The same renderer reads structured chats on either host, so the remote Electron list now carries the same structured-session capabilities as the local one, and the capability test pins that nothing is advertised only locally. * feat(native-chat): open structured chats on the paired server that owns the workspace With the structured-chat default on, an agent launched in a workspace that lives on a paired Orca server always opened as a terminal (or the terminal-backed chat view). Three things kept it off the structured path: the launch check refused every host but this machine, a remote workspace was handed to the host-published terminal path before the structured route was even considered, and the structured launch pipeline sent create and every follow-up call to this machine's runtime. A workspace's owning runtime is fixed, so the pipeline now derives it from the workspace instead of assuming this machine (structured-agent-session-owner.ts, the same derivation the chat pane already uses to read a session). The launch intent carries that target; the pre-create support check, create, the publication check and fence read, the launch prompt send, held option picks, the "focus this chat" marker, the placeholder tab's host, and tab close/purge all use it. The launch check now accepts a paired server and asks that server's own capabilities (read from the status the client already cached for it) rather than this machine's. An SSH workspace stays terminal-backed: no Orca runtime runs there. The host still answers createSupport before anything is created, so an older server that refuses shows the failure in the chat tab. A chat the user closed before its create landed is now also retired on the paired server when it publishes, as the local sync already does. Orchestration workers placed on another runtime are unchanged: federation creates terminal agents only. * fix(native-chat): negotiate client-chosen launch mode so released phones and old servers keep terminals Hosts advertise agent-session.structured.client-launch-mode.v1: they admit structured sessions by client capability alone. A remote client that does not advertise it (phones released before agent.launch) asks createSupport to pick the launch mode, so the host keeps answering that with its own setting, exactly as before. Cleanup methods keep their own named gate so a future admission condition cannot make close or cancel refusable. * refactor(runtime): keep the Electron client capability list in its own module protocol-version.ts is at its line budget; the list is what the desktop advertises to paired hosts, not the host's own contract. * fix(native-chat): the desktop declares it picks each launch mode itself Paired hosts and the desktop's own main process then answer createSupport by the workspace rather than by their own chat setting. * fix(native-chat): pin each structured chat to the host it was launched on - Route: a paired server opens a chat only when it advertises the client-chosen launch mode; an older server keeps its terminal. Its capabilities come from the store's host status, not the compatibility cache that is empty after boot or reconnect. - A launch command override is this machine's: the route applies it only locally, and a host's createSupport refuses on its own override. - The owning host is resolved once, from the same value the route used, and carried on the launch intent, its persisted record (legacy records load as local), the provisional tab and every mirrored chat tab. Close, purge, retry and reload read it instead of re-deriving it from a worktree id two hosts can share; an owner that cannot be named refuses. - Cancellation tombstones record their host: only that host's authoritative inventory retires one, restored cleanup closes it there, and a paired host's tombstone expires after 30 days if it never answers. - A paired server's frame settles launches it published, as the local inventory already does for this machine. * fix(native-chat): a paired server that declines a chat opens its terminal instead createSupport only reads, so both of its non-answers are settled before anything is created: - A paired server that answers it cannot run the chat (a WSL repo, a Claude account mismatch, its own launch command override) closes the chat tab and opens the terminal the route would have chosen, with a notice saying why. This machine's own decline stays a failed chat. - A host that could not be asked closes the chat tab and leaves one failure toast, instead of a lingering "could not confirm" chat. * test(native-chat): a provisional chat carries its launch's host and hands pre-create failures on * chore(native-chat): justify the two type assertions this change's lines touch * test(native-chat): state why each staged test fixture is cast * fix(native-chat): chats that already exist keep showing whatever the chat setting says The structured chat setting decides only what new agents open as. With it off, this machine's structured chats used to be hidden while the host, which no longer reads the setting, still reported them to the workspace activation gate, so a workspace holding only a chat opened empty. The local chat mirror and its startup restore now run whatever the setting says, the continue-after-restart offer follows the chats that exist, and the setting's copy says it applies to new agents. * fix(native-chat): the browser client keeps its host terminal on paired servers A browser client whose own preferences turn structured chat on took the structured route for every paired-server workspace, but its handshake never says it reads structured sessions, so the server refused the chat and the user got a failed chat tab where a host terminal used to open. The route for a paired host now also asks what this client advertises to it: the desktop's list does, the browser client's does not. Its handshake list is now a named constant the route reads, so the two cannot drift. The chat setting's copy now says it runs on paired Orca servers too; WSL and SSH hosts still use terminal chat. * fix(native-chat): a retried launch a paired server declines opens its terminal too A launch restored after a reload settles only through its Retry, so a declining paired server left a failed chat there while a first launch got the server's terminal and a notice. The chat's Retry now hands the same pre-create failures to the same replacement, carrying the prompt the launch had staged. * refactor(native-chat): a paired host's cancelled-chat record ends on its 30-day TTL The paired census re-read a host's whole inventory after every authoritative frame to retire tombstones, and a tombstone restored after a reload needed a second such frame, so in practice it retired nothing. A tombstone guards a random session id and is inert once stale; the chat is already closed on its host whenever a frame shows it. The census, its trigger in the mirror layer and its cleanup are removed; the owner-scoped tombstones, close-on-sight, the TTL and publication marking from frames stay. * fix(native-chat): a chat's pane and status read from the host recorded on its tab The chat pane and its sidebar status still derived the host from the workspace id, which two hosts can share; a paired chat in a non-active same-id workspace was read from this machine. Both now read the owner stamped on the tab, as close, purge and publication already do. * fix(native-chat): "Resume in chat" follows the terminal resume's host rule Agent Session History offered "Resume in chat" for a conversation recorded on this machine into a paired server's workspace, where its transcript does not exist. A chat now resumes a conversation only on the host that recorded it, as the terminal resume does, and that host is the one asked whether it can resume history. * fix(native-chat): the chat setting says older paired servers keep terminal chat * test(native-chat): pin that a host advertises the client-chosen launch mode * fix(native-chat): mirror this machine's chats only where it holds them Round 1 ran the local chat mirror for everyone so existing chats show whatever the setting says. That gave every desktop a permanent session-tabs listener, which turns on the runtime's phone replication paths, plus two full session-tab censuses at startup, and made the browser client mirror its remote host a second time. The runtime now says whether it holds structured chats: its structured host is built only when saved chats were restored at startup or a client created one here, and it announces the moment one is built. The mirror, the startup restore and the continue-after-restart offer run only when the setting launches chats or the host holds some, and never in the browser client. A chat a paired client creates here with the setting off still appears at once. The chat behaviour settings show wherever chats exist, and the setting's copy says it picks what new agents open as. The toggle-off teardown this made dead is removed. * test(native-chat): route a paired-server launch over the capability lists both sides really advertise * test(native-chat): record install listeners without a cast * fix(native-chat): a paired server admits a chat before any of it exists here The desktop opened a paired server's chat tab, launch record, queued prompt and focus intent before asking the server, so a "no" needed a replacement that undid and redid all of it, and every piece it missed was a bug: the workspace deselected, the caller told "failed" while a terminal ran its prompt, the caller's arguments and other queued prompts lost, and a create whose reply was lost treated as never sent. A paired launch now asks the server first and commits nothing until it answers. Admitted opens the chat as before. Declined runs the caller's own launch as the server's terminal, with the existing notice (a resume fails instead, having no terminal equivalent). Unreachable opens nothing and names the server in one toast. The new-tab launcher reports the host's surface for paired workspaces, as it did before paired chats, with the prompt delivery of whichever surface got the prompt. The replacement and its error classes are gone, and the probe inside a launch is back to its old meaning: a "no" is a failed chat with Retry, and no answer leaves "Could not confirm" with Retry and the prompt kept, here as on this machine. * fix(native-chat): mirror this machine's chats only once it holds one, not once its host is built Session history, resume preparation, terminal resume commands and replay-safe phone launches all build the structured host for users who never had a chat, which turned on the chat mirror and the structured-only settings rows until the next restart. The signal is now derived from the host's records (or a records file still owed its import) and pushed when the first chat is restored or created. A throwing listener no longer fails the install that fired it. * fix(native-chat): a fork's reveal never seeds a terminal beside the surface the launcher opens Forking into a paired-server workspace revealed it as if nothing would open there, so the reveal created a blank host terminal beside the forked chat (and beside a forked agent terminal on main). The launcher always opens the fork's surface itself, so the reveal now says so for every surface, as the fix-checks launch already does. * fix(native-chat): a declined direct launch keeps the caller's CLI args; an unreachable resume toasts once When a paired server declines a "Fix checks" chat in a new workspace, the terminal that opens instead now carries the recipe's saved CLI arguments, launch platform and launch source, as the terminal route did. "Resume in chat" to a server that cannot be reached showed the admission's "Could not reach" toast and the vault's generic one; the admission marks its failure notified and the vault adds nothing. * fix(native-chat): a declined background create opens its terminal without switching workspaces Since #23974 a worktree create the user moved away from must not pull them onto the new workspace. When a paired server declined that create's chat, the fallback terminal opened as a new agent tab, whose host create selects the workspace. The create now opens its own agent terminal the way main's background branch does: in place from the request's startup plan (so its CLI args carry), without selecting the workspace. A create the user is still watching keeps the new-tab fallback. * test(native-chat): name the launch's host in main's new outbox fence test Main's new staging-failure test calls settleStructuredAgentLaunchPrompt without the target this PR made required; it is a local launch, as in the sibling tests. * fix(native-chat): a paired server's new chat shows no model until the server reports the one it started A chat on a paired server starts with the server's saved model and options, but the picker showed this desktop's saved selection (or the catalog default) until the server reported a model, and a pick made in that window was remembered on the server under that guessed model. A paired launch now carries no desktop seed, and until the server reports its model the picker names no model and takes no picks. Local chats are unchanged. * test(native-chat): seed the paired repo without a cast The repo literal already satisfies Repo, so the changed-lines cast gate has nothing to excuse. * feat(native-chat): createSupport reports the saved selection a new chat on this host starts with A chat on a paired server starts with the server's saved model and options, which the desktop could not read, so its picker showed a guess. createSupport's answer, which the desktop already waits for before a paired launch, now also carries that seed as a new optional field (older clients ignore it). Create and createSupport read it through one resolver so they cannot drift. * fix(native-chat): a paired server's new chat shows the selection the server will start it with The paired server now names its saved model and options in the admission answer the desktop already waits for. That seed goes into the launch intent and its persisted record, so the picker shows the server's model at once, stays pickable like a local chat, and remembers picks on the server under that model; a reload shows the same. The locked picker remains only for a server too old to name a seed. Also moves host admission and launch-outcome tracking into their own modules: the latest main merge left structured-agent-session-launch.ts over the max-lines limit. * test(native-chat): expect the launch intent's new seed argument in exact-call assertions * refactor(protocol): move the Electron remote client capability list into its own module Merging main left protocol-version.ts one line over the max-lines limit on this branch. The list of capabilities the desktop advertises to a paired host moves, unchanged, into electron-remote-runtime-client-capabilities.ts, the module the next PR in the stack already uses for it; importers point there. * fix(native-chat): a paired chat with no saved server model is pickable; Retry shows the server's current seed A server whose user never saved a chat model sends no seed, and the desktop showed a locked, model-only picker for it, although that is the common case: no server that can admit a paired chat predates the seed field. Such a chat now behaves like a local chat with no saved model: the CLI default, pickable. The lock and its snapshot helper are gone. Retry kept the first admission's seed while the create probe, which already runs on every attempt, reported the server's current one and dropped it. The probe's seed now replaces a paired launch's seed and the picker's, so a retried chat shows what its create will run. * test(cross-version): stub the launch seed resolver createSupport now reads * test(protocol): pin the desktop capability divergence against what a paired server receives Every paired transport sends the shared remote base plus the Electron list, so the divergence test now compares that union with the renderer's local list instead of the declared Electron list. A capability added only to the shared base can no longer slip past it. The two base-only capabilities it surfaced are recorded: skills.install-result.v2 has no local caller; the authoritative-inventory label is read by the local tabs sync but dropped by main, and is marked unsettled. The turn-item and both background-task-stop capabilities were already sent through the shared base, so the Electron list no longer repeats them. The wire set is unchanged; this PR's real change on the wire is structured.v1, the Claude structured capability and the client launch-mode capability. * fix(native-chat): the desktop tells its own host it picks each launch mode, so retrying an existing chat works with the setting off * docs(native-chat): name the real exit for the released-phone createSupport rule * fix(native-chat): the route reads the capabilities a paired host actually receives The renderer decided whether a paired host would admit a chat from the desktop's Electron list, but every desktop transport sends that list plus the shared remote base. They agreed only because the route's checks happened to sit in both. The route input is now built with the same remoteRuntimeClientCapabilities the transports use (the browser client already sends its list as is), and a test pins each against the real handshake. * test(cross-version): a released client still gets the host-setting createSupport answer; a launch-mode client gets supported plus the seed * test(native-chat): let main's child-records test resolve each chat's owner Main's new test mocks worktree-runtime-owner with only the runtime environment id, but the status projection in this PR also resolves each structured chat's owner from the worktree. The mock keeps the module's real exports and overrides only what the test pins. * fix(deps): take #24204's lockfile that the merge reverted * test(native-chat): let the Codex child-approval e2e unit test resolve each chat's owner Its worktree-runtime-owner mock exported only the runtime environment id, but this PR's status projection also resolves each structured chat's owner from the worktree. The mock now keeps the module's real exports and overrides only that id, as structured-child-records-switch does. * test(native-chat): move the close-race launch cases into their own file Merging main added launch tests on both sides and took structured-agent-session-launch.test.ts past the 800-line limit. The three cases where a tab close races a launch move to structured-agent-session-launch-close-race.test.ts, with the same setup the other split launch suites copy. * feat(cli): add --unread/--read to orca worktree set Pass validated read/unread flags through the existing workspace metadata update. Contributor attribution correction: the earlier Ctrl+M squash message placed its related link after the co-author footer, so GitHub did not recognize all contributors. Preserve that credit here for https://github.com/stablyai/orca/pull/24100 and its related contribution https://github.com/stablyai/orca/pull/24143 . Related CLI link validation retained from https://github.com/stablyai/orca/pull/20036 . Co-authored-by: Raz Shlomo <12373339+razshlomo@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Zhichang Yu <yuzhichang@gmail.com> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> * feat(cli): configure external worktree visibility per repo Pass show/hide/inherit to the existing repository visibility update. Related: https://github.com/stablyai/orca/pull/23025 Preserves CLI link validation from https://github.com/stablyai/orca/pull/20036 and read controls from https://github.com/stablyai/orca/pull/22714 . Co-authored-by: Neil <neil@stably.ai> Co-authored-by: KAPUIST <thsxornjs12@gmail.com> * perf(git): reuse queries and stop canceled catalog scans (#24923) * perf(git): reuse queries and stop canceled catalog scans * refactor(git): check relay filesystem error codes * test(e2e): require exact Linux package tokens (#24995) * Allow cold node-pty setup on Windows ARM CI (#24997) Keep a ten-minute bound only for node-pty rebuilt on Windows ARM CI hosts; all other node-gyp calls retain five minutes. Cold setup in two completed ARM jobs left compilation less than a minute. * fix(jcode): harden Windows hooks and negotiate remote history (#24998) Redirect the managed Windows payload file into curl instead of starting pipeline shells, register native Windows delivery coverage, and document Jcode v0.89.0+ as the upstream launcher requirement for invisible hooks. Negotiate Jcode history in both directions with mixed-version Orca hosts, preserving supported search filters and old-client response compatibility. Co-authored-by: czzczz <chanzrz_zbf@foxmail.com> Co-authored-by: JianJia2018 <39438074+JianJia2018@users.noreply.github.com> * fix(git): preserve SSH review context and worktree ownership (#24945) * fix(git): preserve SSH arguments and guard background writes * test(terminal): settle fish fixture startup readiness * fix(git): preserve bare UNC SSH paths * fix(git): unescape shell operators in Windows SSH paths * test(runtime): settle removal writes before fixture cleanup * test(git): skip optional OpenSSH probe when unavailable * perf(git): skip equal-tip reads and bound relay discovery * test(processes): ratchet the removed relay Git spawn * test(shells): wait for initial zsh output before sending input * Fix SSH review context and recover Git maintenance cleanup safely * Keep relay Git compatibility fixtures outside shared client projects * Fence superseded maintenance and preserve mixed-version session search * test: model Git child termination and search catalogs * test: retain catalog authority over history flags * fix(opencode): keep shared-session TUI activity with its owning pane (#24962) * fix(opencode): bind legacy attach status to its TUI pane Adapt the official v1 TUI API to the existing pane reporter and learn structural session identity only after execution-host admission. Preserve known creators, gate new reports to capable hosts, and register the legacy TUI entry without changing user settings or overlay targets. Credit werlang for the same-directory investigation in #22838 and #22847; no source from that PR is copied. (cherry picked from commit d9eeb028a23a66b78b08538a5ebf6052499ec24f) * fix(opencode): fence legacy TUI viewers before creator attribution Use the execution host's existing admission policy on the physical TUI pane and launch token before rewriting to a session creator or mutating the launch-token cache. Preserve live viewers, frozen server stamps and OpenCode 2 behavior. Add HTTP regressions for retired panes, closed tabs, replaced tokens and relay retirement, plus current-launch, alias and compatibility controls. Follow-up to #22838 and @werlang's original #22847; preserves the original intentional creator attribution without copying that PR's source. * fix(opencode): preserve current plugin exports in legacy TUI wrapper Keep the current server, setup, id and other default export entries when adding the legacy TUI entry. Cover their preservation and seed the ACL fixtures with the separate installed TUI/config bytes. This completes the current-main port of the legacy identity replacement for issue #22838, carrying @werlang's original PR #22847 contribution. * fix(opencode): retry timed-out SSH plugin updates (#24666) Preserve bounded retry behavior and the current-main status-envelope fields. Original-PR: #24124 Reviewed-source: 103144f9c5029f9217f64970271a5b7f69d3f823 Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(opencode): keep Go credentials private and resolve backend keys (#24615) Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth. Original-topic-commit: 7903f1cddbc08fe1179f8bd964fff3dcb0e5d020 Original-topic-commit: 588117b5cf1dd57e2310c80068e3ddcc9f9044ec Original-topic-commit: dedd4f8c862a961393977dc3c2547f049391b509 Original-topic-commit: 6645dae104ee5271139fcc0e9564d9223b74835d Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276 Restacked-onto: b032867021c7ef1436ca606559e9d786580a84dc Co-authored-by: kespineira <kespineira@users.noreply.github.com> Co-authored-by: kevimux <kevimux@users.noreply.github.com> Reported-by: pullfrog Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f Native-helper-source: 80dbe23237db191c1e6280001c7e0563f3ca8846 Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c * Skip store notifications when refreshed work items are unchanged (#24530) An identical forced refresh previously returned an empty Zustand patch, creating a new root state and notifying every subscriber. It now returns the current state after renewing the existing freshness timestamp. Real row or metadata changes stil…

ELI5
Your Orca desktop can connect to another computer running Orca (a paired Orca server). When it connects, it tells the server which kinds of tabs it knows how to show. It never said "structured chat", so the server hid every structured chat from it, even though the desktop already has the code to show and use one. This PR makes the desktop say so.
This is step 2 of a 3-PR plan to make structured chat work for workspaces that live on a paired Orca server:
#24203 is merged; this PR now targets
mainand contains only its own change. Currentmainfails its node typecheck until #24494 (a four-line import fix after #24203 merged) lands; that failure is not from this PR.What Changed
What you saw before: a structured Claude chat running on a paired Orca server (for example one started on the server itself or from a phone) never appeared on your desktop. The workspace showed no tab for it, and any structured-chat request the desktop made to that server was refused with
structured_agent_session_unsupported (clientCapabilityMissing).Why it happened: a client tells a server what it supports with a list of short names ("capabilities"). The desktop sends one list to its own background process and another to paired servers. The local list named structured chat (
agent-session.structured.v1) and its Claude companion (agent-session.structured.claude.v1); the paired list did not. The capability test recorded the gap with the comment "why it is one is not recorded here". It was never a decision.What you see after:
What changed in the code: the list the desktop sends to paired servers (
src/shared/electron-remote-runtime-client-capabilities.ts) gains three capabilities. These three are the whole change on the wire:agent-session.structured.v1andagent-session.structured.claude.v1: "I can show structured chats". These make the server send the desktop its chats and accept its requests on them.agent-session.structured.client-launch-mode.v1: "I decide myself whether a new agent opens as a chat". A server from fix(native-chat): a paired server admits structured chat by client capability, not its own chat setting #24203 on then answers the desktop's "can I start a chat here?" question from what it can run, not from its own chat setting. The desktop only asks a paired server that question once feat(native-chat): open structured chats on the paired Orca server that owns the workspace #24205 lands, so for now this has no visible effect. fix(native-chat): a paired server admits structured chat by client capability, not its own chat setting #24203 already sends the same capability to the desktop's own background process, so both lists now say the same thing.The capability test now compares what a paired server actually receives (the shared remote list plus the desktop's list) with what the desktop's own background process receives. The old test compared only the desktop's list, so a capability added to the shared list could never fail it. Two such capabilities were found and are now recorded with reasons. The turn-item and two background-task-stop capabilities are no longer repeated in the desktop's list. That leaves what a paired server receives unchanged: every paired connection sends the shared list plus the desktop's list (
remoteRuntimeClientCapabilities(...)insrc/shared/remote-runtime-client-capabilities.ts), and the shared list already contains all three.Scope:
orcaCLI (it sends only the shared list), the browser client (it still does not claim structured chat, so servers keep hiding structured chats from it as today), the phone app, SSH and WSL workspaces (no Orca server runs there).Servers on other versions:
Why
Saying "I support structured chat" promises that this desktop can handle the structured chats a server then sends. It is the same desktop code whichever computer the chat runs on, so the honest list is the same for both. A separate opt-in only for paired servers would keep two lists that drift apart, which is the failure the capability test exists to catch.
This is its own step rather than part of #24205 because it is useful alone (existing chats on a paired server become visible and usable) and safe alone (no new way to start a chat). It is not part of #24203 because #24203 changes only what the server does.
Differences from the common pattern
Visual Proof
Live run on a second Mac (headless Orca server + paired desktop, both built from
b42259d46b1; later heads add only #24203's test-only cross-version coverage and a merge ofmain, isolated profiles, real Claude). The server's own chat setting was off. A Claude chat was started on the server itself (not from the desktop).Before (desktop built from this PR's base
884cfa8070a, same server): the server's chat never appears; the workspace shows only its terminal (watched for 45 s).After: the chat appears as a "Claude Chat" tab in the server workspace with no refresh.
Sending from the desktop composer reaches the server's chat ("Reply with exactly the word PONG" → PONG):
Closing the tab on the desktop retires the chat on the server (the server's tab list drops it):
Starting a new Claude agent with "+" in the server workspace still opens a terminal on the server, as expected until #24205:
Agent Session History lists the server's chat; after the chat was closed, one click on "Resume in Worktree" reopened it with its transcript:
Also checked on this computer: with the desktop's chat setting on, a new Claude launch opens a chat; turned off, it opens a terminal, and the earlier chat still shows as a chat.
Testing
src/main/ipc/desktop-renderer-runtime-capabilities.test.ts: what a paired server receives differs from what the background process receives only where a decision is recorded, and both tell the server the desktop picks each launch mode. Removingagent-session.structured.v1from the paired list fails it.20 test files covering the remote capability lists, pairing, routing, subscriptions and the cross-version wire contract: 248 passed. Node and web typechecks pass.
Live QA on a second Mac (desktop + paired headless server from this head, real Claude): 7 of 7 scenarios passed, including the before-state control above.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Notes
Follow-ups that start to matter with this PR, because this is the step where paired-server chats first appear on the desktop: