Commit Graph
16589 Commits
Author SHA1 Message Date
eatmoreduckandNeil 15fc7a6769 docs(settings): describe the GitHub integration as the local gh CLI login, not OAuth (#26609)
Orca has no OAuth app; it reads tokens from the gh CLI on the machine running
Orca. Document that, the per-host login for Remote Orca Servers, and the
repo/read:org/project scopes auth-diagnose expects.

Refs #26604

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 04:22:49 -07:00
Neilandbrynnclaw e50fe1e10e fix(ai-vault): delete a server-hosted session on the server that owns it (#33906)
Agent Session History now routes Delete for a session on a paired or
SSH-managed Orca server to that server through a new aiVault.deleteSession
RPC. The host revalidates the path against its own roots, removes the
transcript (into Trash on a desktop host; permanently on a plain-Node host,
which has none), and invalidates its caches. Hosts advertise
aiVault.delete-session.v1; an older host keeps Delete disabled with
"Update <host> to delete its sessions from here."

Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com>
2026-10-26 04:20:36 -07:00
67af384c4b fix(terminal): keep find-bar highlights when navigating with Cmd+G / Cmd+Shift+G (#18844)
The Cmd+G / Cmd+Shift+G path called findNext/findPrevious with only
{ caseSensitive, regex }. @xterm/addon-search only draws the active-match
decoration, fires onDidChangeResults, and keeps refreshing highlights on new
output when the call carries decorations, so the shortcut froze the active
highlight and the match counter.

Share one buildTerminalSearchOptions() between the find bar and the
shortcut path so both send the same decorated options.

Co-authored-by: Anton Kuligin <anton.kuligin@notraffic.tech>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 04:17:21 -07:00
Neil 2fc9ad54cf test(wsl): cover the bash bridge's argv, backpressure, fallbacks and cleanup (#33907)
Prove the relay reaches wsl.exe through --exec unchanged, carries every byte
value both ways, holds the desktop back under a stalled reader on either
side, falls back to Node for no bash, old bash, no /dev/tcp and refused
dials with unchanged sentinels, and leaves no bash or cat behind when
either side goes away.
2026-10-26 04:04:33 -07:00
Neil 5a973e29a7 fix(cli): show orphaned state in human-readable terminal list/show output (#33910)
Fixes #15313
2026-10-26 04:01:44 -07:00
Neil c5299b1169 fix(wsl-host): keep the bridge port across app restarts so the host isn't re-paired (#33109)
A WSL host's bridge listened on a fresh port each launch, which changed the saved
pairing endpoint. The renderer treats a changed WSL pairing as a different machine
and purges the host's workspaces, tabs and selection, then rebuilds them once the
host relists its projects.
2026-10-26 04:01:27 -07:00
OrcaWinandm4air bb5137969f fix(memory): show Activity Monitor's footprint in the resource panel on macOS (#33901)
The resource panel summed RSS. On macOS that counts the Electron framework's
shared pages once per helper process, so main and renderer read 2-8x too
high, while the GPU process read 3-5x too low because RSS excludes graphics
memory. The detached terminal daemon was also missing from the app total.

On macOS, sample per-process phys_footprint from top (the figure Activity
Monitor shows) at most every 10 s while the panel is open, and fall back to
RSS when top is unavailable. Count the local terminal daemon in the app's
'other' bucket; its PTY children stay attributed to their worktrees. Linux
and Windows keep RSS/working set.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 03:57:41 -07:00
17621d5368 fix(editor): match external file changes across Windows path spellings (#14812)
On drive and `\\` UNC roots, an open tab whose filePath used a different
separator or drive-letter spelling than the watcher event (for example
`c:\Repo\File.ts` vs `C:/Repo/File.ts`) never matched, so external edits
did not reload the tab or raise the changed-on-disk banner.

Both direct-match sites (the indexed batch lookup and the non-indexed
fallback in getOpenFilesForExternalFileChange) now compare through
externalChangePathKeyFor(root), which reuses editorBufferPathKey to fold
separators, the drive letter, and the UNC server only. Path-tail case stays
exact, and WSL, POSIX, SSH, and `//` roots keep byte-exact keys.

Fixes #14801

Co-authored-by: VXNCXNX <VXNCXNX@users.noreply.github.com>

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 03:56:28 -07:00
Neilandoutof-place ac5c5ae4cf fix(process-table): pin macOS ps to en_US.UTF-8 so lstart and argv parse under any locale (#33898)
macOS ps formats lstart with the user's locale (%c) and vis-encodes
non-ASCII argv when no UTF-8 locale is set. Under de_DE/en_NZ/ja_JP the
process-table parsers dropped tty/startTime and folded them into command,
breaking agent recognition, pane fingerprints, agent-session start times
and daemon identity. Run those ps readers with LC_ALL=en_US.UTF-8 on
macOS; other platforms keep the inherited env.

Fixes #27004

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-26 03:56:09 -07:00
Wooseong Kim ab62ae7e96 fix(diff): keep the collapsed section header in view (#24466)
Collapsing the section the View all diff viewport was inside kept the
scroll anchor's within-section offset, which pointed into the removed
body, so the structural restore landed on later sections. Pin the anchor
to the section header before the collapse is published.

Fixes #20665
2026-10-26 03:50:58 -07:00
OrcaWinandOrcaWin 819d273e27 perf(lint): one ast-grep scan feeds both the lint gate and the flaky-test ratchet (#33903)
lint:ast-grep and check-flaky-test-pattern-ratchet each parsed the whole tree.
ast-grep-gates.mjs scans once; the lint gate re-runs ast-grep only on files with
warning-or-error findings (ast-grep's own report and exit code), and the flaky
ratchet counts test-* matches from the shared scan.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 03:50:42 -07:00
5ee6e42a3b fix(drops): keep remote drops out of git and say why drops or file opens fail (#33831)
* fix(drops): keep files dropped onto a remote workspace out of git status

Uploads into `.orca/drops` now write `.orca/drops/.gitignore` (`*`) the first
time it is missing, so dropped files no longer block a plain workspace delete
or get committed by `git add -A`. Callers share one constant for the folder.

Fixes #23856

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

* Re-check the import session after the drop staging ignore step

The ignore step swallows its own errors, including a stale session. When
nothing was staged the loop never asserted again, so the caller got
skipped/failed results instead of the retry error.

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

* fix(drops): say why a remote drop or file open failed

Co-authored-by: Jae Heo <83424878+jae-heo@users.noreply.github.com>
Co-authored-by: Bing.Z <zzb@gxsmjx.com>

* fix(drops): keep paths out of failure toasts and reuse the too-large classifier

* fix(drops): shorten whole quoted paths in failure toasts

* fix(drops): describe upload failures by category instead of host text

* fix(drops): match failure categories on unquoted text and name manual disconnects

---------

Co-authored-by: Younghwan Chae <chyohw97@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jae Heo <83424878+jae-heo@users.noreply.github.com>
Co-authored-by: Bing.Z <zzb@gxsmjx.com>
2026-10-26 03:48:47 -07:00
Neil dab0cd1766 refactor: colocate task page PR presentation rules (#33890) 2026-10-26 03:45:47 -07:00
Neil 2c0c6ac0c4 docs: stop promising cross-worktree split panes and Shift-Enter split in Jump Palette (#33902)
Panes are scoped to a single worktree and the Jump Palette has no
Shift-Enter handler, so replace those promises with the real flow:
watch sidebar status indicators and jump between worktrees with
Cmd-J (macOS) / Ctrl-Shift-J (Windows / Linux).

Fixes #10477
2026-10-26 03:45:32 -07:00
Neilandoutof-place c36378c2b9 fix(build): keep index.js source map aligned with the bootstrap banner (#33899)
The main bootstrap banner was prepended to index.js in generateBundle,
after Rolldown had already emitted index.js.map, so every main-process
crash trace decoded ~200 lines off. Emit it via Rolldown's output.postBanner
instead, which shifts the source map natively.

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-26 03:45:15 -07:00
BingZandNeil 7e573331ee fix(shell): resolve VS Code CLI from standard app installs when code is not on PATH (#14010)
GUI-launched Orca often inherits a minimal PATH, so bare `code` fails with
spawn ENOENT for Open in VS Code, including Remote-SSH worktrees. When PATH
and install-dir lookup leave `code`/`code-insiders` unresolved, fall back to
the CLI bundled in the standard macOS app bundle (/Applications or
~/Applications) or the Windows user/system install. Linux packages already
link the CLI onto PATH, so no Linux candidates are added.

Fixes #14008

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 03:39:45 -07:00
Ethereal49andNeil 7cd63e1c66 fix(notifications): use the real macOS default sound for the System notification option (#26321)
On macOS the System sound option passed sound: "default" to Electron, which
the UNUserNotificationCenter backend resolves via soundNamed:"default" (a file
lookup) instead of UNNotificationSound.defaultSound, so banners were silent.
Leave sound unset so Electron plays the OS default, and drop the now-dead
sound field from the notification options type.

Fixes #26043

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 03:39:26 -07:00
faf173235b fix(telemetry): send an errno code, not the raw message, in agent_hook_install_failed (#25287)
agent_hook_install_failed sent up to 200 chars of the raw installer error,
which embeds home-directory paths (and so the OS user name) and can echo
config contents. Send only the error's errno code or 'unknown', and enforce
that in the event schema. The anchored, capped errno pattern now lives in
src/shared/errno-code.ts and is shared with the renderer launch probe and the
file-write precondition instead of their own copies.

Fixes #21492

Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
2026-10-26 03:39:17 -07:00
2sumtechandNeil 007dfff3a9 fix(browser): accept an empty --value in fill and select commands (#16030)
`orca fill --value ""` and `orca select --value ""` were rejected client-side
with "Missing required --value" even though the browser.fill/browser.select RPC
schemas already accept an empty string. Read --value with the existing
getRequiredStringFlagAllowingEmpty helper so an empty value clears a field or
picks the blank option, while an absent --value is still rejected.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 03:27:29 -07:00
03653ea856 fix(orchestration): keep the transcript handle open when a forward page fills (#32894)
Returning early from the for-await over the forward-page ReadStream
destroyed the stream, which closed the shared FileHandle before the
boundary checkpoint read, so any forward page that hit its limit failed
with transcript_parse_failed. Scan with positional handle.read calls
instead so the handle stays open and read errors reject inside the
caller's try/finally.

Fixes #32892

Co-authored-by: Kim Kaznowski <kim@doubledashstudios.com>
Co-authored-by: Neil <neil@stably.ai>
2026-10-26 03:27:10 -07:00
39d4c73b07 fix(automations): step schedule scans by calendar day so DST changes don't skip dates (#19086)
The RRULE day scan stepped local midnight by a fixed 24h. Walking back
over a 23-hour spring-forward day landed at 23:00 two dates earlier, so
the latest-occurrence lookup used for catch-up runs skipped a date. It
returned a run a day too old for daily schedules, and a week too old for
weekly ones.

Step with setDate via a shared addLocalDays helper, in both the RRULE
scan and the cron feasibility scan. Add a regression test for
America/New_York and Australia/Lord_Howe. The test is skipped on Windows,
where unstubbing TZ doesn't restore the OS zone.

Co-authored-by: liutian <liutian.6000@bytedance.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 03:27:00 -07:00
Samuel VilaandNeil bd3a6c875c fix(open-in): strip the AppImage runtime env from editors launched on Linux (#31675)
Open in started editors with Orca's full environment, so an AppImage
launch leaked ARGV0/APPDIR/APPIMAGE/OWD/APPIMAGE_LIBRARY_PATH and the
mount-path PATH and LD_LIBRARY_PATH entries into the editor's integrated
shells (zsh then runs host commands like cargo under the AppImage name).

Add envWithoutAppImageRuntime() next to removeAppImageRuntimeEnv and pass
its result to every editor spawn path on Linux; macOS and Windows keep
inheriting the env unchanged. The clipboard publisher and both AppImage
daemon command builders reuse the same helper instead of their own
copy-and-scrub loops.

Fixes #31455

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 03:26:47 -07:00
Wooseong KimandNeil 6ad0a42425 fix(github): send issue bodies to gh over stdin instead of argv (#25215)
Issue create (including the empty-body fallback and follow-up PATCH),
issue body edits, and issue comments passed the body as
`--raw-field body=...` on argv. Windows caps the command line at
32,767 chars, so bodies with pasted inline images failed with
`spawn ENAMETOOLONG` before reaching GitHub.

These calls now use `gh api -X <METHOD> <endpoint> --input -` with a
JSON payload on stdin. ghExecFileWithScopeAsync also now forwards
`options.stdin` to the child process; it was previously dropped.

Fixes #15832

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 03:26:35 -07:00
OrcaWinandOrcaWin a26006aa6a perf(ci): overlap preflight's serial tail; parallel ratchets; allow 2-10 unit shards (#33887)
- Plan unit selection starts after setup (overlaps lint) instead of last.
- Localization extraction starts with the typecheck; test-file-runners is background.
- run-ratchets.mjs runs ratchets in a pool (19s serial -> 8s locally).
- pnpm lint uses CI's single-parse check-import-boundaries.mjs.
- ORCA_UNIT_FULL_SHARD_COUNT accepts 2-10 (default stays 5).

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 03:17:34 -07:00
NeilandClaude 15a1ff75fc fix(ssh): refuse a second Orca server from a host cloned with the same machine-id (#33775)
* fix(ssh): keep machines cloned with one machine-id off each other's Orca server data (#32918)

Machines cloned from one image share /etc/machine-id. On a shared home both
got the same machine key, so both managed servers ran in ~/.orca, and each
judged the other's PID locally and reclaimed its live instance lock.

- Record the claiming hostname in the shared-home claim and machine homes;
  a Linux machine whose machine-id matches but hostname differs gets its own
  machine home. Older claims fall back to data-root owner records.
- orcad's instance lock no longer treats a holder with this machine-id but
  another hostname as local, and refuses to start when an older clone's
  profile-state owner record shows it is using the data root.

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

* fix(ssh): keep a clone's established machine home, and let a host renamed within its boot restart

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

* fix(ssh): call a machine a clone only with positive evidence

A renamed host keeps its boot and a local disk has one machine, so only
another host and boot with this machine-id on a shared filesystem counts as
a clone, on Linux only. When both clones already write the login home, stay
and let the server lock refuse the second writer. Drop the machine-home
owner markers.

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

* fix(ssh): refuse a second server from a cloned host instead of relocating data

Drop the inferred clone relocation. orcad refuses to start when a holder or
profile-state owner on a shared filesystem reports this machine-id from another
hostname and boot, naming that host and the fixes. Add ORCA_MACHINE_NAME, an
explicit host-env name that gives a managed SSH host its own machine home.

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

* fix(ssh): judge cloned machines by boot and freshness, not hostname

A peer with this machine-id is another live machine only when its record is
from another boot, was written after this boot began, and is fresh. The orcad
lock now heartbeats its mtime. That drops the hostname test, which renames
broke and same-hostname clones evaded. It also drops the participant-owner
precheck that stale records could block forever, and keeps profile-state
owner cleanup from deleting a live clone's owner. stale-lock reclaim uses the
same rule. ORCA_MACHINE_NAME now rejects invalid names and keeps a host on
the home its running server or own machine-id already uses. Hints are
role-specific and aimed only at the clone.

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

* fix(orcad): stale-lock reclaim waits out the lock freshness window

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

* fix(orcad): log a failed lock heartbeat and say a crashed clone's lock frees itself

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

* fix(orcad): align reclaim help, age evidence and clone hint with the freshness window

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

* fix(ssh): ORCA_MACHINE_NAME always selects its own home

Inferring which home to keep from running owners flipped after shutdown or
reboot and couldn't see macOS boots. A name now deterministically selects
its home, and a multi-line name is refused.

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

* fix(ssh): refuse a whitespace-only ORCA_MACHINE_NAME, and pin reclaim test clocks

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 03:08:10 -07:00
eatmoreduck 8d18f318d7 fix(build): pin the native SwiftPM build system for the computer-use universal binary (#21146)
SwiftPM 6.4 (Xcode 27) defaults to the swiftbuild build system, which writes
products to an xcodebuild-style layout instead of .build/<triple>/release, so
the lipo step in build-computer-macos.mjs finds no inputs. Pass
--build-system native to both per-triple builds.

Fixes #21145
2026-10-26 03:05:37 -07:00
Neil 41c7167b03 refactor: colocate task page list presentation rules (#33830) 2026-10-26 03:03:56 -07:00
Neil 33ddab70b7 feat(serve): keep macOS serve out of the Dock and opt in to the GPU on Linux (#33878)
* feat(serve): keep macOS serve out of the Dock and opt in to the GPU on Linux

On macOS, orca serve now runs as an accessory app with no Dock icon or
Cmd-Tab entry, and gets them back only while it hosts a desktop window.
On Linux, ORCA_SERVE_GPU=1 keeps hardware acceleration on for hosts that
expose a GPU to the server.

* fix(serve): restore the Dock only for real launches, after window services resolve

Gate the restore on any background or E2E launch, since dock.show() activates
the app, and run it just before the window is created so a services failure
cannot leave a windowless Dock tile. Say in the docs what the GPU opt-in can't
do on Orca's own Xvfb.
2026-10-26 02:53:57 -07:00
OrcaWinandOrcaWin 23c25ab55c test: remove low-value renderer helper and presentation tests (#33876)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 02:49:50 -07:00
Neil 1e63a0bbe4 fix(terminal): don't rewrite live bytes a renderer hydration seed already painted (#33766) (#33880)
Main seeds its terminal model from the renderer's xterm and queues live
chunks behind the seed. The renderer keeps parsing those chunks while it
serializes, so they were in the seed and then written again, doubling TUI
frames and splitting escapes (literal ';242m'). Hidden-pane reveals repaint
from this model. Skip queued chunks at or below the seed's seq and carry
any unfinished escape into the next chunk.
2026-10-26 02:42:32 -07:00
Neil 80d1038354 fix(runtime): stop a crash-zeroed server list from blocking every server save (#33864)
* fix(runtime): recover from a NUL-filled server list instead of blocking every save

Fixes #18766

* fix(runtime): recover only crash-zeroed server lists; keep removal proofs fail-closed

* fix(runtime): copy the blank server list aside on write instead of renaming it on read

* fix(runtime): recover a crash-zeroed server list only when saving a server

Plain reads stay fail-closed so startup cleanup cannot treat the zeroed file as
'every server was removed'; saving copies the bytes aside and publishes an empty
store only if the file is still blank.

* fix(runtime): publish the recovered server list only together with the saved server

A failed save now leaves the zeroed file in place instead of an empty registry that
startup cleanup would read as 'every server was removed'.

* fix(runtime): let SSH and WSL server setup save over a crash-zeroed server list

Their duplicate and conflict pre-checks read the list before the add and threw on the
zeroed file. The blank-file backup is now taken only once the write is attempted.

* test(runtime): give the fsynced interleaving property test room on slow disks

* test(runtime): run three guard-killing seeds instead of raising the interleaving timeout

The fsync on every store write made 40 seeds x 40 steps slow; seeds 1, 6 and 8 each
fail when one of the three guards this test protects is removed.
2026-10-26 02:42:14 -07:00
OrcaWinandm4air 8767456f60 perf(editor): stop Monaco's TS/JS worker when no TS/JS model is open (#33810)
Monaco's TypeScript WorkerManager has no idle stop, so viewing a single .ts
file kept a ~40 MB language worker alive for the rest of the session. After
60 s with no typescript/javascript model, re-apply the current compiler
options, which makes Monaco dispose the worker; the next TS/JS model starts
a fresh one lazily.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 02:36:57 -07:00
OrcaWinandm4air 4d9c32a84b perf(build): keep bundled scripts one-byte in V8 to cut idle memory (#33786)
V8 stores a script source as UTF-16 when any character is above U+00FF, so a
single em dash in a hot chunk doubled that chunk's resident source. Emit ASCII
(escaped) output for main, preload, renderer and worker bundles, escape the
CJK sentence marks in the prose URL regex source, and fail the renderer
boot-graph check if a boot chunk regresses to two-byte.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 02:36:45 -07:00
OrcaWinandm4air 10cc84f324 perf(terminal): relax idle process inspection for local POSIX panes too (#33829)
A visible local shell pane with no agent evidence was inspected every 2 s
forever. Each inspection is a full-system `ps -axo ...,tty=,lstart=,command=`
capture in the terminal daemon (0.155 s of CPU at ~1,100 processes, ~1.15 s
at ~1,950), which also churned ~2.7 MB/s of short-lived strings and grew the
daemon's young generation to ~120 MB resident. Apply the existing no-evidence
cadence (15 s while quiet; output, title or hook activity re-arms 2 s for
10 s; agent evidence returns to the active/idle tiers) to local POSIX panes,
as it already is for Windows and remote panes.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 02:36:27 -07:00
OrcaWinandm4air c6f54192d1 perf(daemon): cap the terminal daemon's young generation (−51 MB idle, −75 MB after bursts) (#33837)
* perf(daemon): cap the terminal daemon's young generation

Idle terminal polling in the daemon allocates a few MB/s of short-lived
strings (process-table captures), and V8 answers by growing the young
generation to its 64 MB semispace maximum. Nothing is retained (heapUsed
returns to ~12 MB after GC), but the committed semispaces held ~120 MB of
resident memory per daemon. Launch the daemon with --max-semi-space-size=4
on the fork, direct and extracted-AppImage paths. The flag goes on the
command line, not NODE_OPTIONS, because PTYs inherit the daemon's env.

* perf(daemon): pass the young-generation cap through the macOS launchd job

Release macOS builds start the terminal daemon from the signed helper bundle
through a launchd job, not the fork path, so the flag must be in its
ProgramArguments too.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 02:35:01 -07:00
Neil ad73494fb1 fix(agent-awake): warn once and back off when the sleep assertion keeps failing (#33841)
* fix(agent-awake): keep sleep-assertion failures warn-once across respawns

A successful spawn reset the failure streak, so a systemd-inhibit or caffeinate that
exits right away re-warned on every 30s retry.

* fix(agent-awake): back off sleep-assertion retries after consecutive failures

* test(agent-awake): dispose the real-timer assertion
2026-10-26 02:33:13 -07:00
Neil 1d90fd51c6 fix(terminal): typing held for a starting agent still arms recovery when its connect hangs (#33865) 2026-10-26 02:32:23 -07:00
OrcaWinandOrcaWin 7dbf3974df test: remove low-value renderer suites and redundant shared test cases (#33819)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 02:21:05 -07:00
NeilandClaude 196ca641e1 fix(wsl-host): tie each WSL host record to its pairing key (R31) (#29832)
* fix(wsl-host): bind a WSL host record to its pairing's server key (R31)

A valid but stale record could overlay WSL hosting onto a different loopback server re-paired
under the same environment id and bridge port. The record now carries the paired orcad's host key;
the overlay ignores a record whose key differs from the pairing's. Add writes the key and a
pairing refresh rewrites it with the ports, so a relaunch that changes the key still matches.
Records written before carry no key and keep port-only binding until their next refresh.

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

* fix(wsl-host): validate a refreshed pairing before writing, and accept the previous key mid-refresh

Review: the refresh wrote the record's new key before validating the pairing, so a refused or
interrupted refresh could leave a real WSL host without its overlay. Validate first, and keep the
replaced key as previousPairingPublicKeyB64 so the record stays bound across the two writes.

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

* test(wsl-host): use a key distinct from the fixture's own in the R31 overlay tests

Main gave the WSL fixture its own pairing key (#30676), the same one these tests used as the
'other server' key, so both cases inverted after the rebase. Production code is unchanged.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 02:12:06 -07:00
NeilandBen Grynhaus d1f04e6042 fix(terminal): a pane moved to a new tab stays moved on paired servers (#33027)
* test(e2e): a pane moved to a new tab on a paired server workspace stays moved

* fix(terminal): keep a pane moved to a new tab on paired runtimes

Moving a split pane to a new tab in a paired-runtime worktree changed only
the window store. The host never learned about the move, so the next host
snapshot rebuilt the old tab and the pane snapped back.

Add a session.tabs.movePaneToNewTab RPC that commits the move in the host
session through planTerminalLeafMove and republishes the session tabs.
For a mirrored host tab, the renderer applies the move first under the
mirrored id the host snapshot will use, then asks the host to commit it.
An older host or a refused move falls back to the old local-only move.

Fixes #32939

* fix(terminal): commit a host pane move through the existing leaf-move writer

The layout-writer ratchet allows no new main-process layout writers. The
headless host now hands the move to commitLeafMoveAndRekey, the same
commit a local window uses, and keeps only the window check, validation,
rehydrate and notify.

* fix(terminal): gate the host pane move on a host capability

An older host keeps today's window-only move under a local tab id instead of
a mirrored one it never confirms. Adds a terminal.list check to the e2e.

* test: drop type assertions from the pane-move tests

* fix(terminal): the host keeps a moved pane's place, focus and live terminal

After the host commits the move, the window gives it the drop position and
focus through the existing tab move and activate calls; a refusal redraws the
host's tabs. The host moves the live PTY's surface with its pane and checks the
target tab id. The move lives in its own runtime module.

* fix(terminal): hold a moved pane's drop order until the host has it

The host's snapshot of the commit goes out before its reply and appends the
tab, so the window records the drawn order as a reorder intent at the drop and
sends that order, and the focus read then, once the host answers.

* fix(terminal): route the moved tab's reorder to its owning host

The follow-up names the worktree's host instead of reading the active-server
setting (focus-read ratchet); the e2e narrows host rows to terminal tabs.

* fix(terminal): the host places a moved pane's tab in the move itself; a refusal reverts

The move carries the drop's group and index (optional; an older host appends)
and the host places and selects the tab before its one publish, replacing the
follow-up reorder and the drop-time order hold. A refused move closes the tab
this window drew without stopping its terminal and redraws the host's tabs even
when unchanged. E2e covers a same-group drop and a refusal; host unit tests cover
same-group and cross-group placement.

* fix(terminal): a refused pane move keeps its pane records; drop index in host order

The revert hands the pane's status and launch records back to the source tab
before closing the drawn tab. The host turns a projected client's drop index
into its raw order with translateProjectedSessionTabMove, as session.tabs.move does.

* fix(terminal): only an unknown drop group appends a moved pane's tab

The host catches only target_group_not_found and invalid_tab_order from the index
translation and rethrows anything else.

* fix(terminal): settle a pane move by what the host holds when its reply is lost

A lost reply is not a refusal: the window asks the host whether it holds the
pane in the new tab before undoing anything, and waits for the next snapshot
when it cannot ask. A move the host committed but this window could not draw
takes the host's tabs.

* fix(terminal): a lost transport on a pane move is unknown, not a refusal

runtimeEnvironments.call answers a dropped or overloaded transport with an error
envelope; those codes (the shared recoverable set) now ask the host instead of
undoing a move it may have committed.

* test(e2e): pane-move spec waits on real signals, not delays

The source tab is created on the server and split once its shell is listed, so
the split no longer races a desktop-seeded tab's first spawn (the CI failure).
The stay check follows output from the moved pane; the refusal check waits for
the drawn tab to appear and go.

* test(e2e): read the refused move's tab counts without Reflect (anti-slop)

* fix(terminal): a moved pane's tab joins the order the user had, not a rebuilt one

The host inserts the new tab into the group order captured before the commit,
appending without a drop position, so editors and pages keep their places. The
shared group-move fallback is no longer used here.

* fix(terminal): a moved pane's groups hold the host's current tabs, in the user's order

Placement takes membership from the rebuild after the commit and only the order
from before it, so a tab opened while the commit was pending stays (after the
user's tabs) and no stale id is written.

* fix(terminal): a moved pane's placement keeps a reorder made while it committed

The order is read after the commit, from the host's current tabs, not before it.

* fix(terminal): a moved pane keeps the lone group the user merged into

A rebuild names a single group with the default id; placement keeps the user's
id for it, so the drop position still applies after a split was merged back.

* fix: import error classification from its new shared/remote-runtime path

* fix(terminal): a pane or divider drag survives focus moving inside the window

The drag's window blur listener was registered in the capture phase, so it also
heard every element blur. A terminal attach or host snapshot that moved focus
between panes mid-gesture ended the drag; in the paired pane-move e2e on CI it
cancelled the drag before the drop. Only the window losing focus ends it now.

* test: drive the focus-change drag test through a real pane manager, without casts

* fix(terminal): a headless host moves a pane with its live terminal and never empties its source

The host names the PTY it holds for the pane, so a session copy an SSH respawn
left with an old id no longer refuses the move as a mismatch. A move that would
leave its source tab with no pane (a sibling closed meanwhile) is refused, since
no headless cleanup retires the emptied tab and it would publish as a phantom.
The e2e fences its stays-moved check on a later server rename instead of
sampling on a timer.

---------

Co-authored-by: Ben Grynhaus <ben.grynhaus@wiz.io>
2026-10-26 02:01:08 -07:00
Neil e6da9ca339 fix(terminal): answer queries in output a paused paired view discards (#33783)
* fix(terminal): answer queries in ACK-pending output a paused paired view discards

Refs #32944

* fix(terminal): capture yielded-query ownership at ingestion and cap reply age

Refs #32944

* fix(terminal): settle yielded queries by their own end seq across split frames

Refs #32944

* test: use a fixed timestamp in the yielded-query responder test

* test(cross-version-wire): stub yielded-query runtime methods on the host runtime

Refs #32944
2026-10-26 01:56:42 -07:00
Brynn Bendixenandbrynnclaw 963e8cc431 fix(preflight): detect Grok installed in ~/.grok/bin (#25324)
Grok's installer defaults to ~/.grok/bin and only symlinks into
~/.local/bin when that dir is already on PATH. A GUI-launched Orca never
looked in ~/.grok/bin, so the Agents page reported Grok as not installed.

Append ~/.grok/bin after ~/.vite-plus/bin in the three lists that must
stay in step: the packaged PATH seed, the system install-dir lookup
fallback, and the POSIX/WSL guest fallback prelude.

Fixes #17590

Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com>
2026-10-26 01:55:02 -07:00
OrcaWinandOrcaWin 351705bd35 test(vitest): node-runtime worker exits when Vitest's IPC channel closes (#33848)
A killed Vitest left its node-runtime worker running the rest of the file
(still alive after 150s). Exit on 'disconnect' with process.exit captured
before Vitest replaces it with a throwing guard.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 01:39:41 -07:00
OrcaWinandOrcaWin 7324dada30 perf(dev): −1.2 GB idle RSS per pnpm dev instance (Rolldown threads + mimalloc purge) (#33836)
* perf(dev): size the dev server's Rolldown runtime for many parallel instances

~93% of idle electron-vite RSS is Rolldown's native mimalloc arenas. The dev
wrapper now gives electron-vite MIMALLOC_PURGE_DELAY=0 and 4 Rolldown/Rayon
threads; a serve-only renderer plugin strips exactly those keys before
Electron spawns, so dev Orca's terminals never inherit them.

* fix(dev): add the runtime-env plugin only when the dev wrapper set its keys

Keeps createDevServeConfig returning the renderer config unchanged when there
is no port and nothing to strip, as electron-vite-output-contract pins.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 01:39:36 -07:00
Neil bf496c6e40 perf(orcad): retire an idle session scanner after a minute on host servers (#33845)
Only desktop requests reach a host's scanner child, which holds ~60 MB of
RSS even idle, and the 10-minute default kept it alive most of the time.
orcad now sets a 60 s idle timeout; the desktop keeps its default.
2026-10-26 01:30:57 -07:00
Neil 5d3ed61197 perf(wsl): relay orcad sockets through bash instead of a Node bridge (#33820)
Each desktop socket to a WSL host's orcad, and the liveness watch, ran a
Node process in the distro just to copy bytes (~42-50 MB RSS each). A bash
/dev/tcp relay does the same with bash and two cats (~4.5 MB). The Node
bridge stays as the fallback for hosts without bash 4.3+ or /dev/tcp and
for refused dials, so refusal and missing-runtime signals are unchanged.
SSH hosts keep the Node bridge.
2026-10-26 01:30:51 -07:00
Neilandoutof-place 8cdd07c12b fix(daemon): give each macOS resolver health probe a unique clientId (#33833)
Concurrent new-PTY resolver probes shared the 'resolver-health-check'
clientId, so the daemon evicted the older probe's control socket and that
probe waited out the 3s timeout before its terminal could spawn. Use a
per-probe UUID clientId and settle as 'unknown' as soon as the probe
socket closes.

Fixes #27751

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-26 01:20:18 -07:00
Neil adb1f59692 fix(terminal): repaint local TUIs over the hidden-output loss banner (#33835)
Local panes printed '[Orca skipped hidden terminal output because main
recovery was unavailable.]' inside idle Codex/Claude Code frames and it
stayed until a workspace swap, because the one-row redraw nudge from
#31482 only ran for remote PTYs. Differential TUIs never rewrite cells
they believe unchanged, so the banner row persisted. Local PTYs now get
the same nudge, restoring the row on a timer since local main sends no
desktop-fit confirmation.
2026-10-26 01:12:52 -07:00
OrcaWinandOrcaWin db6ab4bc0e test(vitest): give each run its own temp dir and remove it on exit (#33834)
Tests leak os.tmpdir() fixtures broadly (8.6k dirs from repeated prefixes on
one shared dev host; orca-runtime-rpc alone 2,729). run-vitest.mjs now points
TMPDIR/TEMP/TMP at a marked per-run dir, removes it after Vitest exits
(including on SIGINT/SIGTERM), and sweeps marked dirs whose launcher died.
On POSIX a root longer than 50 chars (macOS /var/folders) falls back to /tmp
so Unix socket paths stay under sun_path limits.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 01:06:44 -07:00
Brennan Benson c0714b9ce0 Fix Codex goal Stop and selected model settings (#33631)
* Fix Codex goal Stop and selected model settings

* Preserve settings evidence and captured Stop outcomes

* Preserve refused goal pauses and bound Stop retry diagnostics

* Use checked settings state in goal contract tests

* Narrow captured Stop child and type its timing fixture

* Coordinate Stop timing fixture with deferred phases

* Fix typed mobile warning icon assertion

* Align Stop tests with reconciled controls and owned shutdown

* Check integration attach parameters without a type cast

* Match restart offer close calls to optional observer contract
2026-10-26 01:01:19 -07:00