Commit Graph
7328 Commits
Author SHA1 Message Date
Neil ab9532ecd8 feat(wsl): let an idle WSL distro stop once its server idle-exits (#33084)
* feat(wsl): let an idle WSL distro stop once its orcad idle-exits

The WSL host's holder kept the distro (and the WSL VM) running after Orca quit, even with
nothing running in it. orcad now leaves a release request in ~/.orca when a managed idle stop
retired its terminal daemon; the holder waits for that orcad to exit, claims the request and
ends, so WSL can stop the distro. Live terminals, working agents, enabled automations or a
returning client keep the distro held as before. A host whose distro is stopped at startup
reads as stopped instead of unreachable, and the real-WSL lane gains a phase that proves the
release and records memory.

* fix(wsl): key the holder release on the WSL-host launch marker; name the lane phase

The real-WSL lane showed orcad idle-stopping with its daemon retired while the distro stayed
up: the setsid'd orcad's environment is not guaranteed to carry WSL_DISTRO_NAME, so the
release request was never written. Use ORCA_WSL_ORCAD_HOST, which only WSL-host launches set.
Phase 3 now carries its phase name and path filter, and records what kept a distro running.

* test(wsl): dispose the idle-release lane's guest transports

Each guest command left its exec loop running, a wsl.exe client that kept the distro up after
the holder had already let go (the receipt showed no holder, no orcad, no request left).

* test(wsl): record which wsl.exe clients keep the idle-release lane's distro up

* test(wsl): satisfy the flaky-test ratchet; feed the new idle port in the release test

* test(wsl): snapshot guest processes after launch to find what holds the session

* test(wsl): locate the step that leaves the zombie holding the idle distro

* test(wsl): log the idle-release lane's guest commands with times to place the zombie

* test(wsl): follow the remote runtime client's move

* test(wsl): record when each leftover WSL session init started

* fix(wsl): keep the distro while the user still runs anything, and never trip on the request file

Review of #33084:
- The holder now checks, before claiming a release, that no process of the user runs outside
  the holder itself (session plumbing aside: systemd --user, (sd-pam), dbus-daemon). A detached
  tmux, nohup job or dev server keeps the distro; it fails toward holding.
- A new holder drops any request left from before it started, so an older orcad's request can
  never end a holder a client just asked for.
- orcad touches the request file only for WSL-host launches and never throws over it.
- The real-WSL lane proves a detached job keeps the holder and its request, and the distro
  stops once the job ends.

* fix(wsl): a running container keeps the distro, whoever owns its shim

Docker's containerd-shim processes run as root, so the user-only scan missed them and a
release would have stopped running containers. Any containerd-shim process now keeps the hold.

* fix(wsl): read each process status only up to Uid; document what keeps the hold

Delta review of #33084: dash reads a status file a byte at a time, so stop at Uid. Document
that a root default user never releases, that per-user agents hold it, and the hidepid
exception. The lane's pkill no longer matches the shell running it.
2026-10-27 01:28:40 -07:00
Neil 0ed5f4bb21 fix(orcad): materialize the app's agent-browser driver into the local slot (#34150)
* fix(orcad): materialize the app's agent-browser driver into the local slot

Replaces #34111's ORCA_AGENT_BROWSER_DRIVER hand-off, Windows profile copy and
claimed snapshot store. Packaging now references the app's own
resources/agent-browser-<target> from the orcad template manifest
(packagedBrowser, like packagedRipgrep), so the materialized slot carries it and
every local orcad launch finds it beside orcad-server.js. macOS signs the driver
before hashing; Windows reseals it after SignPath. The resolver now also tries
the musl driver name on Linux.

Refs #33846

* build(orcad): let a checkout keep template drivers with ORCAD_OMIT_AGENT_BROWSER=0
2026-10-27 01:28:20 -07:00
OrcaWinandOrcaWin 4378e2fd3b perf(native-chat): load the chat host and agent adapters on first use (#34318)
Startup evaluated every structured-agent adapter (claude, codex, acp, pi)
even when no chat was opened. The host install already loaded the
registrations with a dynamic import, but structured-chat-cli-fork imported
the same module statically to read sessionHistory, which the lightweight
metadata already exposes.

- structured-chat-cli-fork reads structuredAgentRuntimeMetadata (the same
  objects, so behavior is unchanged).
- installOnJournal moves unchanged into structured-agent-session-host-assembly,
  which install() loads on first host install; the existing installing slot
  already single-flights and retries it.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 01:14:23 -07:00
Neil 80c9278b89 fix(wsl): say why a silent WSL guest command failed (#34304)
* fix(wsl): say why a silent WSL guest command failed

A guest command that exits non-zero with empty stderr was reported as
"WSL <distro>: command failed". When wsl.exe itself fails it writes its
error to stdout, so the real cause was dropped. Report stderr, else
wsl.exe's own error, else the exit code, for the Claude account pointer,
OpenCode reader, WSL CLI install and WSL file operations.

Refs STA-12262 (#33917)

* refactor(wsl): share the wsl.exe host-failure exit check

* test(wsl): type the guest failure fixture instead of asserting it
2026-10-27 00:58:25 -07:00
OrcaWinandOrcaWin bbc35c1a98 test: remove 30 low-value cases and 11 suites (#34288)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 00:54:59 -07:00
Neil 16ea126b4e fix(repos): remove a paired-server project while its server is unreachable (#34079)
* fix(repos): let a project be removed while its paired server is unreachable

An unreachable server's repo.rm timeout aborted the whole removal. The error toast
now offers 'Remove from this desktop now', which purges this desktop's rows, records
a pending repo.rm (persisted UI state, optional), fences the server's catalog so it
cannot re-add the project, and replays the removal once the server is ready again.
Re-adds and replays for one server are serialized so neither undoes the other.

Fixes STA-9705

* fix(repos): replay owed removals whenever the server is ready, and lift the fence on refusal

Main publishes status only on change, so a record written or seeded after the ready
snapshot now replays at once. A refused replay refreshes the server's catalog, a
retired server drops its records, a user disconnect also offers local removal, and
the field is main-owned so paired clients cannot overwrite it.

* fix(repos): keep owed removals across disconnects and re-pairs; drop them only for forgotten servers

Also picks up records written during an in-flight replay, classifies the new UI field for
WSL moves, and fixes the test's projection shape.

* fix(repos): say 'disconnected' when the user disconnected the server, and test records surviving re-pair

* fix(repos): retry a replay when the server reconnects while it is still failing

* test(repos): narrow the toast action instead of asserting its type

* test(repos): run the toast action's removal directly instead of dispatching its handler
2026-10-27 00:51:44 -07:00
Neil e59e4eb550 fix(wsl): close a WSL host channel with stdin EOF before killing wsl.exe (#34307)
* fix(wsl): close a WSL command channel with stdin EOF before killing wsl.exe

Killing wsl.exe while its guest command still runs can leave the WSL session (an /init with a
wslhost.exe helper) behind, which keeps an idle distro running. A closed channel now ends stdin
first and kills wsl.exe only if the guest has not exited within 2 s.

* fix(wsl): kill WSL-host channels still in their close grace at app quit

Review of #34307: a guest command that ignores stdin EOF would otherwise keep its wsl.exe up
past Orca's exit for the rest of the grace. Quit teardown now kills every channel still in its
grace. The abort test runs on fake timers instead of waiting the grace in real time.
2026-10-27 00:50:37 -07:00
Neil 2c6dd27276 refactor: group shared native chat shell environment policy (#34301) 2026-10-27 00:30:13 -07:00
Neil 1dec1ebc35 refactor(shared): group native chat visual contracts (#34296) 2026-10-27 00:03:29 -07:00
Kelvin Amoaba 30872835cd fix(browser): type text that starts with a dash literally instead of as an agent-browser option (#34289)
* fix(browser): type text starting with a dash literally instead of as an agent-browser flag

* fix(browser): keep fill scripts on eval --stdin and send well-formed batch text

* fix(browser): leave passthrough multi-command batch replies unwrapped

* fix(orcad): pass the wait process timeout through the run options

* refactor(browser): let caller stdin imply argv mode and share the batch decoder in tests

* test(orcad): decode batch commands in the provider selection fake
2026-10-27 07:01:46 +00:00
Brennan Benson a0e7fa0619 Keep Claude approval choices across model changes without freezing delivery (#34031)
* fix(native-chat): keep Claude approval choices across model changes without freezing delivery

A Claude chat saved as "Approve for me" could reopen asking for every approval,
because Orca read the folder's saved model list as launch policy, and a model
change could keep running in a weaker approval mode Claude opened with. The
first fix for this was reverted after it froze the app: restored history left
a turn reading as running, a send was refused against it, and delivery retried
the same send with nothing changed.

- The saved approval choice goes to Claude as-is; the menu offers every mode.
- Orca records the mode Claude actually opened in. A send that picks a new
  model reopens Claude first when that mode differs from the one requested,
  only when the chat owes no work; Orca mail notices never reopen it.
- A message sent while a Claude turn is running joins that turn on its current
  choices; new choices apply at the next new turn. Nothing is refused.
- History catch-up closes every turn it opens, in the thread it opened in.
- At startup, a turn reading as running under the new agent that the agent is
  not running is ended as interrupted.
- Delivery goes round again only after a step shows what it changed (a commit,
  a different child, a start it joined ending, or a wake); otherwise it waits
  for the next change instead of repeating the same step.

Tracked in STA-10953.

* fix(native-chat): preserve execution evidence at dispatch

* Fix delivery iteration ownership and progress contracts

* Correct journal fixture types in delivery regressions

* Separate Claude input choices from error correlation
2026-10-27 00:01:09 -07:00
Brennan Benson 1c4d4a03bc feat: drag to reorder queued messages on desktop and phone (#34026)
* feat: drag to reorder queued messages on desktop and phone

* fix: use the queue grip button padding from its primitive

* fix: preserve the queue grip touch width with hit slop

* test: carry queue animation mocks into the chat view harness

* test: complete the shared chat view harness registrations

* test: carry the queue move cross-version wire contract

* Scope queue move feedback to the issuing chat and preserve phone touch width

* Keep queue reorder presentation stable during measurement and pending moves

* Keep measured row handoff tokens constant size

* Avoid rebuilding queue arrival IDs on unchanged renders

* Fix mobile queue regression test fixture boundaries

* Share the queued message leading slot with its reorder grip

* Fix queue regression fixture quality findings

* Check queue icons within the leading slot

* Allow every unsettled queued message to reorder

* Supply stable scope in queued row test mock
2026-10-26 23:57:36 -07:00
217f935597 fix(updater): skip IPC when the main window is destroyed (#11567)
The updater kept a reference to the main BrowserWindow after it closed, and
every status/nudge/install-abort send read `webContents` on it. Electron throws
"Object has been destroyed" from that getter, so the hourly background check
produced main-process unhandled rejections from the MacUpdater failure path.

Route all updater IPC through UpdaterState.sendToMainWindow, which drops the
send when the window or its webContents is destroyed. The renderer re-pulls
status via updater:getStatus on mount, so nothing is lost. Updater test window
mocks now come from the shared updaterMainWindow helper.

Fixes #11544

Co-authored-by: Brennan Benson <brennan@stably.ai>
Co-authored-by: Neil <neil@stably.ai>
2026-10-26 23:51:44 -07:00
Kelvin Amoabaandoutof-place 8655ce670f fix(browser): deliver agent clicks and keys to pages that loaded while their pane was hidden (#34291)
A page that loads while its browser pane is parked (display:none) never
paints, and Chromium drops input to a document before its first paint.
orca click/hover/keypress/mouse on such a page reported success after a
~5 s mouseMoved stall while the page got no press or key.

Before agent input reaches a webview guest, from the CDP proxy queue or
the bridge's direct pointer and key routes, ask the page whether it has
painted. If not, hold its paint with the existing capture paint hold
until a paint entry appears or a few frames pass, once per document.

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-27 06:48:31 +00:00
OrcaWinandOrcaWin 136721fcb9 test: remove53 low-value cases and8 suites (#34264)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 23:45:26 -07:00
Neil b29ae01912 fix(automations): show why a hook-review-blocked automation fails, keep it running, and stop stuck-tab pile-up (#33638)
* fix(automations): pause a schedule whose agent is stuck on a hook review

Codex opens a blocking 'Hooks need review' dialog when a hook in hooks.json is
new or changed. Only a person can answer it, so every later scheduled run of
an automation hit the same dialog and failed. Pause the schedule on the first
such failure and say how to recover. Also re-enable Orca's own Codex hook on
SSH installs, matching local installs.

Refs #28252 #23289

* fix(automations): keep a hook-review-blocked schedule running and say why it fails

Replace the auto-pause with a visible, self-clearing failure: the run error
explains the Codex hook review, the automation and run pages show it above
saved output, and earlier tabs stuck on the same prompt close so only the
newest stays open to answer. Runs succeed again on their own once the hooks
are trusted or removed.

* fix(automations): only close hook-review tabs the run still owns and that are provably unused

- Cleanup resolves the pane through runOwnHandle, so a cold-restored pane holding a new process is left alone.
- Close only on definite 'unused' input history, matching headless run-terminal retention.
- Catch failures from the fire-and-forget cleanup call.
- Show the run page error notice only for dispatch_failed runs, and add the missing en catalog keys.
2026-10-26 23:21:28 -07:00
Kelvin Amoaba cd757f4b19 fix(browser): pass orca wait's timeout through to agent-browser (#34283)
Condition waits never forwarded --timeout, so agent-browser always stopped at its own 25s default and --timeout 60000 still failed at 25s. orcad's external Chromium run and Electron sidecar socket also capped waits at a fixed 90s. One builder now passes --timeout (explicit or the documented 25000 default) on the local and orcad paths, process kills sit 5s above it, and every forwarding hop waits max(60s, T+30s).
2026-10-27 06:17:21 +00:00
Neil 43eb0b969c fix(opencode): give OpenCode 2 a private server only when another data dir holds the service port (#33784)
* fix(opencode): run managed OpenCode 2 accounts on a private server

OpenCode 2's background service binds one fixed port per machine, so a
second managed account's service could never start. Launch managed
accounts with --standalone, which picks its own port.

Fixes #33780

* chore(opencode): tighten standalone rewrite comments

* fix(opencode): use a private OpenCode 2 server only when another data dir holds the service port

Users with one managed account keep the shared background service. Orca
adds --standalone only when a live upstream registration
($XDG_STATE_HOME/opencode/service.json) belongs to a different data dir,
plus a short in-process claim for launches that start together.

* fix(opencode): judge resumed accounts by their applied data dir and claim the port only for real launches

Daemon spawns consume the resume request before the private-server check runs, so
derive the launch's own data dir from the applied account env when present. Only
take the shared-port claim when the --standalone rewrite can apply.
2026-10-26 23:06:43 -07:00
Wooseong KimandNeil 845e4668e3 fix(orchestration): stop calling unobserved worker input "submitted" (#21453)
When a worker's turn start was not observed, the dispatch receipt claimed
the input was "written and submitted". A swallowed Enter leaves the prompt
in the composer, so say the text and Enter were written, keep the wait bound
and possible causes, and point at `terminal read` before resending.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 22:59:09 -07:00
OrcaWinandOrcaWin 84494ce394 test: remove 338 low-value cases and 28 suites (#34234)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 22:58:55 -07:00
Neil fa4d2e99db fix(wsl): reap the bash stdio relay's cats before it exits (#34260)
* fix(wsl): reap the bash stdio relay's cats before it exits

The relay killed the surviving cat and exited at once. WSL's per-session init never reaps
orphans, so that cat stayed a zombie, its session never ended, and the distro never stopped
even with nothing of Orca's left in it (seen on every real-WSL idle-release run). Wait for both
cats after the kill.

* test(wsl): prove the bash relay waits for the cat it kills
2026-10-26 22:54:27 -07:00
Neilandlorenzozanee bca89125ce fix(updater): apply the app proxy to electron-updater's session (#34276)
electron-updater sends checks and downloads through its own
"electron-updater" partition, so a proxy configured only in Orca settings
never reached update requests. Apply the same proxy policy (and request
guard) to that partition at updater setup and on settings changes, and
answer its proxy login challenges with the configured credentials.

Co-authored-by: lorenzozanee <195543813+lorenzozanee@users.noreply.github.com>
2026-10-26 22:52:25 -07:00
Neil 6ae3fbc89b fix(browser): open target=_blank file links from a local page in an Orca tab (#34057) 2026-10-26 22:42:19 -07:00
Neilandoutof-place d5070dedb8 fix(app-icon): restore the sharp bundle icon on the Dock for packaged Classic macOS builds (#34094)
Packaged Classic builds left the live Dock tile on the 256px icon.png set by
applyAppIcon. Once the queued AppKit custom-icon clear succeeds and no newer
icon request is pending, persistMacDockIcon now calls
app.dock.setIcon(nativeImage.createEmpty()); Electron passes that to AppKit as
nil, so the Dock draws the full-resolution bundle icns. A failed or timed-out
clear keeps the PNG, as before.

Fixes #27138

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-26 22:30:59 -07:00
Kelvin Amoaba 9d2e441947 fix(mobile): compare branches and show diffs with desktop's base-ref and whitespace settings (#34038)
* fix(mobile): compare branches and show diffs with desktop's base-ref and whitespace settings

Base-ref resolution moves to src/shared and the host publishes the compare-against-upstream
and show-whitespace settings, so the phone's branch compare and diffs match desktop.

* fix(mobile): use the upstream compare policy on the review screen and rebuild diffs when whitespace changes

* fix(mobile): reread Source Control settings on Refresh and restart diffs loading under the old whitespace setting

* test(mobile): cover diffs dropped when desktop's whitespace setting arrives

* refactor(mobile): share one Source Control settings read per host across screens
2026-10-27 05:29:46 +00:00
Neil 6d43596fda fix(wsl): keep a user's GLIBC_TUNABLES and delegate the launch-env wrapper (#34248)
* fix(wsl): keep a user's GLIBC_TUNABLES and delegate the launch-env wrapper

The orcad launch now sets GLIBC_TUNABLES only when the launching shell has
none, so a value forwarded through WSLENV wins and the claim leaves it in
place. withOwnBuildLaunchEnv delegates to the transport instead of copying
its own properties, so a class-based transport keeps its methods.

* test(wsl): read the delegated transport through its type, not Reflect

withOwnBuildLaunchEnv now returns the transport's own type, so the test
calls the class method directly. The comment no longer claims #private
class fields survive delegation.
2026-10-26 22:26:11 -07:00
a7c9d19048 fix(file-explorer): offer permanent delete when moving to Trash fails (#33956)
Offer confirmed permanent deletion when moving an item to Trash fails.
Preserve authorization and workspace ownership checks, cancellation behavior,
text-snapshot undo, remote compatibility, and all supported translations.

Fixes #33944

Co-authored-by: nori <dosukoicrypto@gmail.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 22:25:01 -07:00
Neil 362104ca18 fix(wsl): background Git and the roots catalog never start a stopped WSL distro (E9) (#34231)
* fix(wsl): background Git and the roots catalog never start a stopped WSL distro

git status ran on the UNC project root 0.45 s after a terminate, next to the
explorer read; either boots the distro. Background Git (status, conflict
operation, upstream status, branch compare, the upstream-ref watch) now asks the
shared running gate first and refuses for a stopped distro, including host
paths whose Git runs through wsl.exe. The authorized-roots rebuild skips a
stopped distro's repo and leaves it dirty, and the detected-worktree scan fails
as unavailable, so rows are kept and the next scan after the distro runs lists it.

* fix(wsl): the active workspace's first status and a wake read's roots rebuild may start WSL

- Drive-path projects whose Git runs through WSL had no wake path: the active
  workspace's first git:status after it becomes active now passes
  wakeWslDistro, so Source Control starts the distro; later polls stay gated.
- A user act runs in an async scope naming its distro; gated work inside it
  (the authorized-roots rebuild an authorization miss triggers, the detected
  scan, the Git) may start that distro and no other. External worktrees on a
  stopped distro no longer fail a wake read with access denied.
- After a user act wakes a distro, background reads stop trusting the older
  'stopped' read and probe again.

* fix(wsl): explicit WSL launches refresh the running read; wake only on tab change; gate the home probe

- Any wsl.exe Git/CLI run (commit, push, fetch) or WSL terminal spawn for a
  distro last read as stopped records that it started, so background reads probe
  again instead of refusing for up to 60 s.
- The active editor tab wakes only when the active tab changes; effect re-runs
  driven by git status or overview views read without waking.
- The authorization roots' WSL home probe no longer runs wsl.exe in a stopped
  distro when the home is uncached.
- The settle window no longer imports the orcad liveness module (it pulled main
  code into the web typecheck); a test pins it to EXIT_SETTLE_MS.

* fix(wsl): deferred work and running-list listeners never inherit a user act

A user act's async scope could leak into work it triggers indirectly: a drain of
deferred tasks it caused, or listeners of a running-list probe started inside
it. Both now run outside the scope, so only the act's own work may start its
distro.

* fix(wsl): keep shared modules free of main-only gate imports

worktree-logic.ts and wsl-running-distro-cache.ts are also compiled by the web
project, which cannot see main-only modules (AsyncLocalStorage, wsl.exe).
getAllowedRoots now injects the gated home lookup into computeWorkspaceRootWithin,
and the background gate's own cache subscriptions run outside the user-act scope
instead of the cache knowing about it.
2026-10-26 22:23:07 -07:00
OrcaWinandOrcaWin a8f7afe84b test: remove 128 low-value cases and 22 suites (#34206)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 22:21:44 -07:00
Brennan Benson 2e181b1b78 Reuse chat history snapshots across readers (#34215)
* Reuse rendered chat history across readers

* test: cover current journal reads across source changes

* test: align journal assertions with current snapshot reuse
2026-10-26 22:19:15 -07:00
9dd44715ba fix(mobile): keep a renamed tab's name on mobile after the host restarts (#33743)
* fix(mobile): keep a renamed tab's name on mobile after the host restarts

After a restart, the reconnecting client restarts each saved tab's
terminal (restored-pane-materialize -> createRuntimeOwnedMobileSessionTerminal),
and the mobile row built from the new terminal carried no customTitle, so
the phone showed the terminal's own title although the saved session still
held the name. publishPtyBackedMobileSessionTerminal kept a name only from
an earlier mobile row, which a restart does not have.

Both builders now resolve the name through one helper: a value already on
the mobile row wins, including a cleared null; only a row with no value
falls back to the tab's saved name.

Fixes #33737

Co-Authored-By: Claude Code <noreply@anthropic.com>

* refactor(mobile): resolve a restarted tab's saved name through getPtyManualTitle

getPtyManualTitle already owns a terminal's manual name (the saved tab's,
else the live rename), so the row builders use it instead of a second
saved-session lookup. A cleared name reads as cleared from the saved
session, so the test now covers that instead of a row-only clear.

* fix(mobile): keep a row's cleared name instead of falling back to the saved one

A null customTitle on a row is a clear: paired desktops need it to drop a
cached name, and a desktop clear lands on the row before the debounced
session write. Only a row with no value falls back to getPtyManualTitle.

* test(mobile): pin that a row's cleared name survives a terminal restart

---------

Co-authored-by: clayphi <193966884+clayphi@users.noreply.github.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-27 05:18:58 +00:00
Neil bff2843fca refactor(shared): organize native chat ask input owners (#34251)
* refactor(shared): group native chat ask input owners

* refactor(shared): keep split ask type imports erased
2026-10-26 22:18:52 -07:00
Kelvin AmoabaandChris Stephens 619ee954c9 fix(browser): paste the local clipboard into streamed browser pages (#34269)
The streamed page's keydown handler forwarded Ctrl/Cmd+V to the host as a
keypress and cancelled the browser's paste event, so the host pasted its
own (usually empty) clipboard. Native paste chords now fall through, and
the frame's paste event inserts the clipboard text with
browser.keyboardInsertText on the pane's input queue, split into chunks
that fit the runtime socket frame.

Co-authored-by: Chris Stephens <nyldn@users.noreply.github.com>
2026-10-27 05:16:01 +00:00
Kelvin Amoaba e79388e3ab fix(agents): keep OMP session titles when a turn finishes (#34266)
Orca wrote a synthetic "OMP ready" / "OMP - action required" title over
the session title that OMP and Orca's titlebar extension already paint.
OMP's hooks are authoritative and its own rest title reads as idle, so
stop synthesizing terminal titles for OMP, as for OpenCode.

Linear: STA-11986
2026-10-27 05:15:58 +00:00
Kelvin AmoabaandFelipe 19c53e5248 fix(browser): let Grab page element pick and track elements inside open shadow roots (#34265)
* fix(browser): let Grab page element pick and track elements inside open shadow roots

Document hit-testing and marker lookups stop at a shadow host, so Grab only
ever picked the host. The overlay now descends through open shadow roots,
and both the overlay and the annotation viewport bridge find the marked
element and listen for scrolls inside them. Closed roots stay opaque.

Co-authored-by: Felipe <5784455+fbetancourtc@users.noreply.github.com>

* fix(browser): track slotted ancestors and stop re-walking shadow roots for a lost target

* fix(browser): walk shadow roots once per selection and count fixed shadow hosts

* fix(browser): restore grab pointer events if a page's shadowRoot throws; type the shadow fixtures

* fix(browser): keep composed-tree walks safe from page-named form controls

---------

Co-authored-by: Felipe <5784455+fbetancourtc@users.noreply.github.com>
2026-10-27 05:15:54 +00:00
Neil 51c393bc2e fix(wsl): close a WSL host's loopback listener once it idles out or its distro stops (#34046)
* fix(wsl): close a WSL host's loopback listener once its orcad idled out or its distro stopped

The supervisor already stops watching an idle or stopped host and never relaunches it for
background work, but the bridge's loopback listener stayed open, and any dial to it (a status
probe, a stale client) spawned wsl.exe and booted the distro again. Retire the listener in both
branches without publishing 'closed', so the host keeps reading as idle or stopped; the next
user connect binds a new one.

* fix(wsl): a retired listener never proves orcad live; never retire a connect in flight

Review of the listener retirement: with no connection, the port probe answered 'ready', so a
wake verify with no orcad pid to compare read the host as live, published ready and re-held
the distro. It now reads as refused. retireListener also leaves alone a key whose user connect
is in flight, so a trigger mid-connect cannot retire the entry that connect produces.

* fix(wsl): retire the listener on E9's single park path too

E9 A parks every confirmed stop, visible work or not; retire the loopback listener there,
before the deferred re-check, so a dial cannot boot the parked distro.

* fix(wsl): read the park generation before retiring the listener
2026-10-26 22:15:00 -07:00
Jinwoo Hong c23ab5546c Antigravity: show a login with no quota as unavailable, not "Refresh failed" (#34163) 2026-10-26 22:07:52 -07:00
Jinwoo Hong ad4b9af825 Stop opening a Google sign-in page every hour when agy is signed out (#34165) 2026-10-26 22:05:27 -07:00
Brennan Benson 192f5783ab fix(runtime): keep terminal.send under the file-length limit with one refusal helper (#34256)
#33968 pushed terminal-send-method.ts to 301 counted lines against the 300-line rule, failing Lint on main and every PR that merges it. Eight refusal branches spelled out the same zero-byte result; one helper builds it.
2026-10-26 22:01:45 -07:00
Kelvin Amoabaandpullfrog[bot] 3c8e40a4c9 fix(browser): make orca set media --reduced-motion apply and reject unknown values (#34253)
* fix(browser): make orca set media --reduced-motion actually apply

agent-browser's set media only looks for the bare tokens dark, light and
reduced-motion and ignores anything else, so the documented reduce value
was dropped and the command still reported success. Map Orca's values
onto those tokens in one builder used by the desktop bridge and the
orcad external Chromium path, and reject unknown values.

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>

* fix(browser): reject bad set media values before queuing and list both flags in help

---------

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
2026-10-27 04:40:53 +00:00
NeilandClaude e2b8332804 fix(terminal): closing a kept host-loss tab after a relaunch ends its history (#34205)
* fix(terminal): closing a kept host-loss tab after a relaunch ends its history

A WSL bridge pane lost with its distro keeps its tab and unended history. The
adapter only remembers the loss in memory, so after a relaunch closing that
tab before waking it hit SessionNotFound and left its history directory
behind. The router now ends that history when the id's history is unended and
every daemon, current and legacy, answers that it does not list the id. A
listing or an unanswered daemon keeps the history.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(terminal): end a lost session's history only when every daemon can answer for it

Review of the close-after-relaunch path: the router-only check never ran
when the app has no legacy daemons (the provider is then the bare adapter),
and the router's adapters are not every daemon sharing the history dir. An
older daemon whose socket probe failed at startup gets no adapter, and a
daemon held for a newer protocol has none either; both may still run the id.

The check now lives in the adapter's close. It ends the history only when it
is unended, no daemon is held for a newer protocol, no older protocol's pid
file names a process that may be alive without an adapter to ask, and every
known daemon answers listSessions without the id. A router shares its
adapters as the daemons to ask.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(terminal): decide a lost session's close in one lock, and never connect a daemon to list it

Review: the unlisted-session check already runs inside shutdownWithHistoryLock,
so a spawn queued for the same id waits until the close has decided; a test
now holds the listing open and proves the spawn cannot slip in. listsSession
no longer connects (or respawns) a daemon just to list it: an unconnected
daemon cannot answer, which keeps the history.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(terminal): count an older daemon Orca may not signal as alive; cover slept-tab closes

process.kill(pid, 0) failing with EPERM means the process exists under another
user, so legacyDaemonProcessMayBeAlive now treats it as alive; only a missing
pid file or ESRCH counts as gone. Tests pin that, and pin the wider scope of
the unlisted close: closing a slept tab without waking it ends its unended
history, and keeps it while another daemon lists the session.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(terminal): move the lost-session listing and check out of session control

daemon-pty-session-control.ts went over max-lines. The daemon listing read and
the unended-history check now live in daemon-unlisted-session.ts beside
mayAnyDaemonRunSession; the adapter keeps only thin calls. No behaviour change.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 21:28:36 -07:00
Kelvin Amoaba 75bcd328cf fix(mobile): answer multi-question asks like desktop and clear Claude's wait on phone answers (#33968)
* fix(runtime): clear Claude's question wait when a phone keystroke answers it

Claude sends no hook after AskUserQuestion is answered; desktop infers it, phone answers left the pane waiting.

* fix(mobile): answer multi-question cards like desktop, with Skip and back-stepping

Mobile required every answer and locked grouped structured questions once tapped; the card rules and structured mapping now live in shared code.

* fix(mobile): announce ask card options as checkboxes or radios

* fix(mobile): answer a grouped question only on the prompt it was picked on

* test(runtime): drop the multi-question case the shared answer rule already covers

* refactor(native-chat): share the typed-answer rules and fold the host answer check into terminal.send
2026-10-27 04:27:06 +00:00
Kelvin Amoaba a9f90e7a71 fix(mobile): use desktop's terminal paste, key and query-reply rules (#33957)
* fix(mobile): send terminal paste, keys and query replies like desktop

* fix(mobile): encode Shift+Enter for the pane's negotiated keyboard modes

The phone's xterm now tracks Kitty flags and modifyOtherKeys with desktop's tracker, seeded from the host snapshot.

* fix(mobile): keep keyboard modes across terminal snapshots

* fix(mobile): adopt snapshot keyboard modes with desktop's rule

* refactor(terminal): share snapshot keyboard-mode adoption and mode mirroring

* fix(mobile): compare terminal modes field by field instead of a dynamic read

* refactor(mobile): share terminal display-mode adoption between snapshot and resize

* fix(mobile): accept only known terminal display modes from the host
2026-10-27 04:26:16 +00:00
Kelvin Amoaba 7e5f9a48df fix(mobile): use desktop's sort, colour, count, agent-row and delete rules in the workspace list (#33995)
* fix(mobile): use desktop's sort, colour, count and agent-row rules in the workspace list

Recent ignores terminal output, repo colours fall back to desktop's neutral,
Home counts skip archived rows, folder workspaces trail each lane, and a stale
agent row on a live terminal reads "No update in …" like desktop.

* fix(mobile): keep Delete disabled on a primary checkout, as desktop does

* fix(mobile): keep the task text on a silent agent row

* fix(mobile): show a silent agent row's time since its last update

* test(mobile): drop agent-row tests that replay the shared verdict

* refactor(mobile): check host PTY liveness once and keep the delete guard on the row flag

* test(mobile): re-record the home catalog goldens for the list's active count
2026-10-27 04:25:59 +00:00
Neil fe82078909 fix(wsl): background file reads and watches never start a stopped WSL distro (E9) (#34222)
* fix(wsl): background file reads and watches never start a stopped WSL distro

Any Windows touch of a \\wsl.localhost path boots a stopped distro. After a
terminate, the dying explorer watcher's overflow refresh ran realpath on the
project root 0.23 s later and booted the distro again. Background reads, stats
and watch installs now ask a fresh running list first (shared, with a 5 s lease
and a stop signal from the watcher exit and the hook relay link) and refuse when
the distro is stopped. Opening the workspace and Retry still start it. A stopped
watch waits for the distro and resyncs the explorer when it runs again.

* fix(wsl): trust a confirmed running read for 60 s without a stop signal

* fix(wsl): user acts wake; unverifiable is not stopped; settle after a stop

- Opening a workspace, expanding a folder, opening a path (explorer, quick-open,
  links), the active editor tab's load and every Retry pass wakeWslDistro on
  readDir, readFile, stat and readFileChunk. Background reloads, restored-tab
  scans and watchers stay gated.
- A failed running-list read is 'unverifiable', not 'stopped': the gate re-reads
  once past the failure backoff (once per failure window) and otherwise refuses
  with 'WSL didn't answer', never touching the path.
- After any stop signal, a running read that started within EXIT_SETTLE_MS of it
  never counts, in isWslDistroRunning itself, so neither the watcher's own
  overflow refresh nor the hook relay's restart check can read a stale listing.
- A confirmed read that sees a distro stop records a stop signal, resetting the
  60 s lease.

* test: user-opened stats now carry the WSL wake flag
2026-10-26 21:17:07 -07:00
Kelvin Amoaba 6c2423d25d fix(mobile): list Source Control changes with desktop's sections, order and row rules (#34017)
* fix(mobile): list Source Control changes with desktop's sections, sort and row rules

Conflicts get their own section in the user's group order, submodule rows lose stage and
discard like desktop, paths sort with the shared collator, and review notes go out as desktop formats them.

* fix(mobile): read the group order the host now publishes and keep submodule rows read-only

The host's paired settings projection now carries sourceControlGroupOrder, the
normalized status projection keeps submodule metadata, and conflict rows reuse the
shared conflict-kind labels.

* refactor(mobile): share Source Control grouping and row rules with desktop

Desktop and mobile group rows through one shared helper, mobile's unstage button
follows desktop's rule, and the group order resets when the host changes.
2026-10-27 04:14:56 +00:00
Neil e882d8eda7 fix(window): pump hidden-window frames from the renderer on Windows background launches (#34197)
* fix(window): repaint a never-shown background window on Windows so CDP screenshots return

Windows composites nothing for an idle window that was never shown, so
Page.captureScreenshot under ORCA_BACKGROUND_LAUNCH=1 waited forever once the
status-bar usage chip stopped animating (#33799).

* fix(window): pump hidden-window frames from the renderer on Windows background launches

Main-process webContents.invalidate() did not make a never-shown Windows window
produce a frame CDP can capture (verified on Windows 11). A one-frame root
background flip from the preload does, so main stamps a preload flag for
ORCA_BACKGROUND_LAUNCH=1 on win32 and tells the preload to stop on first show.

* fix(window): stop the hidden-frame pump only on main's show signal, including after reloads

A never-shown Windows window can report visible after a desktop change, so the
preload no longer stops on visibilitychange; main re-sends the stop after any
reload once the window has been shown.

* fix(window): register the frame-pump stop with on('show') so every window double supports it

createMainWindow suites simulate win32 under the runner's ORCA_BACKGROUND_LAUNCH=1,
so they install the pump stop; their window doubles implement on() but not once().
2026-10-26 21:13:42 -07:00
NeilandClaude 8d62374000 chore(terminal): log the WSL bridge exit verdict and how long the probe took (#34220)
* chore(terminal): log the WSL bridge exit verdict and how long the probe took

A bridge pane's exit is host loss only if the running list, read after the
exit, lacks its distro. Orca's own background reads can reboot the distro
within seconds, and nothing recorded what the probe answered, so a run could
not tell host loss from a raced reboot or a slow wsl.exe. The check now
returns lost, running or unavailable, and the adapter logs it with the probe
latency. Behaviour is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>

* chore(terminal): put the probe's doc comment on checkWslBridgeDistro

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 21:12:42 -07:00
Neil 6357bd7d03 refactor(shared): organize native chat task-list evidence (#34226) 2026-10-26 20:43:05 -07:00
Kelvin Amoaba 3347d47a7d fix(mobile): use desktop's PR lanes and status-dot rollup in the workspace list (#33966)
* fix(mobile): ask before running orca.yaml default-tab commands from the phone

The host's repo.hooks reply now carries desktop's setup config, so the phone
gates the Run/Skip choice and the trust prompt on defaultTabs commands too.

* fix(setup): keep the local script in run-both setup config without orca.yaml commands

* test(setup): drop the shared duplicate-host trust test desktop already covers

* refactor(setup): derive host setup trust from the shared setup config

* fix(mobile): count every host's repo rows before honouring repo-wide setup trust

* fix(mobile): show desktop's PR lanes and failed/interrupted status dots on the phone

The host builds worktree.ps linkedPR with the desktop's PR-lane cache reader
and sends the desktop sidebar dot as an optional sidebarStatus field.

* fix(mobile): keep uncached PR badges and let finished turns show through working titles

* fix(mobile): suppress agent panes' permission and parent titles in the host status dot

* test(runtime): expect sidebarStatus on the compact ps summary

* test(runtime): keep only host-specific sidebar status cases

* refactor(mobile): keep host title suppression and the uncached PR lane in one place each

* test(wire): pass the terminal title evidence map to new host builds

* fix(runtime): read each workspace's PR through its own host's repo
2026-10-27 03:20:58 +00:00