Commit Graph
13762 Commits
Author SHA1 Message Date
OrcaWinandOrcaWin 4d8071abb4 perf(markdown): coalesce draft version hashing with publication (#35107)
* perf(markdown): coalesce draft version hashing with publication

* test(markdown): assert draft projection contents and drop test-local baseline

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 08:12:18 -07:00
OrcaWinandOrcaWin 631d84d0af fix(browser): avoid loading sessions during cold partition cleanup (#35045)
* fix(browser): avoid loading sessions during cold partition cleanup

* test(browser): cover cold orphan cleanup with one representative case

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 08:11:30 -07:00
OrcaWinandOrcaWin 7b2996dc84 perf(github): look up refresh renderer owners by ID (#35015)
* Use targeted owner lookups for PR refresh visibility

* test(github): update document lifetime native lookup mock

* test(github): collapse PR refresh owner lookup matrix into one guard

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 08:08:17 -07:00
Neil e9515b576b chore(wsl): log what a Sleep's folder read saw for each terminal (#35150)
* chore(wsl): log what a Sleep's folder read saw for each pane

* test(wsl): a bridge pane keeps its Sleep folder across reloads and relaunches
2026-10-28 08:07:17 -07:00
OrcaWinandOrcaWin 073de96581 fix(browser): retire queued extension download starts (#35047)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 08:05:45 -07:00
OrcaWinandOrcaWin 821ff9a9b7 fix: retire extension frame listeners on document replacement (#34942)
* fix: retire extension frame listeners with their document

* fix: snapshot extension owner before native destruction

* refactor(extensions): keep listener registry within its line budget

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 08:02:46 -07:00
Vyacheslav ScherbininandNeil b654c3454a fix(persistence): stop rewriting migrated Compact profiles on every load (#34736)
The legacy Compact card-property migration returned the Compact preset even
when the stored list already was a current Compact preset, so every clean
reload of a Compact profile scheduled a full profile write. Treat both the
raw ['status'] and the normalized ['status', 'unread'] form (persisted by any
UI write) as already migrated.

Fixes #34828

Co-authored-by: Neil <neil@stably.ai>
2026-10-28 08:00:38 -07:00
Neil 808aaee3f6 fix(wsl): hide the sidebar setup-script card while the repo's distro is stopped (#35163)
A background hooks:check refused for a stopped WSL distro now says so (unavailable:
'wsl-distro-stopped'). The setup-script prompt maps it to a distro-stopped state: the card hides
instead of showing 'Couldn't verify…' with a Retry that cannot succeed, and focus re-inspects, so
the card returns once the distro runs. An unverifiable distro stays a retryable error.
2026-10-28 07:59:54 -07:00
OrcaWinandOrcaWin 737f397413 fix(terminal): retire reveal requests with their renderer (#35030)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 07:58:20 -07:00
OrcaWinandOrcaWin 32a62c8e1d Scope SSH partition release waits to their target (#35024)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 07:57:30 -07:00
OrcaWinandOrcaWin 6981f34e46 fix: release extension install prompts on renderer reload (#34931)
* fix: cancel extension prompts on renderer navigation

* test(extensions): break circular prompt fixture inference

* test(extensions): drop vacuous same-document prompt navigation test

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 07:56:23 -07:00
Neil 4ee621e89f fix(wsl): never boot a terminated distro off a list taken while it was still stopping (#35143)
* fix(wsl): never boot a terminated distro off a list taken while it was still stopping

WSL keeps listing a distro for a moment while it stops. A bridge pane's exit now marks its distro
as possibly stopped, its host-loss verdict and boot-id reread only count a running list started
after that settles, and deferred background work (file watcher and hook relay restarts, history
cleanup, CLI repair) is drained only by a settled list. Before, a bridge exit's own list could
read 'running' mid-stop and lead to a boot-id exec, and any confirmed list probed mid-stop
drained deferred restarts that spawn wsl.exe, booting the distro the user had just terminated.

* fix(wsl): gate the hook-relay restart and setup-script inspection on a settled running read

- A deferred hook-relay restart re-reads a settled running list right before spawning the relay
  (wsl.exe), and waits again if the distro stopped; a drained deferral is only a hint.
- Setup-script import-candidate inspection (sidebar prompt, runtime RPC) opens nothing under
  \\\\wsl.localhost while the distro is stopped or unverifiable: those UNC opens booted it about 2 s
  after each terminate on the awin verify.

* fix(wsl): close a pane's clean exit at once, and settle the guest-process fast path

- A bridge pane's code-0 exit is the user's own (a terminate gives -1): it now closes at once,
  with no stop mark, settle wait or running-list read. Non-zero exits keep the E9 discipline.
- readWslGuestPaneProcesses' fast path for a live pane (Sleep, quit) trusts the cached running
  list only when it was probed after any stop of the distro settled.
- When a mid-stop list skipped deferred work, one unref'd probe just past the settle drains it,
  instead of waiting on an unrelated probe.

* fix(wsl): mark a clean bridge exit as a possible stop, and fix the exit check test's probe timing

A code-0 bridge exit still closes at once, but now also marks its distro as possibly stopped, so
an in-guest poweroff or wsl --shutdown that exits 0 cannot leave background reads trusting an old
running list. The coalesced-probe test waits for the probe, which now starts after the settle
anchor, before answering it.
2026-10-28 07:56:04 -07:00
OrcaWinandOrcaWin 24b738aba2 fix(plugins): preserve successor panels after stale loads (#35021)
* fix: preserve successor plugin panels after renderer loss

* test(plugins): drop redundant panel lifetime control test

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 07:52:25 -07:00
OrcaWinandOrcaWin bafe4d5c05 perf(electron): target persisted UI broadcasts to main renderer (#34915)
* perf(electron): target persisted UI broadcasts to main renderer

* test(ui): use a supported top-level view in broadcast regression

* test(ui): collapse UI broadcast routing tests into one wiring check

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 07:46:47 -07:00
Neil c58591e56d fix(wsl): refuse render-driven hook checks on a stopped distro instead of booting it (#35155)
hooks:check takes an optional background flag. The sidebar setup-script prompt and the setup
guide's progress probe, which run on render, pass it: on a stopped or unverifiable WSL distro
the check answers status 'error' without opening orca.yaml over \\\\wsl.localhost, which would boot
the distro. Launch preflight and settings, user acts that start the distro anyway, are unchanged.
2026-10-28 07:33:15 -07:00
Henry SuandNeil fce8b13d7f fix(orchestration): reject invalid legacy takeover before attestation (#34284)
run-use --takeover-legacy on an ordinary (non-legacy, non-adopted) Run
hit the takeover authority gate first and told the caller to repair
terminal authentication, even though the flag can never apply there.
Only require takeover authority when the target is legacy, missing, or
the adopted Run, so ordinary Runs reach bindRun, which keeps the caller
and worker fences and rejects the flag before any binding changes.

Fixes #30779

Co-authored-by: Neil <neil@stably.ai>
2026-10-28 07:18:43 -07:00
Neil 77048d55d5 fix(wsl): a bridge pane keeps its folder when its distro stops while Orca is quit (#35141)
* fix(wsl): keep a bridge pane's shell folder when its distro stops while Orca is quit

* refactor(wsl): quit folder budget as an instance field
2026-10-28 07:15:37 -07:00
NeilandClaude 2a3fc8372b perf(terminal): a clean WSL bridge exit skips the boot-id read (#35138)
On awin a wsl --terminate exited each bridge pane with -1, while exit and exit 0 gave 0, so a
terminate never yields 0. A clean exit keeps today's verdict without the extra wsl.exe spawn.

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 07:10:03 -07:00
BingZ f5ee5b4984 fix(emulator): attach the exactly named iOS simulator before partial matches (#34884)
resolveSimulatorUdid matched the first device whose name contained the
requested name, so asking for "iPhone 17" could attach an earlier
"iPhone 17e". Prefer a case-insensitive exact name match first, then fall
back to the existing substring/UDID match.
2026-10-28 07:07:56 -07:00
OrcaWinandm4air a6fdeda541 perf(terminal): release hidden WebGL canvases' drawing buffers (#34309)
* perf(terminal): release hidden WebGL canvases' drawing buffers

Chromium keeps a display:none WebGL canvas's drawing buffers alive (on macOS
a back buffer plus up to four pooled full-size surfaces). Hidden terminal
tabs and retained worktrees therefore held ~80 MB of GPU memory each until
they were parked. Collapse the canvas backing store while it has no layout
box and keep the context; xterm's device-pixel observer restores the size
and redraws synchronously on reveal.

7 terminal tabs, 1920x1050@2x: GPU process 670-760 MB -> 350-408 MB.

* perf(terminal): free hidden canvases only after 30s and never for suspended worktrees

Reallocating the backing on reveal cost about one frame. Delaying the release keeps rapid
switching allocation-free, and worktree-suspended panes keep their backing so worktree
switches match main. A MutationObserver re-checks a canvas that xterm resizes while hidden.

* fix(terminal): restore released WebGL canvases before the reveal frame paints

- Reveal restore reallocates at the current DPR and draws past xterm's paused
  renderer inside the ResizeObserver callback, so the first painted frame has
  content; also covers engines without devicePixelContentBoxSize.
- DPR repair reports released canvases as 'released' (current) instead of
  'deferred', so window-resize recovery stops retrying them.
- Veto release for panes of a hidden worktree surface (marked from
  isWorktreeActive) instead of webglAttachmentDeferred, which a hidden
  prewarm clears.
- Schedule release for canvases attached or regrown while already boxless;
  a zero-size element gets no initial ResizeObserver entry.
- Clear the timer through the canvas's own window.

* test(terminal): guard hidden WebGL canvas release and reveal restore

* perf(terminal): restore a released WebGL canvas at its exact device size without a full resize

Set the backing to the reveal entry's device-pixel size (xterm's own fallback
size where that box is unavailable) and draw once, instead of handleResize:
xterm's device-pixel observer then finds nothing to resize, which removes a
second reallocation and redraw from the reveal. A DPR change while hidden
still takes the full resize path.

* fix(terminal): paint a revealed released canvas through a held synchronized-output frame

A released canvas has no last coherent frame to keep, so when a TUI holds DEC
2026 at reveal, the buffered refresh left it blank for up to xterm's 1s
watchdog. Use forceFullViewportPresent, which draws the current buffer once
directly; the TUI's sync end still presents its finished frame normally.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-28 06:59:27 -07:00
Samuel VilaandNeil 3fd928373c fix(source-control): flag failed git status reads instead of showing a clean workspace (#28079)
When git status failed (e.g. a corrupted index), the read returned an empty
result and Source Control said the workspace was clean. getStatus now carries
Git's error as an optional readError; the store keeps the last known entries
and conflicts while it is set, and the panel shows a status-read banner with
Git's message and Retry instead of the clean empty state. The Retry logic is
shared with the too-many-changes banner, and the per-worktree error is cleaned
up on teardown and migrated on worktree rename.

Fixes #28033

Co-authored-by: Neil <neil@stably.ai>
2026-10-28 06:56:38 -07:00
NeilandClaude 5e1c26c0a8 fix(terminal): a seen distro stop drops its cached boot id, and the relaunch test waits on the reap (#35133)
Follow-up to #35050 review: a pane spawned after a running list saw its distro stop, but before
any bridge exit reached the adapter, could take the old boot's id. The identity now drops the
distro's cache on a stop observation, listening only while bridge panes live. The relaunch
suite waits on the daemon reaping the session rather than assuming it is synchronous.

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 06:53:22 -07:00
Neil a7d9a10e4a feat(files): page a remote server's big folders in the explorer (#35115)
* feat(files): page a remote server's big folders in the explorer

* fix(files): list a remote folder whole unless the host refuses it as too large, then page it

* fix(files): page a remote folder after a cursor entry, not at an offset

* fix(files): release expired folder listings, share one in-flight listing, keep an oversized one alone

* fix(files): cap and time out cached folder listings, bound the cursor name, match id: selectors
2026-10-28 06:51:12 -07:00
OrcaWinandOrcaWin aab2254596 test: remove 53 low-value emulator, parser and cursor cases (#34830)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 06:42:53 -07:00
Neil 7f543df3e5 fix(startup): don't quit when a helper window closes before the main window opens (#35120)
On Windows/Linux, window-all-closed quit unconditionally. A hidden browser
extension native page (content-script restore) destroyed before the first
main window existed emitted window-all-closed and quit the app mid-startup.
Gate the quit policy on the main window having opened at least once.

Fixes #34911
2026-10-28 06:35:05 -07:00
OrcaWinandOrcaWin 149ec5d6db perf(attention): index subject reads once per batch (#35088)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 06:33:47 -07:00
NeilandClaude 4916c09079 fix(terminal): a WSL bridge pane keeps its session when its distro is booted again before the check (#35050)
* fix(terminal): a WSL bridge pane keeps its session when its distro is booted again before the check

A bridge exit that the running list calls 'running' is now host loss when the distro's boot id
changed since the pane spawned (something booted it again first), and an unanswered list is asked
once more before the exit stays an exit. Boot ids are read once per distro boot, only into a
distro the background-work gate confirms running, so the read never boots one.

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

* fix(terminal): an exit drops the distro's boot id at once, and a new incarnation takes the current one

Reviews of #35050: a pane spawned during another pane's exit verdict, or the same session
respawned into a rebooted distro, kept the old boot's id, so its own later exit read as
'rebooted' and its tab never closed. A burst of exits now shares one read of the current id,
and the verdict log names the exit code.

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

* fix(terminal): a stale bridge exit drops the boot id, and the respawn that beat it re-reads its own

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

* test(terminal): wait on the exit, not the clock, in the bridge relaunch suite

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 06:18:54 -07:00
Neil 938286e6bf perf(orcad): qualify a bundled slot once per unchanged host instead of every launch (#35064)
* perf(orcad): qualify a bundled slot once per unchanged host instead of every launch

Every bundled orcad launch ran a second full orcad-server.js process (the startup preflight)
before serving: 0.7-1.4 s after a WSL distro restart. Once a launch with the same key reaches
readiness, the slot records a marker; the next launch with that key skips the child. The key
covers the artifact version, each installed file's stat identity, the runtime identity, Node
version, libc and kernel. The marker is consumed at startup and rewritten only after readiness,
so a launch that fails or crashes before readiness re-qualifies; it is written via temp + rename,
and any read, parse or write problem falls back to the preflight.

* perf(orcad): keep running the startup preflight on Windows

There the child also proves the process identity table, which depends on host services rather
than on the slot's bytes.

* docs(wsl): note when the version GC memo can leave a stale dir behind

* fix(orcad): harden the startup qualification marker

- A failed preflight child deletes any marker, so a concurrent launch cannot rely on it.
- Only managed slots (launched with the managed activation root, as for the compile cache)
  outside process.resourcesPath ever read or write a marker.
- The key fingerprints NODE_OPTIONS, LD_PRELOAD, LD_LIBRARY_PATH and TMPDIR as orcad sees them.
2026-10-28 06:14:49 -07:00
OrcaWinandOrcaWin 3e625b18b8 perf(browser): await installed proxy policies during startup (#34977)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 06:11:44 -07:00
OrcaWinandOrcaWin 05aab3a185 fix(browser): retire notifications with unloaded extensions (#35006)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 05:46:28 -07:00
Brennan Benson ab512bfe13 Show a chat's saved permission mode while its agent isn't reporting (#34546)
Chats with an explicit mode showed a disabled 'Permissions' placeholder whenever no running agent had reported, which is every idle or resumed chat, so the mode could not be read or changed. A live report still wins; chats that follow the agent's own settings still wait for the report.
2026-10-28 05:44:03 -07:00
Neil 8857567570 perf(wsl): read the kernel, login home and platform in one exec (#35070)
* perf(wsl): read the kernel, login home and platform in one exec

The WSL connect's first exec now prints the kernel release, $HOME and the marker-backed uname
platform probe together, and hands the platform and home to resolveOrcadRemoteContext, which
then skips its own uname and $HOME probes: two fewer serial guest round trips per connect. SSH
passes neither, so its probes are unchanged.

* fix(wsl): accept the folded host facts only in their exact shape

Each fact now prints after its own marker, and the output is used only when it has exactly the
kernel line, the home line, the blank separator and the platform line. Anything else (stdout
noise, a HOME containing a newline) falls back to reading the kernel alone and lets the context
probe the platform and home itself, so no truncated path is ever used.
2026-10-28 05:43:33 -07:00
OrcaWinandOrcaWin f50425f2ec fix(browser): retire deleted profile extension action state (#34988)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 05:36:26 -07:00
Neil 760e311693 test(wsl-host): the last Orca on a WSL host tears down once the other is gone past the grace (#35086)
R39 follow-up. When one Orca's Remove kept the server for another, that other
Orca's later Remove must tear it down once the first is gone. The test covers
it end to end on a real server: kept while both are connected, still kept
inside the first Orca's 60-second reconnect grace, and no peers after it.
2026-10-28 05:32:54 -07:00
OrcaWinandOrcaWin a4ecf2741c perf(browser): reuse native census during SSH partition teardown (#34979)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 05:31:27 -07:00
Neil 49bec7dd16 fix(runtime): sleep and stop resolve project-group folder workspaces (#35082)
Refs STA-12562
2026-10-28 05:31:05 -07:00
Neil b329de4407 fix(wsl-move): say a moved project's host was kept for another Orca and needs re-adding (#34989)
* fix(wsl-move): say a moved project's host was kept for another Orca and needs re-adding

When this Orca removed a WSL host while another Orca kept its server running
(R39), "Use on this computer again" refused with the generic "the host isn't
answering, connect it or remove it". Neither works, because the host is
already removed here. It now says: "<project> moved to the <distro> host, which
is still running for another Orca. Re-add the host to use it here again."

* i18n(wsl-move): German for the kept-host undo copy
2026-10-28 05:29:47 -07:00
Neil daf806bb41 fix(wsl-host): refuse Windows-only agent CLIs in phone, resume and fork launches (#35016)
* fix(wsl-host): give phone, resume and fork agent launches the Windows-only refusal

* fix(wsl-host): hint the Command setting on required-CLI refusals

* fix(wsl-host): refuse explicit resumes of a Windows-only CLI with the fix-it message
2026-10-28 05:15:44 -07:00
TotoroandNeil 48b62d9e15 fix(daemon): arm the shutdown deadline when idle retirement begins (#29407)
Idle retirement (last-client disconnect, initial-adoption timeout, ownership
loss, and shutdownIfIdle) skipped onShutdownRequested(), so a stalled resource
disposal left the daemon alive with no five-second exit deadline.

Fixes #29406

Co-authored-by: Neil <neil@stably.ai>
2026-10-28 05:10:24 -07:00
f231d1cde6 feat(files): play remote audio and video through one byte-range preview path (#35038)
* feat(media): read remote media ranges through the paired runtime

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

* feat(media): stream remote media through orca-media grants

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

* feat(editor): play video and audio from remote runtime workspaces

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

* fix(media): surface update-required for remote media and cancel in-flight chunks

Probe files.readChunk once per environment and pairing revision before minting a
grant so older servers show the update message. Closing a media stream now aborts
the in-flight remote chunk. Also validate the IPC address, fix extension-only
names, and tighten the preview return type.

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

* refactor(files): one classifier decides which viewer opens a file

Local reads, files.readPreview on hosts, git blob previews and the desktop's
remote binary handling each kept their own image/PDF extension table, and
media had another. file-preview-kind.ts is now the one table: image, PDF,
audio or video, with the MIME type. AVIF, which only local reads knew,
previews on hosts and in git diffs too.

* perf(runtime): give byte-range reads their own small call lane

files.readChunk (media streams, paged files, downloads) now runs in a
two-call lane per environment, so a playing video or a download never holds
the slots terminal input and workspace calls use.

* feat(files): stream previews from paired runtimes by byte range

Generalises the remote media grant into one byte-range preview path: an
orca-media:// grant keyed by environment, worktree, path and pairing
revision, streamed over files.stat/readChunk. Audio and video use it now;
the shared classifier decides which viewers do.

- One files.stat at mint replaces the readChunk probe: it proves the host
  serves range reads and that the path is a file, so an old host or a
  missing file fails in the tab, not as a silent player error.
- A burst of range requests shares one stat (reused for 1s), so seeking
  costs one round trip less on a slow link; later requests re-stat, so a
  growing recording keeps playing.
- Removing a paired runtime revokes its grants; a re-paired one answers
  410 and drops the grant.
- Only readers that render bytes mint a stream; baseline checks don't.

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>

* fix(files): prove chunk reads at mint, and let a reload report the new size

Hosts from v1.4.5 answer files.stat but only v1.4.111 and later answer
files.readChunk, and no capability names it, so minting reads one byte,
cached per pairing, and an older host fails in the tab with the update
message. A re-mint seeds the grant with its fresh stat, so a reload never
reuses an older size. A renderer gone mid-mint mints nothing. Preview
chunks time out after 20s so a stalled one frees its lane sooner.

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>

* fix(files): resolve preview hosts in the pairing registry's own directory

The remote preview reader looked environments up under the canonical
user-data path, while the pairing IPC writes the registry under
app.getPath('userData'), which can differ in casing on case-sensitive
installs. Both now use one getter. A chunk-read verdict is cached only
when a pairing revision pins it, so it can't outlive a re-pair.

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>

* fix(files): read the pairing registry from one directory everywhere

Doc previews resolved paired servers under the canonical user-data path,
the same casing mismatch the media reader had. They and every other main
caller that names the registry directory inline now use
getRuntimeEnvironmentRegistryRoot(), so it has one source.

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>

* fix(files): pin an unpinned preview grant to the pairing it was minted on

A renderer that hadn't loaded the environment's pairing revision yet sent
none, and every later chunk read went unguarded, so a re-pair under the
same environment id would let the old URL read from the new host. Main now
pins the registered revision at mint.

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>

* refactor(files): route the remaining pairing-registry readers through the one getter

AI-vault host scans, the settings runtime-environment preference, skill
capability checks and the mobile relay host list named the registry
directory inline. They now use getRuntimeEnvironmentRegistryRoot() too;
callers that also use the directory for other storage keep their own path.

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>

* refactor(files): write new pairings through the same registry root

The ephemeral VM pairing writer named the registry directory inline; it now
uses getRuntimeEnvironmentRegistryRoot() like every reader.

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>

---------

Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 05:08:55 -07:00
OrcaWinandm4air c1262516b9 perf(renderer): mirror modal overlays to body attributes instead of body:has() (#34932)
A body:has() rule with a descendant subject (the modal blur and toast rules) made
Chromium invalidate the whole document's style on every DOM mutation anywhere in
the app. A workspace switch paid two full-document recalcs (~1200 elements each,
~9 ms). A childList-only MutationObserver on body now mirrors the overlays into
data-modal-overlay-open / data-onboarding-overlay-open and the rules key on those.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-28 05:04:20 -07:00
Neil ce3c8d1383 perf(wsl): hold the distro alongside the read-only context probes (#35037)
* perf(wsl): hold the distro alongside the read-only context probes

The kernel probe has already started the distro, so the holder now runs alongside the four
read-only context reads instead of before them; it is still held before recovery, which may
launch orcad. No new wsl.exe spawns. The WSL 1 check and the parallel hold move to
wsl-orcad-held-context.ts.

# Conflicts:
#	src/main/wsl/wsl-orcad-deploy.ts

* fix(wsl): stop the context probes once the distro hold fails

A failed hold left the context probes running; after the deploy disposes its transport they fall
back to fresh wsl.exe execs, which could boot a distro that just went away (E9). The probes now
run under a child signal of the connect's, aborted on a hold failure or any other rejection.

* test(wsl): cover the context probes running while the hold is pending

Moves the ordering check out of the deploy suite, which is at its line cap after main's new
refusal tests, into the held-context suite.
2026-10-28 04:53:32 -07:00
OrcaWinandOrcaWin 15fac13c5f Limit extension visible-tab capture admission (#34962)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 04:52:57 -07:00
Neil 19e0b84834 perf(wsl): skip orcad version GC on reconnects once a pass left nothing behind (#35027)
A distro restart reconnects with the same active version and daemon, so the ~9 guest commands of
version GC find nothing new. GC now reports whether it left any stale version dir behind; the WSL
deploy skips it for the rest of the app session once a pass under the same active version and
daemon version came back clean. SSH callers ignore the new return value.
2026-10-28 04:46:39 -07:00
Neil e8084426ad test(wsl): capture a CPU profile of orcad's startup after a distro restart (#35043)
After the three measured restarts, the idle-release lane runs one more, unrecorded restart with
orcad launched under --cpu-prof (through the lane's own launch env), waits for its idle exit and
copies the profiles of orcad and the Node children it started into the receipts.
2026-10-28 04:37:46 -07:00
Neil f59bd43c46 fix(wsl-host): Remove keeps a WSL host's server that another Orca on this computer shares (R39) (#34699)
* fix(wsl-host): Remove keeps a WSL host's server that another Orca on this computer shares

A WSL host's server lives in the Linux login's ~/.orca, so two Orca installs on
one Windows account (stable and dev), or a desktop reaching the distro over SSH,
share one server. Remove used to close every terminal there and decommission
it, ending the other desktop's sessions and agents.

The server now answers host.peerDesktops (capability orcad.peer-desktops.v1):
the other desktops paired with it, whether each is connected now, and when each
was last seen. Before tearing anything down, Remove asks. If another desktop is
connected or was seen in the last 30 days, it only closes this desktop's bridge
and reports the server kept. If the server can't answer, the teardown is
refused. An older server without the capability gets today's teardown, plus a
warning.

* fix(wsl-host): a shared Remove releases this Orca from the host, and says the host keeps running

- On a shared server, Remove now revokes this desktop's own device (and its
  phones) on the host, through the new host.releaseDesktop, before letting go.
  Otherwise its recent row would make a peer's later Remove keep the server
  forever. Peers also skip rows of the caller's own installation (same caller
  fingerprint), such as an enrollment from before a re-add.
- The renderer says when a removal kept the host for another Orca, and the
  Remove confirmation no longer promises to end terminals unconditionally.
- Remove-path files now route CI to the fake transport e2e spec, which
  exercises Remove.

* i18n(wsl-host): Russian and Traditional Chinese for the shared-host Remove copy

* fix(wsl-host): tell desktops apart by device key, and release this Orca on every Remove

- Peers are no longer hidden by caller fingerprint. Every device-key fork of
  one pairing token row inherits that row's fingerprint, so two installations
  that paired through one code hid each other, and one's Remove could tear the
  server down under the other. Only a shared device public key now marks the
  same installation, as with a re-add under a new token.
- This desktop's own device is released as the last call over the bridge on
  every Remove that proceeds (no terminals left), not only a shared one. A
  later Add then Remove never meets a stale row of ours.
- When the release fails on a shared Remove, the toast says the host may keep
  running for a while. The Russian confirmation copy is corrected.

* fix(wsl-host): move undo refuses a removed host whose server another Orca kept

A Remove that kept a WSL host's server for another Orca (R39) now records
that. Before, undo of a move onto that host read the missing environment as
"its terminals and automations stopped with it", and would have restored the
project here while the host's copies kept running, duplicating its agents and
automations. Undo now reads such a host as unreachable and refuses, as it does
for any host it can't reach. A later Remove that proves the server stopped
clears the record. If the record can't be saved, the host stays listed as
pending instead.

* i18n(wsl-host): Turkish for the shared-host Remove copy

* fix(wsl-host): each WSL desktop splits off its own row from orcad's startup pairing

orcad publishes one startup pairing offer and never rotates it, so every
desktop that enrolled through it shared one token row and device id. Stable and
dev Orca on one distro were invisible to each other as peers, and releasing that
shared row broke the next re-add and pairing repair.

- New host.forkDesktop (same orcad.peer-desktops.v1 capability). A runtime
  device on a shared desktop token mints its own token row, forked from it and
  named by the caller. Forks share the device-key fork cap, and a released fork
  frees its slot.
- The WSL desktop forks right after enrolling through the startup offer, or
  after a repair lands back on it, and keeps the forked pairing (named after its
  userData folder, e.g. Orca or Orca Dev). On an older orcad, or if the fork
  fails, it keeps the shared pairing and warns.
- A token row that desktops forked from counts as a peer only while something
  is connected on it. One that nobody forked from keeps the last-seen rule.

* fix(wsl-host): keep host.forkDesktop to the startup offer's holder, over E2EE, with a clean label

host.forkDesktop mints a credential, so:
- only the holder of the desktop pairing offer this server advertised last
  (orcad's startup offer) may fork; an older offer, a fork, a phone or any
  other row is refused;
- the fork takes exactly the caller's grants and reach; params are just a label
  (strict, so a grant request is refused);
- it runs only on an authenticated E2EE socket; the token goes back only in
  that reply and is never logged;
- the label is display-only: control, zero-width and bidi characters stripped,
  whitespace collapsed, at most 64 characters; an empty result is refused.

* refactor(wsl-host): count only Orcas connected right now as WSL host peers; drop fork and release

Review found the token fork and self-release add more identity state than R39
warrants: orphan forks, a desktop left on the shared token releasing it, and a
changed caller fingerprint. So this drops host.forkDesktop, host.releaseDesktop
and the 30-day last-seen rule, and restores the restart test.

A peer is now another Orca installation with a control socket open on the
server right now. The desktop declares its installation (a hash of its userData
path) with host.declareClient on its shared-control socket after every ready,
including reconnects. The server tags that socket and drops the tag when it
closes. host.peerDesktops takes the caller's installation id, so its own other
sockets (multiplex, one-shot) never count, and two desktops sharing one startup
token stay distinct. Undeclared sockets, phones and browser sessions are
ignored. Peer names go through sanitizeDeviceLabel, and a startup-offer
"CLI <date>" name shows as "another Orca". An older orcad lacks the method:
nothing is declared, and Remove keeps today's teardown with a warning.

Limit: an Orca that's closed while its terminals keep running isn't protected.

* fix(wsl-host): keep a reconnecting Orca as a WSL host peer for 60 seconds

Lost contact isn't proof an Orca left. When an installation's last declared
control socket closes (a bridge exit, an orcad restart, resume from sleep,
reconnect backoff), the server keeps counting it as a peer for 60 seconds, or
until it re-declares. A Remove inside that gap no longer tears down its
terminals.

* fix(wsl-host): say an open Orca keeps the host, and name each peer once

- The Remove confirmation now reads "Unless another Orca that's open on this
  computer is using it", since only a connected Orca keeps the server.
  Updated in all 10 locales.
- The kept-host toast dedupes peer names, so several unnamed peers read
  "another Orca" once.

* test(wsl-host): pin the reconnect grace to the last socket's close, and to the server's own forget

- The unit test advances the clock between the two closes and checks that the
  peer still counts when the first close's grace would have run out.
- The integration test waits until the server has dropped the closed socket
  before reading peers, so it fails without the grace (checked by setting the
  grace to zero).

* fix(wsl-host): sweep expired reconnect graces on every close, on a monotonic clock

Expired graces are dropped at the start of forget() as well as peers(), so the
map stays bounded even when nobody asks for peers. The default clock is
performance.now(), so a wall-clock jump can't stretch or cut the grace.

* i18n(wsl-host): German for the shared-host Remove copy
2026-10-28 04:27:30 -07:00
NeilandClaude df2c29230e test(wsl-mover): undo of an older move refuses while a newer one stands, and newest-first undo touches only its own move (#35033)
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 04:26:41 -07:00
NeilandClaude 4a9c1265e1 fix(agent-session): a chat whose working folder was deleted says so, not that the CLI is missing (#35003)
* fix(agent-session): a chat whose working folder was deleted says so, not that the CLI is missing

Node reports a spawn whose cwd is gone as ENOENT naming the command, and the supervisor's
report names no path, so a deleted worktree read as a missing agent CLI. On a spawn ENOENT,
one stat of the cwd the spawn was given now tells the two apart, and the chat reports the
existing launchFolderMissing reason.

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

* fix(agent-session): a missing supervisor binary is never reported as a missing agent CLI

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 04:22:52 -07:00
0b6071aec4 fix(wsl-host): tell users how to fix a distro Orca can't host (D1c-1) (#33085)
* fix(wsl-host): tell users how to fix a distro Orca can't host

With the WSL bridge going away there is no fallback for a distro Orca's server can't
run in, so each refusal now names the step that fixes it:
- WSL 1: the wsl --set-version command, also shown in the Add host form, where the
  disabled option could never show it.
- An unregistered distro, at Add and at connect: how to list installed distros.
- NixOS's stub loader: turn on nix-ld.
- glibc below every runtime's floor: the minimum release to use.
- A WSL distro with an unknown platform no longer reads as "this SSH host".
Connect refusals other than WSL 1 report as 'unsupported-distro' instead of reusing
'unsupported-wsl1'.

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

* fix(wsl-host): show only the plain message when a WSL host can't connect or be added

* test(wsl-host): fold the plain-message case into the existing readIpcErrorDetail tests

* fix(wsl-host): keep SSH's old-glibc and NixOS refusals as they were; add the fix only for a WSL distro

The glibc and nix-ld hints were appended in code SSH hosts share, so SSH users
saw new wording with the WSL hosts gate closed. The shared messages are back to
main's text; the WSL add flow adds the fix to its own refusal.

(cherry picked from commit c7a07b61c440e87652ca956570b8b91492c2a375)

* refactor(wsl): map a missing distro in the unsupported-distro module, keeping orcad deploy under its line cap

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 04:17:40 -07:00
Neil 2459222db1 test(wsl): break the WSL host restart into phases in the lane receipt (#35005)
The real-distro lane now times each restart's ensure by phase (first exec and boot, holder,
pre-launch checks, launch, orcad startup, post-readiness, bridge, pairing) from wrapper marks and
guest-command start times. orcad logs its own startup phases to its slot log only when the
lane's launch env sets ORCA_E2E_ORCAD_STARTUP_TIMING; the lane reads that line into the receipt.
2026-10-28 04:13:55 -07:00