useStructuredAgentSessionOwnPermissionState subscribed to the whole
runtimeStatusByEnvironmentId map, so each status publication for any paired
host rerendered every mounted chat (including hidden ones). Select the
derived capability verdict for the chat's own host instead.
Co-authored-by: Claude <noreply@anthropic.com>
* 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
* 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
* 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
* fix(browser): copy and cut from streamed browser pages to the local clipboard
The streamed frame forwarded Ctrl/Cmd+C and X to the host page as a
keypress, so the host's Chromium copied into the host machine's
clipboard. The chord now runs copy or cut inside the page over the
existing browser.eval and writes the text to the viewer's clipboard. A
cut deletes the selection only after that write succeeds.
* test(browser): read streamed keyboard RPC calls through the typed helper
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>
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>
xterm's touch inertia gesture events carry no clientX/clientY, so with a
TUI requesting wheel reports a flick sent `ESC[<65;NaN;NaNM` to the PTY
(#20983). NaN slipped past `col < 0 || col >= cols`; the patched range
check in MouseService._triggerMouseEvent is negated so it fails closed.
Regenerate the beta.304 bundle and lock hash.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* 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.
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).
* 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.
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>
* 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
* fix(browser): focus newly opened image tabs
Focus the window before the webview so Command+W closes the new
image tab instead of the original tab after a plain image click.
Add tests for focus order, image loading, and close-shortcut forwarding.
Fixes#34114
* test(browser): verify image tab focus with native keyboard input
* refactor(ci): keep browser E2E routes within registry size limit
* fix(ci): enable background launch for native browser regression
* test(ci): include browser routes in isolated detector fixture
---------
Co-authored-by: Neil <neil@stably.ai>
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>
The pending-terminal budget was skipped whenever another session-tabs
recovery need was active, so it never ran out and the terminal never
reached "Terminal is taking longer than expected" with Retry.
Refs #32231
Co-authored-by: zhangxaochen <zhangxaochen@163.com>
Plugin language packs register under synthetic plugin<hex> resource
languages, so i18next's plural resolver fell back to English rules and
Russian/Polish/etc. packs never selected their _few/_many forms. Map each
pack's resource language to its declared (Intl-supported) locale inside
the plural resolver, and fill missing plural categories from the key's
_other form so packs that only ship _one/_other stay in-language.
Co-authored-by: Neil <neil@stably.ai>
Opening the "..." menu on one Session History row left another row's
menu open, because the row wrapper's pointerdown stopPropagation hides
the click from Radix's outside-dismiss. Each row now controls its menu
state and broadcasts the shared close-all-context-menus event when it
opens, so any other open row menu closes.
Fixes#31563
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
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>
* fix(mobile): open wrapped terminal urls and paths with desktop's link detection
Desktop's terminal URL and file-link detectors move to src/shared and the phone's
WebView document calls them, replacing its single-row copies. File taps carry every
reading of the tapped text so the phone opens the longest one the host finds, as
desktop does.
* fix(mobile): keep the unc host of osc 8 file links for the host to resolve
* fix(mobile): resolve terminal file-tap readings a few at a time
A tap inside a run of path rows yields hundreds of hard-wrap guesses; firing them all at once overflowed the page bridge's pending-request cap and the real path was never checked.
* refactor(terminal): share the osc 8 link classifier and trim file-tap plumbing
Desktop and the phone now read OSC 8 targets through one shared classifier. Terminal file taps carry only their candidate list, deduped by path, and desktop checks OSC overlap only for candidates it can resolve.
* refactor(terminal): keep shared link files under the line cap
The xterm buffer subset gets its own module, and the text-only OSC resolver goes now that the router uses findExactTerminalFileLink.
* 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
* 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.
devalue rejects Error objects, so when a NODE_RUNTIME_INCLUDE test file
failed to load, the pool's send() threw DevalueError and the run ended
without a summary. Give both ends of the IPC channel one codec with a
matching Error reducer/reviver (name, message, stack, cause) so the load
failure reaches the reporter as a normal FAIL.
Fixes#29854
Co-authored-by: Neil <neil@stably.ai>
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>
* 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.
Bump agent-browser to 0.27.3. Its 0.27.2 release scrolls the target node into
view (nested scroll containers included) before computing the click point and
errors when another element covers that point, instead of reporting a click
that never reached the page.
* Reuse rendered chat history across readers
* test: cover current journal reads across source changes
* test: align journal assertions with current snapshot reuse
* 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>
`npx` and `npm run` set npm_execpath to npm's own npm-cli.js/npx-cli.js,
so resolvePnpmCliInvocation ran npm with pnpm's arguments. Skip npm's CLI
by file name and fall back to PNPM_HOME / pnpm on PATH. Route
build-workspace-packages and terminal layout parity through the shared
resolver instead of their own npm_execpath parsing.
Fixes#29438
Co-authored-by: Lance Woodson <65194841+woodsonl@users.noreply.github.com>
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>
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
* 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>
* 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
#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.
* 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>