Commit Graph
16655 Commits
Author SHA1 Message Date
Brennan Benson c20971dbd1 fix(native-chat): send launch prompts and worker tasks through the retrying start (#33832)
* Make opening launch prompts own the retrying chat start

* test: observe launch inventory through surface publication

* fix: keep blank chat launch prompts unsent

* fix: bound launch seed filtering and update CLI replay fixture

* fix: preserve encoded launch selections after filtering
2026-10-26 10:45:40 -07:00
Brennan Benson dff068fe46 Show chat-only workspaces as active before the first message (#33815)
* fix(sidebar): show chat-only workspaces as active before the first message

A workspace whose only tab is a native chat showed the grey Inactive dot
until a message was sent, because the dot counted only live terminals and
browser tabs. Count a chat that is not explicitly slept, the same rule the
sleeping-workspace check already uses, in the sidebar cards, the parent
picker and the Cmd+J switcher.

* test: bound chat status work on unrelated store writes

* test: correct chat status contract formatting

* test: use a fixed clock for chat status fixtures

* test: prune obsolete chat status clock allowance

* test: complete sidebar status store fixtures
2026-10-26 10:44:34 -07:00
Jinwoo Hong 2a15a50691 fix(relay): retire a pooled Postgres connection that turned slow or lossy (#33900)
Director only. When one pooled connection is far slower than its peers (median over 25 ms and 3x theirs, or third-slowest statement in 60 s over 200 ms and 5x every peer's slowest), it is destroyed on release and the pool dials a fresh one. At most one per pool per 10 s; never mid-transaction; no change in connection count. Fixes the 10-26 director stalls where one connection stalled the sticky lane.
2026-10-26 13:38:58 -04:00
Jason Brashear e3ece052e0 docs(cli): document terminal read --screen and realign terminal help usage (#15893)
The bundled orca-cli skill guide never mentioned `terminal read --screen`,
so agents onboarded from it used the stream read on repainting TUIs and got
stacked fragments. Add a --screen example plus the stream-vs-screen and
--screen/--cursor rules, and realign the root help usage lines for
terminal read and terminal split with their command specs.

Fixes #15856
2026-10-26 10:22:12 -07:00
Nikolas SapalidisandNeil ce4e0579ce fix(shortcuts): cycle floating workspace tabs on Ctrl+Tab when the floating panel is focused (#33223)
When the floating workspace panel had focus, Ctrl+Tab (tab.previousRecent)
and the recent-tab switcher resolved tabs from the main workspace, so the
shortcut either did nothing or switched main-workspace tabs. Route the
previous-recent command and the RecentTabSwitcher to the floating
workspace's group when the panel is focused, and share the recent-tab
lookup via getPreviousRecentTab. Floating simulator tabs are now included
in the visible-tab set used for cycling.

Fixes #33134

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 10:05:45 -07:00
Serhii SavenkoandNeil 8fbee4334f fix(appearance): make match-terminal sidebar text inherit the terminal foreground (#29157)
Match Terminal only redefined --foreground on the sidebar surfaces, but
inherited text color comes from body's already-computed color, so labels
without their own color class (e.g. project names) stayed the app
foreground. Set color directly on the surface as well.

Fixes #29151

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 10:00:15 -07:00
José Antonio Muriano CriadoandNeil d4500b486d fix(pty): feed the runtime once for in-process panes behind a degraded daemon (#33119)
When the daemon's PTY spawn check fails, the DegradedDaemonPtyProvider
routes fresh terminals to the in-process LocalPtyProvider. bindProviderListeners
decided whether to feed the runtime via `instanceof LocalPtyProvider` on the
registered provider, so behind the degraded wrapper every in-process chunk and
exit was ingested twice (once through configure().onData/onExit, once here),
doubling output sequence numbers and exit handling.

Tag each data/exit event with `runtimeFed` when the emitting provider already
reported it through configure(), and gate the listener's runtime feed on that
per-event flag instead of the provider's class.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 09:59:09 -07:00
Aashish MahatoandNeil fd26aef37c fix(terminal): treat macOS '??' tty as no terminal in spawn-file and tmux readers (#23251)
The daemon's spawn-file foreground and child-process readers and the tmux
client attachment reader compared root.tty against Linux's '?' only, so a
macOS root reported as '??' (or '-' on some ps builds) was read as having a
controlling terminal. All three now use the shared hasControllingTty
predicate from src/shared/posix-controlling-terminal.ts.

Fixes #23245

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 09:53:08 -07:00
grboy6770andNeil 6877b55c7d fix(tab-group): resolve tab drag targets from the real cursor position (#27930)
dnd-kit's drag-end delta is scroll-adjusted, so a pointer derived from
activatorEvent + delta drifted by the source tab strip's scroll offset and
dropped tabs into the wrong group or split. The tab drag pointer sensor now
records the actual cursor coordinates on pointerdown/move, and
getDragPointer prefers that recorded position.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 09:52:37 -07:00
YEONGUK LEEandNeil a3ba93c87b fix(i18n): localize PR merge/close confirmations and merge method labels (#28568)
PR close/reopen/merge confirmation titles were built from a fragment
template ("{{value0}} PR #{{value1}}?"), so locales could not reorder the
verb, and merge method labels came from English-only shared constants.

Add whole-sentence title keys per action and merge method plus translated
merge method labels in a renderer copy module, and route every PR surface
(item dialog, PR page, Tasks MergeCell, right-sidebar HostedReviewActions)
through it. Drop the English labels from the shared merge-method
presentation and remove the dead fragment keys from all locales.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 09:52:05 -07:00
Jinjing 512927523e Remove obsolete reference documentation (#34008) 2026-10-26 09:40:10 -07:00
Noah Rijkaard e682ee6285 fix(sidebar): stop the workspace details scroll area from clipping field focus rings (#31816)
The workspace details dialog body is an overflow-y-auto scroll area, which
also clips horizontally, so the fields' 3px focus ring was cut off on the
left and right. Add -mx-1 px-1 to the container so the ring has room
without shifting the fields.

Fixes #31427
2026-10-26 09:39:14 -07:00
Kaynan Sampaio de Camargo 6fdffe8605 docs(orca-cli): correct terminal split --direction semantics (#9038)
The orca-cli skill guide said `--direction horizontal` splits left/right and
`vertical` splits top/bottom, but terminal panes map `vertical` to a
side-by-side split (flexDirection 'row'), matching the "Split terminal right"
menu. Swap the wording and regenerate the bundled guides.

Fixes #9023
2026-10-26 09:33:28 -07:00
den4ikandNeil 0afedab10d fix(lifecycle): keep UI listener failures from vetoing the shutdown checkpoint (#21029)
A throwing ui-changed listener (e.g. webContents.send on a destroyed
secondary window) propagated out of store.updateUI() during
app:stage-before-unload-sync and cancelled the shutdown checkpoint,
leaving the user unable to quit. notifyUIChanged now isolates each
listener, the ui:stateChanged broadcast skips destroyed webContents, and
the staging failure cause is returned to preload so the error toast
names it.

Fixes #20897

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 09:15:45 -07:00
EvgeniiandNeil 79894979d2 fix(i18n): localize Commit & Sync, Rebase, and Create PR hints in the source control dropdown (#14127)
The Commit & Sync tooltip, the Rebase label/tooltip, and the Create PR
blocked hints were bare English literals while the labels beside them went
through translate(). Route all 25 strings through translate() with named
placeholders and add the keys to the English catalog.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 09:04:02 -07:00
1d0d3f5e94 fix(ssh): expand %d, ${NAME} and other tokens in ssh -G IdentityFile paths (#33981)
* fix(ssh): expand %d and other tokens in ssh -G IdentityFile paths

OpenSSH prints IdentityFile values from `ssh -G` with their percent
tokens unexpanded (it expands them only at connect time), so a config
line like `IdentityFile %d/keys/work.pem` reached Orca as a literal
relative path. The key was silently skipped and the connection fell
back to a password prompt even though plain `ssh <alias>` worked.

Expand the tokens OpenSSH supports for IdentityFile that can be derived
locally or from the ssh -G output (%%, %d, %u, %i, %l, %L, %h, %n, %p,
%r). Paths with tokens that need OpenSSH internals (%C, %j, %k) are left
unchanged. A configured, non-default identity file that does not exist
is now named in the auth error instead of being skipped silently.

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

* test(ssh): reproduce #33849 end to end and keep tests off the real ~/.ssh

Adds a Docker e2e: a host from ~/.ssh/config whose IdentityFile uses %r
and %p connects with that key. It fails on v1.4.241 and passes with
the token expansion. Drops a unit assertion that read the real
~/.ssh/id_xmss.

* fix(ssh): expand ${NAME} in ssh -G IdentityFile paths too

ssh -G also prints IdentityFile's ${NAME} environment references
unexpanded, so a key at ${KEYS}/work.pem fell back to a password prompt
in the same way as #33849's %d. Expand the braced form first, and keep
the raw path when the variable is unset, as OpenSSH refuses it.

---------

Co-authored-by: william <wanglv93@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 08:51:31 -07:00
Trevor SmithandNeil 6b831180e3 fix(dashboard): close the agent terminal dialog on Cmd/Ctrl+W (#19758)
The agent terminal preview auto-focuses xterm, which claims Escape and Tab,
and it swallowed the pane-close chord because a preview has no pane. Route
that verdict to an optional requestClose callback so the dialog (modal or
adjacent panel) closes; plain SSH terminals pass none and keep swallowing it.

The workspace keyboard router also treated the preview textarea as terminal
context, so the chord would have closed the active editor/browser tab or hid
an empty floating panel behind the dialog. Mark the preview container and
skip those close handlers for its targets.

Fixes #19757

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 08:50:19 -07:00
Naveen ChatlapalliandNeil 8a42aa87c6 fix(orchestration): keep a settled worker report when startup fails late (#26762)
When a worker reported its outcome (succeeded or failed) before the
worker-start path finished, a late startup error such as a rejected
prompt delivery overwrote that settled outcome with a start failure and
tore down the live worker session. The start-failure path now checks for
a settled report first and returns a ready receipt carrying the reported
workerOutcome without teardown; otherwise it records the failure before
awaiting teardown so no report can slip in between.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 08:50:11 -07:00
arookieofc 232ca39297 fix(terminal): split link-routing dialog context out of the component module (#29740)
link-routing-preference-dialog.tsx exported both the provider and
useLinkRoutingPreferenceDialog, so it was never a Fast Refresh boundary.
When another file in the terminal subtree changed in the same watcher
batch (e.g. a branch switch), createContext ran twice and the terminal
pane read a different context than the provider published, throwing
"must be used inside LinkRoutingPreferenceDialogProvider".

Move the context and hook into a component-free module, matching the
confirmation-dialog-context split from #11980.
2026-10-26 08:44:51 -07:00
Neil d7cf9d2d37 fix(ai-vault): resume a server session whose workspace was deleted; show remote hit previews (#33965)
Since #27214 every SSH session is retagged runtime:<env>, so the #24236
check that drops a deleted cwd (and its prebuilt `cd`) before resuming
only ever ran for the legacy ssh: spelling. Resume on a paired or
SSH-managed server therefore ran `cd '<deleted folder>' &&` and failed.
The check now covers runtime hosts too, probing the folder with the
existing files.browseServerDir RPC; only a definite "missing" answer
drops the cwd, so an older or unreachable host keeps today's behaviour.

Search-hit cards carry no turns and remote hosts cannot reparse a first
prompt, so a server session found through search showed "No first
prompt" and "No conversation preview". Hits now borrow the preview of
their scanned history row.
2026-10-26 08:44:18 -07:00
Neil d47ffbe46d fix(ssh): say why an SSH host failed in the Add project host picker (#33992)
The Add project host picker showed a failed SSH host as "Needs attention
- SSH" with no reason. Its Connect handler also overwrote the failure
main had just published with the host's earlier state, and toasted
Electron's raw IPC error. The picker row now shows the same reason
Settings → SSH Hosts does. The handler keeps main's published failure
and toasts through the shared SSH connect-failure toast.

Fixes #29648
2026-10-26 08:40:58 -07:00
NeilandMatheus Breguêz ee325f8d1b fix(renderer): move side effects out of React state updaters (#33989)
Revoking a paired device, syncing repository settings drafts, and
auto-expanding the first failed check all mutated refs or queues inside
setState updaters, which React may run twice (StrictMode) or late. Move
the impure work into the event handler or effect that queues the update.

Fixes #25529

Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
2026-10-26 08:39:21 -07:00
JunandNeil 5985bbf913 fix(watcher): treat FSEvents rescan-required errors as overflow so folder watches keep running (#31439)
@parcel/watcher reports FSEvents MustScanSubDirs ("... File system must be
re-scanned.") as a non-fatal per-batch error while the native stream keeps
running. Orca forwarded it as watch-error, which retired the watched root and
silently stopped external-edit delivery for the rest of the session.

Route rescan-required errors to a new delivery-queue overflow() so consumers
resync and the subscription stays live. A root deleted in the same batch is
still reported as watch-error. Other errors keep the existing path.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 08:23:11 -07:00
CIS2042andNeil 88fc2eb4fc fix(window): stop "Object has been destroyed" crash from stale renderer-reply IPC after window close (#21581)
Electron's BrowserWindow.webContents getter throws "Object has been destroyed"
once the native window is gone. Several ipcMain reply listeners (terminal
reveal, CLI/mobile terminal create, browser tab create, remote CLI scope) and
the main window focus lifecycle read mainWindow.webContents on every event, so
a late or replacement-window reply after close threw inside ipcMain.emit,
crashing main and starving the new window's listener.

Capture the renderer webContents once at setup and compare event.sender
against that reference instead. Adds a regression test for a pending reveal
on a closed window while a replacement window answers.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 08:22:57 -07:00
MeapriandNeil 2f93f7b555 fix(terminal): keep a pinned reading position anchored through scrollback trimming (#23334)
When the scrollback is full and the user has scrolled up, new output trims
the oldest lines and renumbers every buffer row. The pinned scroll intent
stored an absolute viewportY, so enforcing it later (mouse report, reattach,
visibility resume) jumped forward by the number of trimmed lines.

Pinned intents now carry a single xterm marker on the pinned line. Restore
and enforce use the marker's live line and fall back to the stored
coordinates when the marker is disposed (trimmed away or a replay clear).
A pinned sync after trimming compares against the live anchor and refreshes
the stored coordinates so keyed remounts restore the same content.

Fixes #23333

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 08:17:34 -07:00
Naveen ChatlapalliandNeil 67cdeada9d fix(windows): skip watcher-process reauthorization during removal cleanup (#26765)
Windows runtime file watches run in-process, so closeFileExplorerWatchersForPath
never has a watcher child to close there. Re-resolving the authorized path after
Git already dropped an external sibling worktree's registration threw
'outside allowed directories' and aborted the Windows partial-removal recovery.

Fixes #26764

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 08:17:19 -07:00
NeilandMinidoracat 396e3f1b2f fix(terminal): adopt another client's terminal under its own tab instead of a second one (#33978)
* fix(terminal): adopt another client's terminal under its own tab instead of a second one

A paired client that spawns a terminal in a host's local worktree leaves the host renderer without that tab. On activation the host reports the PTY unowned with the recorded pane, and adoption minted a tab with a random id because the recorded tab was not in this window, so the client showed the PTY in two tabs. Adopt it under the recorded tab id and leaf instead, unless that id was closed, and let PTYs the host names as a pane's owner bind before PTYs that only recorded one.

* fix(terminal): never mint a second tab for a PTY a recorded-tab create already bound

If createTab had to give the recorded tab another id, that tab already holds the PTY, so the fallback create would show it twice.

* test(terminal): pin the clock for the closed recorded-tab case

The wall-clock tombstone tripped the flaky-test ratchet. Also tightens the adoption doc comment and keeps the fixture header first.

---------

Co-authored-by: Minidoracat <11269639+Minidoracat@users.noreply.github.com>
2026-10-26 08:06:41 -07:00
Naveen ChatlapalliandNeil dad5c7ddb4 fix(orchestration): teach workers to acknowledge and drain mail batches (#26768)
Dispatched workers were told to run `orchestration check` but never to ack
the returned deliveryId, so the same batch replayed on every check and newer
coordinator mail stayed hidden. The dispatch preamble, orchestration skill
guide, and worker contract now tell workers to ack each processed batch with
`--ack <delivery_id>` (which also reads the next one) and repeat until count
is 0.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 08:00:46 -07:00
Neil c1d3031bcd test(e2e): wait for the catalog failure past a slow conversion (#33960)
"reconnect restores the managed host name after its conversion catalog
fails" started page.waitForEvent('console') before the reconnect that
converts the host. Its 30 s clock ran through the conversion, so on a
loaded machine or a slow host the test timed out even though the catalog
failure was logged. It failed this way on unmodified main locally. With
the Docker host frozen for 35 s during the reconnect it fails every time
before this change and passes after it. The test now collects console
messages and polls once the host is managed. It also drops a log line
the app no longer prints.
2026-10-26 07:52:20 -07:00
Neil c3bbd6fd67 fix(session): clear an emptied field on a runtime partition this window loaded (#33972)
* fix(session): clear an emptied field on a runtime partition this window loaded

* fix(session): leave hosts with parked contested rows to the shadow

Also replaces the new type assertions with checked types.
2026-10-26 07:50:02 -07:00
625d284e4d fix(terminal): send a composing cursor chord once, not twice (#17624)
On macOS with a Korean IME, pressing Option+Left while a syllable was in
the preedit moved the shell cursor two words. Chromium forwards a
composing keydown for the chord, commits the composition, then replays
the same native key event (same timeStamp). Orca deferred the first
copy until the composition settled and then sent the replay too.

The deferred chord sender now remembers the deferred keydown's code and
timeStamp and absorbs exactly one matching replay. The absorb check runs
before the composing-defer branch, so a replay arriving before xterm
ends the composition session is covered as well. Any other checked
keydown, blur, or teardown forfeits the slot.

Fixes #17616

Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com>
2026-10-26 07:39:48 -07:00
Wooseong Kim 0a92d71874 test(daemon): stop assuming POSIX endpoints and cwds (#18289)
Daemon suites handed Windows production branches POSIX-shaped values, so
they failed on Windows checkouts:

- Preflight client replacement bound `join(dir, 'daemon.sock')`; win32
  listens on the path verbatim and refuses a file path. Use
  getDaemonSocketPath like the sibling daemon suites.
- Cwd-validation fixtures used POSIX cwds, which win32 preflight never
  validates, so cancel/missing-dir cases reached spawn. Give them a native
  `C:\` cwd on win32. The skipped validation also leaked a pending
  mockImplementationOnce gate into the next test, which then timed out.
- ORCA_SHELL_FEATURES is only written on the POSIX launch path; gate the
  history-wrapping expectation on platform.

Refs #18261
2026-10-26 07:24:09 -07:00
Jacob HonoréandNeil 8cfbfa5430 fix(daemon): warn when terminals inherit a zero RLIMIT_RTTIME (#29762)
On Linux, PTYs inherit the daemon's RLIMIT_RTTIME. When the soft or hard
limit is 0 the kernel kills timer-armed jobs (SIGXCPU / SIGKILL, exit 152
or 137) and unprivileged code cannot raise the hard limit. Read
/proc/self/limits at terminal-scope initialization and log a
rttime-limit-zero event with a remedy hint (rtkit, or the launcher /
systemd LimitRTTIME that starts Orca). No-op off Linux or when the limits
file is unreadable.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 07:18:52 -07:00
NeilandZrzzzz a1c6e1273d Continue remote CLI conversations in Chat UI on paired servers (#33954)
* Enable continuing remote CLI conversations in Chat UI

* fix(native-chat): send the host's own pane key; ask older hosts to update

On a paired host the desktop names a pane by its mirrored surface key, but
the host matches cliSource against its own agent-status rows, so every
remote "Continue in Chat UI" create was refused as unreadable. Translate
the key with toHostSessionPaneKey before sending.

A resume launch's join identity now includes its execution host, so a
remote resume never joins an in-flight resume of the same conversation id
on another host.

A verified host that lacks resume-history now shows the pane-header action
disabled, with "Update Orca on this host to continue in Chat UI." in its
tooltip and accessible name, instead of hiding it.

---------

Co-authored-by: Zrzzzz <1160026659@qq.com>
2026-10-26 07:17:41 -07:00
Neil 20f7bb6a69 fix(session-tabs): retire terminal rows the host closed, and offer Close Pane on a closed remote terminal (#33949)
* fix(session-tabs): retire kept terminal rows the host closed, and offer Close Pane on a closed remote terminal

* fix(session-tabs): a live handle outranks an older close record
2026-10-26 07:16:04 -07:00
NeilandClaude 6c815e80c8 fix(runtime): recognize hand-typed native Claude at its startup dialogs (#33826)
* fix(runtime): recognize hand-typed native Claude at its startup dialogs

A shell-typed claude emits no title at the trust dialog, so nothing asked
which process owned the pane, and native Claude's process name is its
version (2.1.310). agentWait now identifies a title-less, unowned pane
from its foreground process, confirming an unfamiliar name with one process
scan whose verdict is kept while that name stays in the foreground.

* fix(runtime): scan only native Claude's version-named binary, only when a dialog is on screen

Review follow-ups: an untitled, unowned pane earns a foreground read only
when its live screen shows a blocked dialog, so plain shells answer without
a round-trip; the process scan runs only for a semver-shaped foreground name
(native Claude's versions/<semver> binary), never on win32, and only an
answered scan is cached.

* fix(runtime): don't persist a titleless pane's scanned identity

A hand-typed native Claude identified for an interactive-wait query was
stored as the pane's foregroundAgent. If the user declined the trust
dialog before Claude set a title, no title transition fired, so the shell
stayed labelled Claude until the next inventory refresh.

The identity now answers only the current query; the per-pty scan cache
(keyed by foreground name) keeps repeat queries cheap. Concurrent queries
share one in-flight identify, and the version-name match is anchored.

* fix(runtime): keep scanned identity out of background refresh; null for disconnected panes

- load() matches main again; only identify() consults the confirm-scan cache
- disconnected/unreadable panes answer null so the tail path still answers; only timeout is unknown
- check pane ownership before projecting the screen
- cache only recognized agents, so a not-an-agent verdict is rescanned

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

* fix(runtime): drop a titleless identity read if the pane rebinds; trim tautological tests

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 07:13:36 -07:00
NeilandClaude b51d904ef0 fix(agent-status): show Claude/Codex panes waiting on the folder-trust dialog (#33804)
* fix(agent-status): show Claude/Codex panes waiting on the folder-trust dialog

Hooks only start after a folder is trusted, so a pane parked on Claude's or
Codex's trust dialog had no sidebar row (or an idle one) even though
agentWait already reported agent-trust-workspace. Main's headless-screen
observer now runs the same blocked-text detector on the screen and projects
a waiting row while the dialog shows, settling it with a session-boundary
done once the dialog leaves. The row is not first-party evidence: it skips
the prompt lifecycle and lastExplicitAgentStatus.

Refs #25854

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

* fix(agent-status): match the live trust dialog's structure and settle on agent exit

Require the dialog's key footer and trust choice so quoted wording in a reply
cannot raise a waiting row, settle the row once a killed agent's pane is back
at a shell, and cover dismissal with a Codex 0.164 recording.

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

* fix(agent-status): settle the trust-dialog row only on positive evidence

ASCII-escape the dialog regexes for the orcad build, settle only after a quiet
settled screen without the dialog or a proven shell foreground (readLaunchedAgentForeground,
which is the only shell-alone proof on Windows), so a resize repaint split across
reads no longer flips the row and re-notifies.

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

* refactor(agent-status): move trust-dialog status projection out of headless hydration

Keeps headless-terminal-hydration.ts under the max-lines lint limit.

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

* test(agent-status): drive the trust-dialog settle window with fake timers

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

* test(agent-status): drop the Codex dismissal capture the serializer fuzz rejects

Its replay trips known serialize I2 diffs; cover Codex dismissal with a composer
repaint over the existing 0.158 capture, and compare only appearance/absence.

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

* refactor(agent-status): track trust-dialog rows per PTY and clear on debounced screen reads

Keys state by ptyId so an emulator swap no longer strands the row, owns the
row by its receipt stamp instead of a toolInput tag, drops tracking as soon as
another writer replaces the row, and clears after two debounced reads without
the dialog instead of 3 s of total quiet.

* fix(runtime): clear the trust-dialog read timer when a screen read throws

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 07:13:29 -07:00
Konstantin StasenkoandNeil 2bcf5b27bd fix(codex): skip the Codex hook under a Claude background job (#24641)
Claude background-job workers, and the `codex exec` runs they spawn,
inherit the dispatching pane's ORCA_* env, so the Codex hook posted
events against a pane the run never lived in. The Codex hook now exits
when CLAUDE_JOB_DIR is set, like the Claude hook already does.

The guard moves into agent-hooks/claude-background-job-guard.ts and is
shared by the Claude hook, Claude statusline, Windows Claude entry and
Codex hook. POSIX exits after stdin capture; Windows exits before
owning stdin so an abandoned stdin cannot hang the drain.

Pane spawns now drop an inherited CLAUDE_JOB_DIR so an Orca launched
from a Claude background job does not silence its panes' hooks.

Fixes #24516

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 07:08:15 -07:00
Neilandoutof-place 88518900e2 fix(i18n): reject duplicate keys in localization catalogs (#33950)
JSON.parse silently keeps the last value of a repeated key, so the
catalog verifier could not see duplicates. Scan en.json and every target
catalog with ts.parseJsonText before parsing and fail with file:line and
the dotted key for each duplicate.

Fixes #27153

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-26 06:52:19 -07:00
Neil 899d2aad96 fix(ssh): say why SSH failed when Connect never reaches the host (#33928)
When the SSH session itself could not open (key rejected, port refused,
host not answering, host key not trusted), Connect on a host Orca had not
set up yet said "Orca couldn't start its server on this host" and offered
a plain SSH terminal that could not work either. Errors from opening the
SSH session are now marked where they are dialed, and a setup that fails
on one ends the connect with SSH's own reason. A held move keeps its
status. The connect-failure toast also drops Electron's IPC prefix.
2026-10-26 06:51:39 -07:00
Tae Hyeong, SonandNeil 8b1f86dfa5 fix(windows): keep spaced batch launcher paths intact when spawning (#13501)
cmd /c strips the first and last quote of a line that starts with a quote
unless exactly one quoted, paren-free executable path is present. A spaced
.cmd launcher plus any quoted argument (or a Program Files (x86) launcher)
was cut at its first space and the spawn silently failed. Prefix the batch
invocation with `@` so the line never starts with a quote, in both the
waiting and detached start /B forms.

Add a real cmd.exe round trip in the Windows CI lane.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 06:46:57 -07:00
Wooseong KimandNeil 5b1e387895 docs: use the full stablyai/orca/orca cask name and warn that bare orca is Plotly (#14777)
Bare `brew upgrade --cask orca` resolves to the unrelated, disabled Plotly
cask in homebrew-cask. Add a warning and a qualified upgrade line to the
README install blocks (all locales) and qualify the upgrade command on the
docs site install page.

Fixes #14591

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 06:41:41 -07:00
zhangxaochenandNeil 67e42c90b9 fix(terminal): return chat tab to terminal when a confirmed shell foreground follows agent exit (#30614)
Agents that leave their OSC title behind on exit (grok, codex) never trip
the title-based exit, so ChatView stayed on top of the returned shell.
onConfirmedShellForeground now notifies onAgentExitedRef, except for
Orca's own hibernation stop, which keeps its chat surface.

Fixes #30613

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 06:36:12 -07:00
Neil a93f73c032 fix(terminal): skip an escape tail an abandoned hidden-output restore would print (#33905)
* fix(terminal): skip an escape tail an abandoned hidden-output restore would print (#33766)

Main drops a hidden pane's renderer delivery after its model ingests the
bytes, so the first chunk sent on reveal can begin inside an escape whose
start was dropped. When the restore is abandoned, the renderer resets its
parser and writes the queued chunks, and xterm printed the tail (';242m',
the rest of a Codex OSC title).

Main tracks each PTY's escape state over every accepted payload and labels
the first delivery after a hidden or pending-cap drop with the escape it
resumes inside (gapEscapeState). Only the abandon path strips that
continuation; a successful restore keeps every byte so the snapshot's
pending escape tail can complete. No label means no change.

* fix(terminal): make the escape-continuation scan's switch exhaustive (#33766)
2026-10-26 06:33:23 -07:00
Daniele SolombrinoandNeil 0ea1ac609c fix(terminal): release replay guards when a pane's xterm is disposed (#31095)
A disposed xterm silently drops its queued write callbacks, so replay
guards engaged on it never saw a parse completion. The stall probe then
certified a false wedge, logged a wedged-release breadcrumb and fired the
undeliverable-write recovery against a pane that was already gone.

Track each pending guard release per terminal and settle them with a
'target-disposed' reason from disposePane, and skip new replays into a
disposed xterm the same way certified-dead pipelines are skipped.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 06:30:47 -07:00
d290035e6e fix(cli): reject empty --terminal/--from handles instead of falling back to defaults (#16745)
An explicit empty --terminal (or orchestration --from) was treated as absent,
so `orca terminal send --terminal ""` targeted the active pane and
orchestration check/inbox/worker-start fell back to the ambient
ORCA_TERMINAL_HANDLE mailbox. Hoist the existing getPresentStringFlag into
flags.ts and use it for these handles so a present-but-empty value fails with
invalid_argument.

Fixes #16694

Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: wusiyuan05 <wusiyuan05@zuoyebang.com>
2026-10-26 06:30:34 -07:00
Neilandzerone0x 4fda57bb11 feat(open-in): open SSH workspaces in Cursor and Zed (#33877)
* feat(open-in): open SSH workspaces in Cursor and Zed

Cursor shares VS Code's Remote-SSH argv and now opens SSH and SSH-reached
server workspaces the same way, in a new window like its local launch.
Zed opens them through its ssh://[user@]host[:port]/path URL, so manual
custom-port hosts work without a local SSH config alias.

Co-authored-by: zerone0x <soberzml2333@gmail.com>

* fix(open-in): keep manual Zed targets on their saved route

Always send the saved port for manual targets so a matching ssh config Port
cannot redirect them, ask for an ssh config alias when a manual host needs a
key, agent or proxy the URL cannot carry, reject option-like hosts, and accept
the zeditor CLI name.

* refactor(open-in): move the remote SSH editor launch into its own module

Keeps external-editor-launch.ts under the max-lines limit after the main merge,
and moves main's new macOS CLI fallback test onto the remote launch API.

---------

Co-authored-by: zerone0x <soberzml2333@gmail.com>
2026-10-26 06:28:29 -07:00
NeilandClaude 0cf40b1687 fix(session): show a toast when Force Reload is vetoed by a failed shutdown checkpoint (#33941)
Browser-initiated beforeunload (Force Reload, reload) had no caller to surface
the checkpoint veto, so the reload silently did nothing. Show a reload-specific
failure toast naming the cause for trusted unload events; synthetic close and
restart dispatchers keep reporting their own verdict. Paired web skips the toast
since trusted unloads there also cover tab close/navigation and the browser's
leave prompt already reports the veto.

Fixes #21017

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 06:25:13 -07:00
Neil 9f02111538 fix(persistence): a paired server's workspaces keep their saved tabs across desktop restarts (#33926)
* fix(persistence): a paired server's workspaces keep their saved tabs across desktop restarts

Main's per-repo terminal topology revision fences window saves so a stale save
cannot undo main's own membership change. The window never sends revisions, so
on a runtime partition, which mirrors a paired server, one removal or main-side
close froze every workspace of that repo: from then on each window save had its
terminal rows rebased onto the prior rows, and every restart reopened those
workspaces on the server's per-device tab pick.

On runtime partitions the fence now lasts only through the race it guards: a
repo main changed is fenced for RUNTIME_PARTITION_TOPOLOGY_FENCE_MS, then the
window's saves win again. Local and SSH partitions keep the permanent fence.

* test(persistence): pin that a window save can drop a tab the server closed after a restart (#21236)

* fix(persistence): fence the retirements the sanitizer makes from legacy tombstones on runtime partitions
2026-10-26 06:11:15 -07:00
Neil 639d52952d feat(ssh): per-host Reconnect on launch toggle (#33935)
* feat(ssh): per-host Reconnect on launch toggle

A host with Reconnect on launch turned off starts each launch as if the user
had disconnected it: main records the session user-disconnect for it and the
managed servers reached through it, so neither the startup restore, pane
mounts nor managed-server calls dial it until the user connects it. The
renderer also skips it in the startup restore. The switch lives in Settings ->
SSH -> Advanced for hosts this desktop dials; undefined keeps today's behaviour.

* fix(ssh): hold opted-out hosts before server status probes start

Server status probes start inside registerCoreHandlers, before the SSH
handlers register, so hold launch opt-outs right before it (once per
process). Relay-era panes that hit a held host now wait for Connect instead
of reporting a failed connect.
2026-10-26 06:01:54 -07:00