Commit Graph
16750 Commits
Author SHA1 Message Date
Jinwoo Hong d4544c831d test(relay): wait for the relay's own close before confirming a resume (#34117)
The served-relay blackbox test closed the phone and data sockets from the client and sent the resume confirm before the relay had processed the close, so on a busy runner the relay correctly answered device-resume-confirmed and the test failed (about 1.8% under load). The test now closes only the phone and waits for the relay to close the data leg with 4408, which happens in the same step that marks the connection inactive. Test-only.
2026-10-26 18:47:27 -04:00
Neil 73ede0fbed fix(terminal): keep a brand-new remote pane's typing for the terminal it creates (#33859)
* fix(terminal): keep a brand-new remote pane's typing for the terminal it creates

* fix(terminal): new-pane typing goes only to a genuinely fresh create, never an adopted or restored terminal

* fix(terminal): decide a new pane looked blank at connect; at bind re-check only what the create can't cause

* test(terminal): replayed history from the real restore path drops a new remote pane's typing

* fix(terminal): type the replayed-history marks by xterm Terminal
2026-10-26 15:46:50 -07:00
BrantandNeil 3f256ad4d5 fix(browser): keep annotate session alive across iframe loads (#24032)
did-start-loading fires for subframe loads too, so a page that reloads an
iframe on each poll invalidated the annotation document every cycle: the
pending card closed, grab mode was cancelled and saved-note markers were
retired. Main-frame did-start-navigation already invalidates for every
document replacement (including same-URL reloads) and same-document
navigation, so drop the did-start-loading handler and move the overlay
viewport reset next to that invalidation.

Fixes #23988

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 15:45:34 -07:00
NeilandClaude a97c7ab7d5 fix(terminal): a WSL bridge pane whose distro went away keeps its tab and cold-restores (#34095)
* fix(terminal): a WSL bridge pane whose distro went away keeps its tab and cold-restores

wsl --terminate (or a shutdown or crash) exits every live bridge pane with an
ordinary code, so Orca closed those tabs as if the shell had exited, and the
next launch opened new sessions instead of restoring the old ones. A proven
exit of a WSL bridge session now checks the shared, coalesced
wsl --list --running (never boots, bounded); if the distro is confirmed gone
it is host loss: code -1, history left unended, tab kept, exactly as after a
daemon crash. A running distro or an unanswered check leaves the exit as is,
so  still closes the tab. Native and SSH sessions are untouched.

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

* fix(terminal): trust only a running-list probe that started after the exit; close a kept tab's history

Review of the WSL bridge distro-loss check:
- A probe already in flight from before the exit can predate the distro's
  boot, so it could call a user's own quick exit host loss. Only a probe that
  started after the exit answers; one fresh probe is chained after an older
  in-flight one and shared by the whole wave.
- The outer bound drops to 3 s: every bridge exit waits on it.
- Closing a kept tab later hit SessionNotFound before removeSession, leaking
  its history; an explicit close now treats that as already stopped.

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

* fix(terminal): only a session this adapter lost to its distro may close as already gone

Swallowing SessionNotFound for any id could remove the history of a session a
legacy daemon (sharing the history dir) still runs. The adapter now records
the sessions it turned into host loss, clears them on respawn or close, and
swallows SessionNotFound on an explicit close only for those.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 15:44:35 -07:00
OrcaWinandOrcaWin b8c596ea88 test: remove 68 low-value cases and 18 suites (#34112)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 15:43:25 -07:00
Kelvin Amoaba d7a8bb9240 fix(mobile): show the diff when tapping a changed file from a session (#34073) 2026-10-26 22:42:11 +00:00
Brennan Benson ffb7561f04 Stop hidden chats re-rendering on every tab change (#34020)
* perf(native-chat): stop hidden chats re-rendering on every tab change

Skill discovery now subscribes to tab and workspace state only while the
slash/skill picker is open, and the per-chat image owner subscription
reads only its own workspace's tabs. Previously every mounted chat
re-rendered and rescanned the tab maps on any tab change anywhere.

* Resolve native chat image context from its selected owner

* Cover selected chat image owners through preview consumers

* Use typed reads in chat subscription performance fixture

* Key chat subscription probes by fixture chat identity

* Type dense chat subscription measurement results

* Name the read-only floating chat resolver view

* Exercise document markdown in selected-owner preview test

* Check unavailable chat image through its preview dialog
2026-10-26 15:41:53 -07:00
Jinwoo Hong d4a5609d30 refactor(connector): provider-neutral connector core with Slack as its first adapter (#34088)
Moves routing, machine choice, held starts, the post queue, prompt cards and owner controls out of the Slack files into a provider-neutral connector core, with Slack as the first adapter behind one adapter type. Conversation records and delivery ids are keyed by source, so Slack and Discord ids cannot collide. Behaviour-neutral for Slack apart from a slack: delivery-id prefix and a 403 (not 404) from the reply route when Slack is off. Staging's connector database is reset after deploy.
2026-10-26 18:41:17 -04:00
moonrailgunandNeil 037cf27429 fix(codex): show live usage on the active account row, including System default (#20842)
The Codex switcher only rendered usage bars on inactive account rows from
the per-account cache, so the active row (and System default, which never
has a managed account id) showed nothing. Render the live Codex usage on
the active row when this desktop owns the accounts; a remote owner's usage
belongs to that host's target and stays off desktop-selected rows.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 15:40:01 -07:00
zhangxaochenandKelvin Amoaba 8291297b0b fix(mobile): recover terminal input lease on attach and preserve picked file names (#32987)
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-26 22:34:31 +00:00
NeilandClaude 8a001a93c4 fix(runtime): a restored host pane resumes its agent from the hook store, never replays the launch (#34054)
* fix(runtime): a restored host pane resumes its agent from the hook store, never replays the launch

When a WSL host's daemon restarted, the host re-created each pane with its
original launch command (a fresh Codex conversation), or a plain shell for an
agent typed into one: orcad has no resume record, because only layout-owner
builds record hook status. A pane with no record now resumes the conversation
its own hook rows name (local rows only, this workspace's), through the same
pane-owned resume path a recorded session takes.

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

* test(runtime): hook-store resume vetoes: other worktree, two sessions, shared or live elsewhere, structured host

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

* fix(runtime): a vetoed hook-store resume launches the tab's agent fresh, as before

A record read from the hook store is no promise to keep: when it is vetoed
(two sessions, shared or live in another pane, no resume command) the tab's
agent now launches fresh as main did, not a plain shell. Its two-session veto
counts only the rows it was read from (local, this workspace), so a relayed
SSH row no longer vetoes a local resume.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 15:31:05 -07:00
OrcaWinandOrcaWin 86a75e99c6 perf(bench): measure startup memory and cold SSH latency (#33912)
* perf(bench): separate historical startup loading evidence

* fix(bench): retry owned root identity before teardown

* fix(bench): format survivor identities explicitly

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 15:29:32 -07:00
Mkjung GithubandNeil 4a8cb6fc71 fix(terminal): keep legacy bash prompt dispatch out of OSC 133 command start after a DEBUG trap change (#29165)
On bash <= 5.0 the PROMPT_COMMAND is a single scalar string. After the
user changed the DEBUG trap at the prompt (`trap - DEBUG`, `trap ':' DEBUG`),
Orca's preexec never saw the status-capture command, so the legacy wrapper
flag stayed unset and the dispatch tail emitted OSC 133;C before the next
prompt was drawn.

Set __orca_in_legacy_prompt_wrapper directly in the PROMPT_COMMAND string,
and re-arm the Orca DEBUG trap at the top level of that string: bash <= 4.3
(including macOS /bin/bash 3.2) restores the caller's DEBUG trap when a
function returns, so the re-arm inside __orca_finish_legacy_prompt_dispatch
was undone. Tests force the legacy dispatch on any bash and also run with
/bin/bash on macOS.

Fixes #29164

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 15:28:41 -07:00
Jinwoo Hong 1a723194c3 chore(native-chat): delete the orphaned duplicate structured chat pane menu (#34086) 2026-10-26 18:28:10 -04:00
Kelvin Amoaba 86f2f24ddc feat(mobile): open PDFs from the file browser in Quick Look or the system viewer (#33771) 2026-10-26 22:26:58 +00:00
Neil b58513a049 test: import mocked-module graphs one at a time after vi.mock (#34103)
Same Vitest registration race as the daemon-init fix: concurrent first imports
can load dependencies before pending vi.mock/vi.doMock calls are registered.
2026-10-26 15:26:32 -07:00
NeilandClaude c2c545f245 fix(wsl-host): no-boot connects stay quiet, and liveness recovery never boots (E9 follow-up) (#34093)
* fix(wsl-host): no-boot connects stay quiet, and liveness recovery never boots (E9 follow-up)

Two lows from the #34050 review:
- A no-boot connect published "Connecting" before its running-list read, and a quiet
  refusal then left the row on "Connecting". It no longer publishes the pending state.
- Liveness recovery reconnects only after confirming the distro runs, but that read
  could go stale before the reconnect spawned anything. Recovery now passes the same
  running check to the connection manager, which re-reads it right before spawning.

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

* fix(wsl-host): a no-boot recovery connect still publishes its own pending status

Only the default "Connecting" is skipped for a no-boot connect; an explicit status
(liveness recovery's "retrying now") is still published.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 15:25:30 -07:00
NeilandClaude 268f3d3af8 fix(wsl-host): a clean watch or holder exit is settled like a failed one (E9) (#34063)
`wsl --shutdown` can end the watch and holder with code 0. Two places only reacted
to a failed exit:
- the settle window that keeps a poll from reconnecting into a stopping distro;
- the liveness run's 500 ms settle and running-list re-read before the verdict.
On a clean exit the run read a possibly stale list that still showed the distro,
and readIdentity then exec'd wsl.exe into it, booting it again. Both now use one
"any watch or holder exit" predicate.

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 15:25:24 -07:00
Neil ad5f787ad0 chore(process-host): drop the WSL hook relay launcher from the direct-import baseline (#34078) 2026-10-26 15:24:14 -07:00
Neil 26b158d7bd fix(browser): delete a removed server's browser folder on the next start, not while loaded (#33280)
* fix(browser): delete a removed server's browser folder on the next start, not while loaded

Removing a server (or an SSH target, or evicting a binding) cleared the partition through
Chromium, which loads its session, then deleted the folder right away. On Windows the loaded
session keeps files open, so the delete failed with EBUSY half-way. The data is still cleared
through Chromium at once, but the folder is now queued and deleted on the next start, before
any session loads; startup orphan collection no longer loads the sessions it deletes.

* fix(browser): keep deferred partition deletes per profile and inside Partitions

The pending-delete list now lives next to the active profile's binding file,
so one profile never deletes a folder another profile bound again. Listed
paths must resolve strictly inside the Partitions folder before a recursive
delete, and bound-folder checks fold case for Windows paths.

* fix(browser): re-check bindings before each deferred partition delete

Read the bindings again for every pending folder so a partition bound while
an earlier delete was awaiting is never removed, and keep folders queued
during the startup pass.
2026-10-26 15:23:02 -07:00
Neil ba85f1a6f3 fix(main): share one window listener across overlapping requests to stop MaxListeners warnings (#33102)
* fix(main): share one window/WebContents listener across overlapping requests

Per-request lifecycle watchers (renderer-gone aborts, tab-close relays,
project-move pause, SSH-access link, Jira summary, workspace-cleanup scans)
each added their own destroyed / render-process-gone / did-navigate /
closed listener to the long-lived main window. They were removed on
settle, but with a dozen remote-runtime subscriptions or tab closes in
flight they stacked on top of the window's permanent listeners and tripped
MaxListenersExceededWarning.

addFanoutListener keeps one native listener per (emitter, event) and fans
out to a callback set, detaching when the last subscriber releases.

* test(fs-watcher): await watcher conditions instead of sleeping

* test(window): one lifecycle event rejects every overlapping close request
2026-10-26 15:22:58 -07:00
Neil 39b390516e fix(terminal): save a woken terminal's first history as a full snapshot (#34060)
* fix(terminal): save a woken terminal's first history as a full snapshot

A wake that reused the Sleep-time cold-restore cache reopened the history
writer without asking for a full checkpoint, so the new process's output was
appended to the pre-wake checkpoint, which lacks the fresh-shell padding the
seed gave the daemon. The next save that replayed checkpoint + log (quit's
final save, or a relaunch's adoption) printed the new shell's prompt on the
restored one's row (`$ $`). Mark a full checkpoint for a new process in that
path, as the uncached cold-restore path already does.

* test(terminal): drive the periodic save through a test subclass instead of a cast
2026-10-26 15:21:50 -07:00
d2f9617615 fix(omp): stop finished subagents holding the pane on working and name child rows (#29263)
Co-authored-by: Kien Le <122910950+kien-ship-it@users.noreply.github.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-26 22:20:16 +00:00
ad2156c358 test: remove 140 low-value cases and 49 suites (#34062)
* test: remove 140 low-value cases and redundant browser probes

* fix: remove unused upstream chat menu import

* test: pin the host-split layout fixture branch

---------

Co-authored-by: Orca Test Audit <test-audit@stably.ai>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 15:16:27 -07:00
Neil 7423c8c6e1 fix(automations): settle a run on the agent's own done when its screen never reads idle (#34096)
A Claude Code that negotiates OSC 7501 drops its title glyph, so after a stream
gap or a runtime restart main holds no rest evidence for the finished pane and
tui-idle never settles. Runs then sat dispatched for 6h. A turn-end done
reported after dispatch that has stood for 30s, with no row of the pane saying
otherwise, now completes the run; a blocked screen still resolves first.

Fixes #34064
2026-10-26 15:15:52 -07:00
Neil 9bfabff0ca fix(runtime-environments): drop a recipe VM's rows and session partition when cleanup forgets its server (#33805) (#34101)
Recipe cleanup removed the saved server without the retirement a Settings
removal runs, so the host's session partition stayed (listings kept it
under omittedHostIds) and the sidebar kept the VM's primary checkout until
the next catalog read. Cleanup now retires the server through the same
routine as a Settings removal, the renderer re-reads the catalog once
cleanup returns, a catalog read that started before a change is followed
by one more, and registry edits made outside Settings (CLI environment rm,
recipe cleanup) also drop the removed host's session partitions.
2026-10-26 15:14:23 -07:00
Neil 7a5df406f5 perf(wsl-host): focus connects without first probing WSL when no bridge exists yet (#33110) 2026-10-26 15:13:14 -07:00
Rongzheng LiuandRongzheng Liu b2270cd184 fix(usage): include GPT-6.1 Sol in Codex cost estimates (#29707)
Price gpt-6.1-sol (and its effort/suffix variants) at its own base and
long-context rates instead of leaving it unpriced.

Co-authored-by: Rongzheng Liu <tianlrz@users.noreply.github.com>
2026-10-26 15:11:00 -07:00
a96171d1ac fix(sidebar): let repository labels use available sidebar width (#28342)
The repo badge in detailed worktree cards capped its name at a fixed 6rem,
truncating long repo names even when the meta row had free width. The badge
now keeps the old 6rem name floor (so the branch label still shrinks first)
and grows into any width the branch leaves free, up to its content width.

Fixes #28341

Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: Ander <ander.aramburu@nextdigital.es>
2026-10-26 15:10:00 -07:00
LukasandNeil aeb73cd4be fix(skills): classify cloud request failures as transport, not filesystem (#20848)
SkillCloudRequestError carries the server's error code in `code`, which
the Node errno branch treated as a filesystem error. Every rejected cloud
request (e.g. a failed publish finalization) was reported as
skill-install-filesystem-failed and never retryable, including a 5xx.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 15:09:42 -07:00
Neil 642353623f test(daemon): import the fresh daemon-init modules one at a time (#34085)
Parallel dynamic imports right after vi.resetModules made the cold first test in
daemon-init-provider-installation order-dependent: it failed on every CI run that
placed the file in unit shard 4.
2026-10-26 15:07:12 -07:00
a93e31a933 perf(renderer): keep modal blur with independent source regions (#33799)
* perf(renderer): drop full-window overlay blurs and the idle usage-chip pulse

A full-window backdrop-filter is re-blurred on every frame while anything
beneath it animates, which held ~370 MB of extra GPU render-pass textures and
swapchain buffers while a dialog, sheet, palette or onboarding was open. The
2px scrim blur is barely visible under the black scrim, so keep the dim only
(5 points darker to keep the background as recessive) and drop the panel blur
that sits under a 96%-opaque background. The status-bar usage chip also pulsed
forever before its first fetch (unfocused windows never poll); show it static
until a fetch is actually running.

* perf(renderer): preserve modal blur with independent source regions

* fix(renderer): preserve modal blur recovery and Space coverage

* fix(ci): remove stale context-menu import after main merge

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 14:40:39 -07:00
NeilandClaude 2e67ba5a64 perf(wsl-host): start booting only the focused WSL host early at launch (E9, replaces #33141) (#33924)
* perf(wsl-host): start booting the distros the last run had open work on as the app launches

The WSL host connect can only start once the store has loaded, about 1.5-2 s into
startup on a slow PC, and its first command then waits for the distro to boot.
The service now remembers which distros had open work, and the next launch starts
booting just those right after taking the single-instance lock.

* perf(wsl-host): wake only the focused WSL host early at launch (replaces #33141's list)

open work on, which conflicts with E9 (a launch boots only the focused host). Each
focus entry now records just that host's distro for the next launch's early boot,
and focusing a workspace off WSL (reported as a null focus entry), turning WSL hosts
off, or a host that can't run clears it.

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

* fix(wsl-host): the early-wake list is authoritative: deleted when off, forgotten on Remove

Review of #33924: the early wake runs before settings load, so it can't read the WSL
hosts setting. Turning WSL hosts off now deletes the list synchronously (emptying it
if the delete fails; a missing or unreadable list wakes nothing), and removing a host
drops it from the list. There is no pendingStop field on host records yet (E11); the
existing registered-host filter covers removed records until then.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 14:35:11 -07:00
Jinwoo Hong b7fb07c379 fix(ci): unblock main: split over-long files and pin scanner test file times (#34072) 2026-10-26 17:14:54 -04:00
OrcaWinandBrennan Benson 82ab53ba61 fix(updater): pin stable fallback before downloading (#34076)
## ELI5

Orca can remember one release's ZIP filename and later follow “latest” into a newer release where that file does not exist. Resolve “latest” once, then keep the manifest and download on that concrete release.

## What Changed

- Replace the default-channel moving-feed fallback with a validated stable tag resolved from GitHub's `/releases/latest` redirect.
- Reuse the existing Electron `net.request` HEAD handling and platform manifest/asset readiness probes. `net.fetch` cancels manual redirects in real Electron, so it is not used for redirect discovery.
- Return a retryable check failure when a ready concrete fallback cannot be resolved, and reject fallback results belonging to an expired check.
- Update existing feed expectations and installer fixtures; cover stable fallback, Atom outages, unavailable fallback, late completions, redirect validation, and platform manifest selection.

## Why

The normal path already pins a tag, but Atom outages and no-newer results still installed a `/releases/latest/download` provider. That provider retains relative filenames while GitHub's redirect can move between checking and downloading. Correct release manifests alone cannot prevent the mismatch.

Credit to @brennanb2025 for the original tag-pinning fix in #1797, and @nwparker for the attempt-ownership guard in #23160, which this change extends across the fallback lookup. Also reviewed @sechan-netizen's #30952 and its review thread: its release-manifest validation is a complementary safeguard and remains separate because this race reproduces with correct manifests. No commits from that PR are copied here.

This PR adopts @brennanb2025's audited #34075 lint fix (splitting three files that already exceeded main's line limits), with Brennan retained as a co-author. Independent byte-level audits preserve the moved runtime bodies and test groups; the follow-up replaces five test-only assertions with typed calls and emits identical JavaScript. The standalone older PR remains unmerged after repeated daemon-test CI/order sensitivity; the combined tree here passed all CI, including that exact daemon test file (16 tests) in run 40398604134, job 121839803430.

## Linked Issue

Fixes #34034

Related reports: #15921 and #22621. The controlled race matches their URL signature and retry behavior; the reporter's original feed selection cannot be established without its logs.

## Visual Proof

N/A — updater feed selection only; no presentation change. Verified the HTTP behavior using the production fallback resolver and electron-updater 6.8.10 with unmodified v1.4.240/v1.4.241 manifests and a controlled local release server:

| Scenario | Result |
| --- | --- |
| Old moving provider: read 240 manifest, advance latest to 241, download | `v1.4.241/Orca-1.4.240-arm64-mac.zip`: 404 |
| Retry the old download without a new check | Same 404 |
| Fresh check | Correct 241 ZIP: 200 |
| Fixed fallback: resolve 240 tag, advance latest to 241, download | Correct 240 ZIP under tag 240: 200 |

No installer was executed and no app window was opened.

## Testing

- [x] I manually tested these changes locally
- [x] Automated tests added/updated

`ORCA_BACKGROUND_LAUNCH=1 pnpm check:changed --maxWorkers=2`: all 26 checks pass on the combined branch, including formatting, lint, typechecks, affected tests, and ratchets. The earlier updater-only run also passed all 20 selected checks.

The controller regression run against the original implementation produces five failures with passing controls. The fixed implementation passes. Resolver tests exercise macOS arm64, Windows x64, Linux x64/arm64 manifest selection, invalid redirects, missing assets, and recovery after network failure; these platform variants use mocked transport.

A separate background Electron 43.8.1 smoke on macOS arm64 uses the production resolver and real Electron networking against GitHub, resolving the ready `v1.4.241` tag. The controlled before/after reproduction also exercises the production resolver and actual GenericProvider. Neither proof exercises native installation.

All non-skipped GitHub CI checks pass for combined head `c04a6ca95604e064fb4f91adb1a57ea3dcf9adf0`: all five full unit shards, relay integration, Linux/Windows package checks, macOS updater regression tests, static analysis/typechecks, and the required aggregate check. Final independent review recommends merging that exact head as low risk with no code blockers.

## AI Disclosure

## Review

Independent sub-agent review found no actionable issues and rated the updater change low risk; 57 relevant tests passed independently. The prerequisite received two independent refactor audits, with identical moved runtime/test bodies and a merge-preservation gate reporting zero unexplained deletions and zero unrelated files. The five typed mock changes produce identical JavaScript. Also self-reviewed the feed-selection paths, timeout ownership, transport cleanup, and release-channel filtering. The added lookup runs only on the existing fallback path, uses HEAD for redirect discovery, retains five-second request deadlines, and reuses manifest/asset probes. No new polling, subprocess, persistent cache, or per-workspace work is introduced. Native Windows/Linux networking and installer execution were not exercised locally.

Review disposition for [the DMG-only manifest comment](https://github.com/stablyai/orca/pull/34076#discussion_r4382275117): an independent executable comparison of the original and fixed implementations returned the same `ready` Atom result for a DMG-only manifest; the old fallback already handed that manifest directly to MacUpdater, which cannot select its required ZIP. This is an existing release-integrity limitation, not introduced or worsened by tag pinning. It remains outside this race fix; a complete integrity change must validate the native files list and architecture selection rather than merely finding any ZIP-like name.

## Agent skill upstream boundary

- [x] Not applicable; no upstream skill source or fixtures copied.

## Notes

Desktop updater implementation is shared with headless serve. No IPC/RPC contract, remote version requirement, mobile client code, filesystem path, or workspace-kind assumption changes. Existing RC/perf selection remains in place. If fallback discovery also fails, checks use the existing retry/error flow instead of launching a moving feed.

## Checklist

- [x] This PR is focused on consistent release selection
- [x] Problem, behavior, and mechanism explained
- [x] Visual proof N/A with network verification recorded
- [x] Self-reviewed for correctness, security, and performance
- [x] Cross-platform, remote, mobile, and folder-workspace impact considered
- [x] Required changed-code checks pass


Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-26 14:09:01 -07:00
Brennan Benson ffc2b3fba1 fix(orchestration): preserve task reset lineage per Run (#28823)
* fix(orchestration): preserve task reset lineage per Run

STA-10382

* fix(orchestration): record removed Tasks, Dispatches and workers per entity

Replace the per-Run capped JSON snapshot with one row per removed entity in
removed_orchestration_work, written by AFTER DELETE triggers on tasks,
dispatch_contexts, worker_dispatches, worker_terminal_resources,
remote_dispatch_attachments and federated_dispatches. The triggers are
rebuilt on every open after migrate and dropped at migrate start; a
recorded_since coverage marker moves forward whenever any trigger was
missing, so a Run created before recording reads partial, never
complete-and-empty.

reset --tasks keeps its delete list and order; its reply gains optional
removed counts computed after commit (a failed summary only drops the
field). run-show gains an optional constant-size removedWork summary and
--removed/--cursor paging. reset --all clears the record; deleting a Run
deletes its rows.

Removes the snapshot modules, the run_reset_lineage table, the in-transaction
receipt completion and alwaysRequestId from the first version of this PR.

* chore: drop accidental pnpm-lock.yaml churn

* refactor(orchestration): decode removed work entries through unknown before the checked cast

* fix(orchestration): count settled workers with open terminals and name affected Runs

- A worker may still be running when its state was possibly live or its
  Orca-owned terminal was never released; the reset reply, run-show line and
  listing share one derivation from the removed records.
- The reset reply names the affected Runs (optional runIds); the CLI prints
  the exact run-show command for one Run and the list for several.
- The watermark read is no longer swallowed inside the reset transaction.
- run-show's removed-work read is guarded; a failure omits the field.
- Coverage compares created_at strictly after recorded_since.
- --removed lists a federated worker once, shows a user-taken-over terminal
  as such, and says when a cursor is past the end.

* fix(orchestration): count removed workers by held process minus durable exit proof

- A removed worker may still be running when Orca held its process (live
  state, federated dispatch pending or dispatched, or an Orca-owned terminal)
  and no durable exit proof exists (stopped, released, released terminal, or
  a certified termination reason on its Dispatch).
- The exit proof is one DURABLE_EXIT_PROOF constant shared by the fleet
  liveness projection (no behavior change) and the removed-work reader.
- Dispatch records keep terminationReason.
- Coverage is complete when a Run was created at or after recorded_since; a
  moved marker is stamped one second past the newest existing non-legacy Run,
  and the capture installs after the stub home Run backfill.

* docs(orchestration): correct the terminationReason and coverage marker comments

* fix(orchestration): decode removed work entries through a checked schema

The stored record is parsed once with a discriminated zod schema per kind,
so the listed entry keeps its precise type without an assertion. The same
lineage field table drives the capture triggers' key set and integer casts.

* fix(orchestration): exhaustive removed-work listing switch; keep valid ids in id lists

List worker and remote worker entries with explicit cases so the switch is
exhaustive over the entry kinds. An id list drops non-string elements and
keeps the rest, as before the schema decoder.

* test(orchestration): build removed-work CLI fixtures without type assertions

Use a real RuntimeClient with a spied call and decode listing fixtures through
the entry schema, so the tests carry checked types instead of casts.

* fix(orchestration): name only the removed kinds in run-show and word the no-record message truthfully

The run-show line lists the kinds a Run actually lost, terminals included,
and the --removed message for a missing record no longer claims the host
keeps none, since a new host omits it when its read fails.

* fix(wsl-move): classify the removed-work tables with the other orchestration tables

removed_orchestration_work and its coverage marker live in the orchestration
database and go with its Runs, so the WSL mover rewrites them in place like
every other orchestration table.

* fix(orchestration): keep the removed-work hint when a reset removes only terminal records
2026-10-26 14:05:33 -07:00
c2ceb5204f fix(windows): stop recursive deletes from retry-storming when a file is held open (#33722)
* fix(windows): stop recursive deletes from retry-storming when a file is held open

Node's async recursive rm retries every nested entry separately and orphans
sibling walkers when it rejects, so deleting a workspace holding a live
browser profile multiplied filesystem work per directory level until the
main process hung. Delete Windows host trees with a walker that retries
whole passes from one shared budget and leaves nothing running on failure.

Also bound and log detached worktree removal, and fail a file transaction
whose proper-lockfile lock is compromised instead of throwing from its timer.

* fix(windows): retry a locked delete as whole passes instead of a custom walker

Replace the hand-rolled tree walker with Node's own recursive rm and no
per-entry retries. Async rm gives each nested entry its own retry counter and
never stops siblings, which is what multiplied the work; with retries off each
pass is one bounded walk, and a transient Windows lock repeats the whole pass
from the existing 250/500/1000/2000 ms budget, checking the job's signal
between passes.

A failed delete now names the file another program holds open instead of
Node's EBUSY/EPERM text. Drop the 30-minute background deadline. The lost-lock
error no longer embeds the library's message and says the write may or may not
have been saved.

* test: cover bounded deletion failure and recovery contracts

* test: prune unchanged cleanup coverage

* fix(worktrees): give truthful failed-delete cleanup advice

* test: document fake-clock retry adapter

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-26 13:50:11 -07:00
Brennan Benson 5709037f4c Continue a chat after the terminal agent exits (#33759)
* fix(native-chat): a chat sends again once the terminal's agent exits on macOS

The terminal-writer check required the pane's root process to be a shell,
but macOS panes spawn under login(1), which stays as the shell's parent,
so the check refused every send until the terminal closed. Census the
shell login started instead.

* Reconcile current terminal writer evidence before continuation

* Share fresh foreground confirmation and prove hosted login census

* Restore shell process identity import in foreground tracker

* Correct process fixture identity and polling callback contracts

* Align decisive Windows inspection fixture expectations

* Complete foreground inspection Session fixture
2026-10-26 13:47:20 -07:00
Naveen ChatlapalliandNeil 1df8501246 fix(claude): keep a user-set async flag on Orca-managed hooks (#26736)
applyManagedHooks rebuilt each managed Claude hook from scratch, so an
explicit "async" a user added to an Orca hook in settings.json was wiped
on every install. Carry the boolean over from the managed hook being
replaced for the same event; fresh installs stay synchronous and
user-owned hooks never donate their value.

Fixes #26718

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 13:34:39 -07:00
OrcaWinandm4air d58ab9762c perf(memory): read macOS footprints with a bundled proc_pid_rusage helper instead of top (#34053)
top costs ~263 ms of CPU per sample, so the memory panel only refreshed
footprints every 10 s. The new orca-process-footprint helper reads
phys_footprint for every same-user process in ~3 ms, so footprints now
refresh on the panel's 2 s poll. top stays as the fallback when the helper
is missing or fails.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 13:32:55 -07:00
Neilandoutof-place 568131056d fix(i18n): translate crash report, notification settings and tour copy (#34066)
Route the remaining hardcoded English in the crash report dialog, the
macOS/Windows notification failure hint, the feature tour reopen hint and
the CLI install fallback through translate(), with keys in all locales.

Fixes #27074

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-26 13:27:48 -07:00
NeilandClaude e63b8f4c7e fix(wsl-host): a runtime-call reconnect never boots a distro that stopped meanwhile (E9 follow-up) (#34050)
* fix(wsl-host): a runtime-call reconnect never boots a distro that stopped meanwhile (E9)

ensureForRuntimeCall reconnects only to a distro confirmed running, but the distro
could stop between that read and the reconnect, which would then boot it. A runtime
call now asks for a no-boot connect: the connector supplies a running-list check that
the connection manager runs right before anything spawns in the distro, refusing
with WslDistroNotRunningError (and starting nothing) when the distro isn't confirmed
running. The generation is read before that await, so a close during it still
supersedes the connect.

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

* test(wsl-host): import the no-boot error alongside the other connection errors

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

* fix(wsl-host): no-boot connects don't swallow a focus boot, report no failure, re-verify (E9 review)

Review of #34050:
- A connect that may boot (focus, Connect) joined an in-flight no-boot connect and so
  inherited its refusal. It now waits for that one and runs its own.
- A no-boot refusal published 'failed'. It now publishes nothing from the manager;
  the supervisor, whose connect had already disarmed the entry, re-verifies instead of
  arming the incumbent (which would dial into the distro), so liveness gives the
  verdict and parks a stopped distro.
- The generation is checked right after the running-list read, so a close during it
  supersedes the connect before anything deploys.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 13:27:33 -07:00
Kelvin Amoaba cf6c70bfce fix(mobile): keep chat-agent create when the capability check spans a lan-to-relay switch (#33697) 2026-10-26 20:25:58 +00:00
Kelvin Amoaba b590977919 fix(notifications): workspace mark as read clears the chat alert on the phone (#33713) 2026-10-26 20:21:37 +00:00
Neil f8a0b0f60c refactor(store): colocate agent-status action composition (#34045) 2026-10-26 13:20:11 -07:00
Neil 9185d1021e fix(runtime): share one lazy load of the session-tabs apply modules across refreshes (#33939)
Concurrent refreshes each re-imported the same four modules. Under vitest,
overlapping imports of a vi.mock'd module share one importer callstack and
fall through to the real module, so the second and third of three rapid
browser creates loaded and transformed the real session-tabs graph inside the
test (about 20-28s) instead of using the mocks.
2026-10-26 13:18:14 -07:00
Jinwoo Hong f0cc235427 fix(orchestration): let a sleeping chat's background commands send as it (#34049)
* fix(orchestration): let a sleeping chat's background commands send as it

* fix(orchestration): keep unreconciled sleeping sessions and ask refused

* test(orchestration): cover ask refusal for a sleeping session
2026-10-26 16:18:03 -04:00
Neil b7ad8be42e refactor(agent-hooks): launch the WSL hook relay through the process host (#34051)
Build the wsl.exe argv with buildWslExecArgs and start it with spawnProcess
from @orca/process-host instead of a hand-built node:child_process spawn.
2026-10-26 13:17:06 -07:00
Brennan Benson 9ae33a96f9 fix(native-chat): keep damaged chats readable without granting agent actions (#31931)
* fix(native-chat): validate saved next-fence floors before use

* WIP: separate saved conversation observations from runtime proof

* Consolidate duplicate imports for WIP compiler checkpoint

* Preserve saved conversation observations with strict runtime authority

* Consolidate session admission and catalog imports

* fix: align conversation observation contracts and fixtures

* test: update conversation observation and writer fixtures

* test: use checked host fixtures for structured workers

* fix(native-chat): bound conversation projection work per request

* test(native-chat): consolidate scale fixture imports

* test(native-chat): use checked scale fixture types

* test(native-chat): bound unreadable inventory traversal

* Test native CLI admission and durable reference reads

* test: bound cold conversation name subscription work

* test: distinguish native receipt probes from terminal identity

* test: retain exact mutation refusal recovery identity

* fix: explain agent conversation preparation refusals

* test: adapt remaining conversation readers and document CLI timeout

* fix: register preparation refusal English message

* test: align conversation fixtures with checked read APIs

* test(native-chat): use checked conversation in Codex fixture
2026-10-26 13:16:41 -07:00
Kelvin Amoaba d6567867e5 fix(mobile): ask before closing other tabs, sharing desktop's confirm (#33704) 2026-10-26 20:15:24 +00:00