When a Slack-started agent asks for approval or asks one pick-one question, the thread gets a card with one button per option. Only the person who asked for the work can answer; anyone else is told so privately. The answer travels through the existing inbox and delivery path, and the card closes once answered or no longer pending. Other question formats (grouped, pick-several, typed answers) still point to Orca; a follow-up adds them. Connector service only; Slack is off unless configured.
setActiveWorktree's no-op guard now compares activeWorkspaceKey with the key
derived from the target worktree, so reselecting the current worktree repairs
a stale key instead of returning early.
Session hydration always derives activeWorkspaceKey from the restored
activeWorktreeId instead of trusting a persisted key that may name another
workspace, which kept the wrong sidebar row highlighted after restart.
Fixes#14474
Co-authored-by: Neil <neil@stably.ai>
An Orca launched from inside a Claude Code session inherits CLAUDECODE,
CLAUDE_CODE_EXECPATH, and CLAUDE_CODE_ENTRYPOINT alongside the child-session
stamps #9961 already strips. Every pane then looks nested to Claude Code and
to agent-aware tools, and the inherited entrypoint overrides Claude's own
detection. Add them to the existing inherited-stamp deletion list so every
local, daemon, and relay spawn drops them while explicit pane values win.
Closes#9155
Co-authored-by: Neil <neil@stably.ai>
* fix(claude-accounts): restart System default sessions on the outgoing login when switching
A Claude account switch only restarted sessions in the outgoing account's
own folder. A session on System default (~/.claude) signed in to that
account's exact login, as older Orca's copied login leaves it, was skipped
silently. Match it by email and organization, read by main at switch time;
never compare managed folders by login. Sessions in the user's own
CLAUDE_CONFIG_DIR are no longer treated as System default, and legacy
accounts match their current launch folder.
The ask dialog groups sessions into Running on X, Not on X and Can't move,
and the Always restart toast names sessions it left and offers Review.
* refactor(claude-accounts): simplify the switch login match, scan and toast styling
Inline the single-use login adapters, carry each pane's foreground result with
its row, keep the header-pin listener local to its effect, move the inline
toast action classes to the Sonner module, and stop the Review dialog
promising a restart for sessions that cannot move.
Each terminal tab and the Floating Workspace own separate PaneManagers, each
with its own activePaneId. The hover gate skipped any pane that was already
its manager's active pane, so a single-pane main terminal never took focus
back from the floating terminal (or vice versa). Refocus an already-active
pane when DOM focus sits in another terminal pane; focus outside panes
(chat, editor, inputs) is still left alone.
Fixes#29912
Co-authored-by: Neil <neil@stably.ai>
Grouping a GitHub Projects view by a NUMBER field sorted group headers as
text (1, 10, 2, 8). Number values now carry their value as the group order
hint and the NUMBER comparator sorts by it, falling back to label. Stale
non-number values use the finite unknown-option sentinel so mismatched
single-select/iteration comparators stay consistent.
Fixes#19395
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Usage caches and their source sidecars hold session ids and project
paths, but their durable temp files were created with the process
default mode, so a replace under umask 022 published them as 0644.
Thread an optional creation mode through writeFileDurable /
writeFileDurableIfCurrent and pass 0o600 from UsageCacheSnapshotWriter
and the usage source sidecar writer. Other durable writers are unchanged.
Fixes#31026
Log-only, Cloud Run director only. Each runtime line gains per-window deltas of the instance's /proc/net/snmp TCP counters (segments in and out, retransmits, errors, resets), so a stall can be checked against packet re-sends. Unreadable or reset windows are omitted.
The connector cloud now assigns each machine connection's revision instead of trusting the desktop's saved number. Acks, events and polls from an older connection get 409 hello_required, and the desktop announces itself again. Also records the cloud's request size limit in the shared contract and adds the current turn to the machine snapshot so a stale turn end cannot clear a newer prompt. Connector service only; not deployed to production.
* Apply Codex Ask permissions at each fresh turn
* fix: admit fresh Codex input with current host permissions
* fix(native-chat): finish cancelled Codex input under its owner
* fix(native-chat): preserve mobile type boundary for input finalization
* test(native-chat): bound input finalization work at scale
* Fix cancellation result fences and exercise host proofs
* Fix input finalization type contracts
* Remove obsolete Portuguese permission description
* Preserve proven Stop outcomes during input finalization
* Preserve input handover proofs with session-ending Stop
* Preserve pending input recovery before lifecycle cancellation
* Assert one recovery card across overlapping close requests
* Preserve unwritten inputs across shared-agent Close preparation
* Narrow cancelled dispatch to its rejected outcome
* Import Codex app-server types from their colocated modules
* Use standard Ask policy for fresh Codex chat input
* Deliver applied Codex permission reports to the host
* Cover applied reports with pending settlement waiters at scale
* Fix settlement waiter timer portability on mobile
* Keep pre-send exit failures with their original input result
Adds the Slack side of the Orca Cloud connector: verified Slack event ingress, owner-only routing, thread starts held in the shared inbox, a post queue for replies and status, and agent replies into the thread. Off unless the connector is configured with Slack secrets; no production deployment.
* 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
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.
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
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>
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>
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>
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>
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>
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>
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
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
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>
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>
* 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>
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>
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>
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.
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.
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
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>
@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>
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>
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>
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>
* 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>
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>
"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.
* 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.
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>
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
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>
* 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>