* fix(agent-resume): record a background agent launch's recipe so resume keeps its flags
* test: narrow the reveal's notifier so the test needs no cast
* refactor(agent-resume): one recipe registration path; skip adopted panes
* test: add the launch-recipe listener to the remaining window mocks
* fix(codex): resume a thread with the permissions it was last given, not Orca's launch flag
Codex restores a resumed thread's saved approval/sandbox settings unless the
launch passes a permission flag. Orca replayed its launch-time recipe
(--dangerously-bypass-approvals-and-sandbox, --approve-for-me, or the Ask
flags) on every resume, so a session switched to "Approve for me" came back
as Full Access after a restart, and that override was saved to the thread.
Fixes#10886
Co-authored-by: mys <4546173+wowpotato@users.noreply.github.com>
* test(mobile): Codex AI Vault resume no longer replays Orca's permission flag
The mobile AI Vault resume builds its command through the shared resume plan,
so it now omits --dangerously-bypass-approvals-and-sandbox like desktop does.
Co-authored-by: mys <4546173+wowpotato@users.noreply.github.com>
---------
Co-authored-by: mys <4546173+wowpotato@users.noreply.github.com>
Moves the push gateway's database layer into a shared cloud/packages/cloud-database package (service name and schema passed in). Push's behaviour, log names, SQLite file and tests are unchanged.
A repo saved as \\wsl.localhost\<distro>\mnt\c\... runs Git in WSL, which
lists its worktrees as /mnt/c/.... The listing mapped those to C:\..., so the
primary worktree got the id <repo>::C:\... instead of the saved
<repo>::\\wsl.localhost\...\mnt\c\.... Its tabs, agents and terminal history
are keyed by the saved id: the renderer dropped them as belonging to no
worktree, and the C:\ row showed up as a hidden discovered worktree.
Map drvfs output to the distro's UNC view when the repo itself is saved
under it. Repos saved as drive paths (Git routed to WSL) and in-distro repos
keep today's drive mapping.
Adds cloud/packages/connector-contract: the shapes the desktop and the cloud connector service exchange (hello, held poll, received/done acks, events with per-hello seq, replies), limits, error codes and the contract version. Nothing calls it yet.
* fix(agent-resume): resume Claude sessions at their own effort level
* fix(agent-resume): keep effort through persistence and /clear; simplify ensure shaping
* fix(runtime): keyboard tab switches tell a paired server which tab this desktop shows
A paired server keeps one tab selection per device and a server workspace
reopens on it. Clicks, Cmd+1..9 and the palette updated it, but the next,
previous, recent and terminal-only shortcuts changed the tab locally only, so
the server kept an older pick and the desktop could reopen on the wrong tab.
* fix(runtime): keyboard switches to agent chats and server browser tabs also reach the server
Browser activations carry the visible local tab so later navigation cancels
their deferred focus, matching terminals.
* fix(runtime): keep keyboard agent-chat switches local in workspaces no server owns
* fix(runtime): scope keyboard agent-chat activation to this client on old and new servers
* fix(runtime): a keyboard switch to an agent chat reaches the server that hosts that chat
* fix(agent-status): keep Codex's hidden title-thread prompt off the sidebar heading
Codex titles a new thread in a hidden ephemeral thread. When managed config pins hooks on,
that thread's SessionStart (source startup) took the pane and its prompt became the row heading.
Drop its prompt as a foreign ephemeral thread and keep the row's prompt across rollout-less starts.
Fixes#30049
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(agent-status): hold a rollout-less Codex start until its prompt shows what it is
The hidden title thread's SessionStart no longer swaps the row's state, session or tool snapshot.
A held start is dropped with the title prompt, or replayed as SessionStart on a new conversation's
first prompt so relayed desktops still let it take the pane. Covers a main Stop arriving first.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(agent-status): also hold Codex's hidden recap thread and clear the old completion stamp on takeover
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(wsl): open, save and rename a UNC drive-mount project's files through its drive path
WSL 2.7 refuses Windows file access to its drive mounts over UNC. #33735 fixed listing a saved
\\wsl.localhost\<distro>\mnt\c\... project, but opening a file from it still failed with EPERM, as
did saving, renaming, creating and copying.
The open/read helpers (editor reads, ranged reads, media previews), the save path (write probe,
disk precondition, its locks), rename, create, copy, the file stat/exists checks, the runtime
provider used by remote clients and the document-folder realpaths now hand the filesystem the
drive path. Authorization is unchanged: it still runs on the caller's UNC spelling against the
UNC roots. Delete already runs inside the distro.
* fix(wsl): check a missing path's ancestors for links through the drive path
Authorizing a path that does not exist yet walks up to the nearest existing folder and refuses a
dangling link on the way; that link check ran lstat on the UNC spelling, which WSL 2.7 refuses for
drive mounts. So New File, New Folder, a first save, an upload and a copy or rename into a new
folder all failed with EPERM (failing closed). The check now lstats the drive path, where Windows
still reports junctions and symlinks.
* fix(codex): let Codex's elevated Windows sandbox read Orca's managed Codex home
Fixes#24306
* fix(codex): run the sandbox read grant off the launch path, once per home
* fix(codex): skip the sandbox read grant when the home already has it
* fix(codex): grant the sandbox only resource folders, retry failures, cover first elevated session
* fix(codex): machine-qualify the sandbox group and verify full propagation
* fix(remote): a desktop ignores its own workspaces echoed back by a server it serves (#33424)
When two desktops pair to each other, each server republishes the tabs it
mirrors from its own servers. Desktop A then received B's mirror of A's own
workspace under the real workspace id and grafted it onto its local copy as
B-hosted tabs, so opening those files asked B (selector_not_found) and closing
them closed B's tabs.
A session-tabs frame from a paired server no longer writes a workspace this
app lists as its own (a stamped local or direct SSH row) unless that server
also lists a copy. Other servers' workspaces stay open to every runtime.
* fix(remote): retire echoes already taken and replay frames a twin's late row releases
An echo fenced out of this app's own workspace now applies as that server's
tombstone, so rows it left before the fence (restored sessions, or frames that
arrived before this app's own row listed) are retired without closing anything.
A held frame replays once the server's own copy of the workspace lists, so a
same-id twin that publishes before its row loads still mirrors. The e2e waits
on a later frame from the same stream instead of a fixed delay.
* fix(remote): serve a desktop's tabs on its servers' files only to its phone, not to other runtimes
Redesign of the #33424 fix at the source. A desktop publishes every editor tab in
its window, including ones on files of its paired servers; its phone uses those
through the desktop's relay. Served to another runtime, such a tab routes the file
to the desktop, and in a pairing cycle it is that runtime's own workspace coming
back as the desktop's tab: file reads fail with selector_not_found and closing it
closes the desktop's real tab.
Publishers now stamp those rows with hostRuntimeEnvironmentId (window, layout-owner
main projection and the windowless projection alike). projectSessionTabsForClient
strips the stamp for every caller and drops the stamped rows for runtime-scope
callers, keeping groups, layout and the active tab consistent. Phones and local
callers see what they saw before. The receiver-side fence is removed.
* refactor(remote): keep the file-host stamp helper outside the old-client boundary; test an all-server snapshot
History lists every managed OpenCode account's sessions since #33658, but
resume still launched with the active account's XDG_DATA_HOME, so OpenCode
looked in the wrong database and reported "Session not found".
Derive the owning account from the row's store path and request it via a
spawn env key; the host validates it against registered accounts and falls
back to the active one when the owner was removed.
Refs #28790, #33658
* fix(program-status): keep a Pi row working while a pi-subagents child outlives the parent's done
OSC 7501 projected the root record's done straight onto the row even when
live child records remained, so a Pi parent showed Done/IDLE while an async
pi-subagents worker kept running. Fold child liveness with the existing
foldMainAgentWithRowChildWork; mainAgent keeps the lead's own verdict so the
row settles to done once the last child ends.
Fixes#33657
* fix(program-status): announce a held turn's done on time and keep hook verdicts authoritative
- Stamp turnCompletedAt on the child-held row and its all-clear so the lead's
done is announced once, when it happens, as hook rows do.
- Hold only a finished (non-boundary) turn, only for working/waiting children;
in-turn rows and failed/idle children keep the root's state.
- A settled hook row is never reopened by a program's child-held working row,
so the 2-minute silence fallback cannot flip done -> working -> done.
* fix(program-status): lapse an unrefreshed child hold to the lead's done
Children report only changes, so a pi-subagents that dies or hangs inside a
live Pi would hold the row working until decay. The lease timer now settles a
child-held row no report refreshed within AGENT_STATUS_STALE_AFTER_MS minus one
renewal interval (20-30 min) to the lead's done, keeping turnCompletedAt so it
is not announced again.
* fix(ai-vault): list Claude sessions from a wrapper or launch-setting CLAUDE_CONFIG_DIR
History, usage and transcript lookup now also scan Claude config folders Orca saw in Claude hook transcript paths (kept across restarts) and the CLAUDE_CONFIG_DIR set in Orca's Claude launch environment.
Fixes#23505
* fix(ai-vault): normalize observed Claude folders and cache missing ones
Adds tests that only Claude hooks record a folder (not same-layout CodeBuddy), non-transcript paths are ignored, and the 32-entry cap holds.
Main yields a chunk's query replies to a receiving remote view at ingestion.
If that view paused while the chunk was still in the 5 ms output batcher,
the pause flushed it into the paused gate and dropped it, so a fish DA1
went unanswered and fish stalled 10 s. Flush the batcher before applying
the pause; the desktop's hidden-pane path already answers queries in
bytes that arrive after it paused.
Refs #32944
* fix(hermes): keep named profiles' orca-status copy and pane passthrough current
A Hermes named profile loads plugins and terminal.client_env_passthrough from
profiles/<name>/, so a profile that carries Orca's managed plugin (e.g. cloned
with `hermes profile create --clone`) never got the pane-identity passthrough
or plugin updates. Install/remove now also update those profiles, locally and
over SSH.
Refs #33591
* fix(hermes): never re-enable orca-status in a profile; isolate profile failures
Only refresh named profiles that keep orca-status enabled and not disabled,
match the local managed check remotely (both plugin files), and skip a profile
or an unlistable profiles dir with a warning instead of failing the install.
* fix(hermes): write a profile's config before removing its plugin
When worker-start had to infer the coordinator terminal, the CLI scoped that
lookup with the command's own --worktree (and --terminal) flags. Those name
where the worker goes, often on another server, so the local runtime rejected
an existing remote selector with selector_not_found before any Task or
Dispatch existed. Infer the sender only from the caller's own directory.
Fixes#33579
* fix(wsl): read a UNC drive-mount project's files through its drive path
WSL 2.7 refuses Windows file access to its drive mounts over UNC: \\wsl.localhost\<distro>\mnt\c\x
answers EPERM, while the distro's own folders still open. A project saved under such a path lost
its file explorer (fs:readDir failed on the authorization realpath) and logged an EPERM warning
for every setup-script import candidate.
The authorization realpath now resolves a UNC drive-mount path through its drive and answers in
the caller's UNC spelling, so allow-list checks are unchanged; readdir and the import-candidate
reads open the same folder by drive path. Distro folders, other UNC shares and non-Windows hosts
are untouched.
* fix(wsl): read a UNC drive-mount repo's orca.yaml through its drive path; pin junction refusals
orca.yaml checks (hasHooksFile, loadHooks, the unknown-key probe) opened the UNC path, which WSL
2.7 refuses for drive mounts, so a saved /mnt/c project's setup hooks silently disappeared. They
now use the same drive mapping.
Also pin that authorization still judges a UNC drive-mount path against the UNC roots: a junction
under the project that resolves to another drive or outside the project is refused.
* test(wsl): run the UNC drive-mount fs:readDir suite in the Windows package lane
Its cases need native Windows path resolution, so they skip on Linux and macOS. Gate the suite
(not each case) on win32 and register the file with the Windows lane, so CI actually runs it.
Managed OpenCode accounts launch with XDG_DATA_HOME=<account>/data, but
history discovery only read the app process's XDG data dir, so sessions
created after selecting an account never reached History or the vault index.
* fix(sidebar): list a workspace's newest linked reviews first in the hover card
* fix(sidebar): order linked items newest-first for every surface that lists them
Setup on Windows Server 2012 R2 and on Windows hosts with neither
System32\tar.exe nor Expand-Archive ended in the generic "Orca couldn't
start its server on this host. Try connecting again.", which no retry
fixes. The runtime probe that already runs before staging now also reads
the Windows build and checks for an extractor, read-only, and refuses
before anything is staged or uploaded. The refusal travels the existing
orcad_unavailable reason plumbing to the host card and the ssh:connect
error, and is rechecked on every connect like a noexec home.
Fixes#33574
Reported-by: HKLHaoBin
* fix(ssh): a migrated host's old session no longer brings closed tabs back on restart (#33539)
After an SSH host moved to a managed server, main hides its retained source
repos but still listed its frozen session partition. The window adopted that
partition at startup, and agent tabs the user had closed on the server came
back on every restart. The partition census now hides that partition exactly
when its repos are hidden; the stored rows stay for downgraded clients.
* test(ssh): pin that an uncommitted move keeps its session listed
* Keep the permission pill inside the Arguments box
* Share the Settings permission menu and commit Arguments on field exit
* Honor changed permission choices and acknowledged host picks in reset notices
* Show acknowledged permission resets with scoped Undo
* Consume removed permission recipes in the Arguments draft
* Keep reset notices separate from the inline permission field
* Show reset choices and Undo after a global permission pick
* Use Textarea variant for composite arguments field
* Fix permission test query typing and sync English runtime catalog
* Keep permission reset Undo beside the toast title
* Add permission reset localization base keys
* Complete host settings bookkeeping transport mock
* Flow arguments beneath the permission chip
* Keep composite argument typography in Textarea variant
* Share native scrolling between permission chip and arguments
* Place all-agents permission menu beside its label
* Preserve permission menu width while settings load
* Keep explicit agent permissions when changing the global default
* Use acknowledged settings for local permission notice actions
* Apply local permission notice actions at the settings owner
* test: give settings runtime mock a portable type
* test: place settings fixtures in the recognized fixture directory
* fix: update populated permission notices without dismissal
* Toast says agents still use their own permission setting
* fix(native-chat): a Claude chat saved as Approve for me keeps it when Orca can't read its model list
A chat's auto mode dropped to Ask whenever the saved model list was missing
or couldn't name the chat's model (another account home, first start in a
folder, an unlisted model id), so a resumed chat launched asking for approval.
Auto now drops to Ask only when the list shows the model without it; Claude
itself starts a model that can't run auto in its default mode.
Tracked in STA-10953.
* fix(native-chat): a model list from a CLI older than auto mode still reads as Ask
A CLI that marks no model with auto support predates the auto value (2.1.71)
and would refuse --permission-mode auto, so its listing is evidence, not a gap.
Tracked in STA-10953.
* docs(chat): correct auto support reporting version
* test(chat): type saved launch option cases
* Honor requested chat permissions across model changes
* Match outgrown child fixture to journal null contract
* fix(native-chat): preserve admitted input and current mail choices
* perf(native-chat): derive wake debt and held sends once per retirement decision
The retirement check derived wake debt (a child-work projection and a scan
for the newest turn) before asking whether open work had already decided
the outcome, and its admitted-input fallback rebuilt the provider's held-send
set once per unanswered submission, O(S x W) per decision.
Open work is now read first and wake debt only where it picks the outcome or
the refusal reason. Current work gains one batch query that reads the held
set and the handover set once, sharing the single holds rule with the
per-send reader. Outcomes and refusal reasons are unchanged.
Adds N/10N operation-count contracts on the real Claude host rig: two
retirement checks per ordinary send, each one pass over history, with a
control that the second sees a sign-out reported between them; no wake debt
mid-turn; one held-set read per refusal in a queued model-change burst.
* Keep active Claude input on its turn choices
* Fix chat admission type imports and cover turn-scan costs
* Preserve root lifecycle delivery under journal pressure
* test: construct Codex mail fixture with its source
* test: expect root retention metadata in Claude turn timing
* test: cover captured Claude full-ID Auto launch
* test(native-chat): explain queued-send test timeout
* test: supply explicit mailbox working policy