Commit Graph
13906 Commits
Author SHA1 Message Date
Jinwoo Hong f1d1a9b076 test(e2e): sample the delete dialog until it has enough frames (#28323)
* test(e2e): sample the delete dialog until it has a full frame floor

* test(e2e): drop the frame-count assertion the sampling loop now guarantees
2026-10-13 10:30:37 -04:00
Neil 41e6ea530a feat(wsl): accounts shim for agents on a WSL orcad host (WSL-via-orcad C9) (#27874)
* feat(wsl): accounts shim for agents on a WSL orcad host (WSL-via-orcad C9)

The desktop prepares the selected Claude/Codex account's in-distro home with the
existing WSL account code and sends it as env on terminal.create /
session.tabs.createTerminal, or as agent.launch's new optional accountEnv.
Structured sessions keep their host-derived home and warn. Launch-time CLI
resolution inside a WSL guest skips /mnt/<drive> shims.

* refactor(wsl): track WSL host environments beside their registry
2026-10-13 07:23:53 -07:00
Neil fc7dff8ce1 ci(wsl): real WSL2 lane for WSL via orcad (C10) (#27921)
* ci(wsl): real WSL2 lane for orcad deploy, bridge, liveness and holder (WSL-via-orcad C10)

* ci(wsl): upload the template's dot-directories; save the rootfs cache on failure

* ci(wsl): update the runner's WSL to 3.0.1+ before asserting WSLInterop survives

* test(wsl): let a released holder settle before asserting it exited

* ci(wsl): install a pinned, cached WSL 3.0.1 MSI instead of wsl --update

* test(wsl): keep the lane's survival seconds typed in its assertion message
2026-10-13 07:09:02 -07:00
Jinwoo Hong aa7afabb1d test(e2e): wait for the paired-reveal decoy to settle at its new size (#28319)
* test(e2e): read the parked-reveal decoy grid only after it settles at the new fit

* test(e2e): name the settle wait and give it the file's reveal timeout
2026-10-13 10:00:18 -04:00
Neil 4280eb118c feat(wsl): liveness, failure classification and recovery for WSL orcad (WSL-via-orcad C6) (#27916)
* feat(wsl): liveness, failure classification and recovery for the WSL orcad connection (WSL-via-orcad C6)

* fix(wsl): a user connect supersedes liveness recovery; report a stop once

* chore(wsl): exhaustive terminal verdict switch; typed test state
2026-10-13 06:52:35 -07:00
Jinwoo Hong 7cf6f0a281 test(e2e): probe the delete dialog's confirm button, not the force-delete menu chevron (#28315) 2026-10-13 09:27:31 -04:00
OrcaWinandm4air c90f4fb435 fix(linux): unpack the AppImage copy in the background so the first daemon runs from it (#28311)
* fix(linux): unpack the AppImage copy in the background so the first daemon runs from it

A validated AppImage now extracts its generation in the background, at the
lowest CPU and I/O priority and under the registration lock, at a launch that
finds no copy for its file and when an update finishes downloading (into the
namespace and generation key the installed file will have). The copy is staged
without publishing the CLI launcher. A daemon about to be launched while this
launch is unpacking waits up to 8s for it, then runs from the copy instead of a
FUSE mount it would outlive. A full cache, noexec cache, untrusted download or
failure is logged and the launch keeps today's fallback.

* fix(linux): drop idle copies of earlier releases at launch

Staging never prunes, so a desktop that never registers the CLI would keep
every release's unpacked copy. At launch, once this release has its copy, idle
sibling generations in its namespace are pruned under the registration lock;
leases, residency and the installed CLI target still protect anything in use.

* fix(linux): leave serve's own first-start unpack and its progress in place

Serve already unpacks the copy itself with one deadline and progress on its
output (D3-D2), which the packaged shutdown oracle checks. Launch-time
pre-extraction now runs for the desktop only; serve still gets the
update-downloaded staging.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 06:23:25 -07:00
Neil b978bc4dc2 feat(wsl): connect to a WSL distro's orcad over wsl.exe stdio only (WSL-via-orcad C5) (#27834) 2026-10-13 06:13:03 -07:00
Neil 2bb02f062d [CI] Reuse Windows resolver imports and retire unused helper tests (#28296)
* [CI] Retire the weak local title-corpus comparison

* [CI] Retire tests for seven unconsumed helper modules

* [CI] Reset the Windows launch resolver graph once per group
2026-10-13 06:07:28 -07:00
OrcaWinandm4air e15b77aba3 fix(daemon): a stop requested from outside never counts as a crash (F3) (#28307)
When the daemon gets SIGTERM or SIGINT it now durably marks its restore
marker as stopped before the async teardown starts. A systemd scope stop
signals the daemon and its AppImage mount helper together, so the teardown
can die with SIGBUS before it writes clean-exit; that left the marker at
running and the next start paused automatic restores for a crash that never
happened. A real crash (no signal handler run) still leaves running and still
pauses in the same boot.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 05:50:40 -07:00
github-actions[bot] e439e3850f Update README downloads badge 2026-10-13 12:44:20 +00:00
Neil 0d9cecadb9 perf(wsl): skip re-hashing unchanged orcad artifacts and guest Node runtime on the WSL wake path (C4c) (#27941)
* perf(wsl): skip re-hashing unchanged orcad artifacts and the guest Node runtime on the wake path

materializeOrcadArtifact now reads each template file once (manifest check and slot identity
in one pass) and remembers the digests in <cacheRoot>/<target>/.verified-sources.json keyed
by each file's device, inode, size, mtime and ctime; any change re-hashes. WSL deploys probe
the guest runtime against a recorded stat signature beside .verified, hashing only on
mismatch. SSH probe commands are unchanged.

* fix(orcad): trust the artifact verification record only on the WSL wake path

SSH deploy and local serve hashed every launch before; a record anyone
with userData access could edit must not let them skip that. Only the
WSL deploy opts in, and untrusted callers neither read nor write it.

* fix(orcad): reject a browser named like a slot file; skip signatures when untrusted

A browser digest keyed like orcad.js replaced the common digest it must also match; callers that keep no record no longer stat every source.
2026-10-13 05:42:07 -07:00
OrcaWinandm4air 5e09488911 fix(terminal-daemon): status says live, exited or unverifiable, and shows the process ceiling (#28239)
* fix(terminal-daemon): status reports live, exited or unverifiable, and the process ceiling

`orca terminal-daemon status` printed 'Terminal daemon: OK.' whenever no severed daemon was
recorded, including the ~60 s after a kill -9 before the next terminal respawned it. The host
now probes the daemon (health check, then its pid record with Linux start-time identity) and
returns an additive `daemon` report; the CLI prints the verdict and, for a live daemon, the
terminal process ceiling, which no CLI command showed under Electron serve.

Fixes BUG-5 and BUG-7 from the real-host Linux test run.

* fix(terminal-daemon): load the ceiling description from shared so the packaged CLI can resolve it

The packaged CLI cannot load out/main/daemon modules: electron-vite replaces out/main after the
CLI build. The ceiling state and its description move to src/shared, which the CLI already ships.

* fix(terminal-daemon): a pid the signal proved live is never exited because procfs hides it

* fix(terminal-daemon): load the liveness probe lazily so the RPC table stays light

Importing the probe eagerly pulled the daemon provider graph into every module that loads the
runtime RPC method table, which broke the cross-version terminal wire harness.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 05:21:49 -07:00
OrcaWinandm4air b724e3a24d fix(linux): a supervised AppImage serve follows a replaced AppImage (#28244)
* fix(linux): a supervised AppImage serve restarts from a replaced AppImage

Swapping the AppImage file never reached a supervised serve: it runs the copy it unpacked, and
even a full service restart went back through the stable launcher to that same copy. The
extraction cache now records which AppImage each namespace came from. Before each start the
supervisor compares that file's identity with the build it runs; once a settled new file is
there and runs on this host, it execs the new AppImage with its own arguments (same pid), whose
serve unpacks the new build and re-points the stable launcher.

Fixes BUG-4 from the real-host Linux test run.

* fix(linux): try a replaced AppImage once, and let it past an old build's give-up

- A give-up recorded against the old build no longer stops the supervisor before it checks
  for a replaced AppImage.
- The supervisor records the AppImage identity it is about to exec in the profile. If that
  build dies before its own crash brake, later starts of the old build keep running it
  instead of exec'ing the same broken file until systemd's start limit disables the service.
  A supervisor running that build, a further replacement, or --force clears the record.

* test(cli): compare the namespace listing order-independently

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 05:12:18 -07:00
OrcaWinandm4air 97fac546df fix(linux): a supervised serve run from the AppImage stays in place instead of re-exec'ing (#28270)
Since a direct `Orca.AppImage serve --supervise` now runs the CLI supervisor (#28227), the
supervisor's relocation re-exec ran from the AppImage mount. An exec from node mode closes every
inherited descriptor, including the AppImage runtime's keepalive pipe, so the runtime unmounted
the AppImage during the exec and the new image failed with 'libffmpeg.so: cannot open shared
object file' (exit 127) on every start. Relocation exists so an update cannot swap the app under
a running supervisor; an AppImage's mount cannot change during the run, so it stays in place.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 05:12:13 -07:00
OrcaWinandm4air a10ca391ff fix(ci): restore the single Codex capacity replay entry (#28301)
#28295 and #28297 each removed one of the two duplicate entries, leaving none, so shard 5 fails
again (expected 0, got 12). Re-add exactly one.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 04:49:46 -07:00
OrcaWinandm4air 38a4958cad feat(linux): run the AppImage terminal daemon off the mount, on the extracted copy's bundled Node (#28214)
On a validated AppImage the desktop's daemon launch first runs <generation>/resources/node-runtime/bin/node
on the generation's daemon-entry.js when the extracted copy for the file at $APPIMAGE is complete, carries
the bundled Node and the entry, and is the running release. It then falls back to the AppImage's own mount
and the current mount, logging every fallback. The copy rung records $APPIMAGE/<entry> like the own-mount
rung, so either daemon is adopted. Generation leases recognize the bundled Node. macOS, Windows, deb and
rpm never reach it.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 04:34:25 -07:00
Neil e09d732d17 perf(wsl): pooled wsl.exe command loops and orcad compile cache on the WSL wake path (C4 follow-up) (#27923)
* perf(wsl): run stdin-free probes over pooled wsl.exe command loops; cache orcad's compiled bundle

The WSL wake path made ~37 sequential wsl.exe starts at ~180 ms each. Stdin-free
execCommand calls now go through a few long-lived wsl.exe sh loops (one command at a
time per loop, own session, stdin at EOF, base64-framed output). SSH has no such
method, so its commands and options are unchanged.

orcad enables Node's compile cache inside a client-managed slot, and hands it to the
profile preflight child, which compiles the same bundle.

* fix(orcad): share the slot compile cache with the preflight only in a managed slot

An unmanaged orcad started with its own NODE_COMPILE_CACHE kept that
location for its preflight before; never redirect it into the install dir.
2026-10-13 04:27:48 -07:00
OrcaWinandm4air 121386908b fix(ci): drop the duplicate Codex capacity replay entry (#28297)
#28286 and fba7b753ec both recorded the same capture; the duplicate key fails typecheck and lint.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 04:04:14 -07:00
OrcaWinandm4air d0b659604c fix(ci): drop the duplicate Codex capacity replay baseline entry (#28295)
#28192 and #28286 both recorded 'codex-model-capacity-fullscreen' with the same count, and the
duplicate object key fails typecheck (TS1117) on main.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 03:53:06 -07:00
OrcaWinandm4air 4dcd0b95c8 fix(ci): record the Codex capacity capture's known serializer divergence (#28286)
#28231 added the codex-model-capacity-fullscreen PTY capture without an entry in the replay
test's known-divergence table, so every PR's test shard fails on main (expected 0, got 12).
The serializer is untouched; the divergence is the same restore limitation the table records.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 03:42:08 -07:00
Neil fba7b753ec Cache mobile typechecks and overlap CI setup (#28192)
* ci: run mobile runtime test groups on separate runners

* ci: use a lightweight runner for the mobile result gate

* ci: distribute Bun tests across both mobile runners

* ci: reuse mobile compiler state without adding runner queues

* test: verify eviction of source variants in one cache bucket

* test: baseline existing serializer limits in the capacity capture
2026-10-13 03:35:51 -07:00
Neil 2cbb71963c fix(ssh): show managed hosts once in the connection menu (#28277)
* fix(ssh): show managed hosts once in the connection menu

* fix(ssh): name the merged host row after its SSH host in the status menu
2026-10-13 03:11:24 -07:00
Neil 3a7ec7dff1 perf: reuse verified Node and run the layout check with Bun (#28218)
* perf: overlap preflight daemon smoke and reuse verified Node executable

* Keep measured Node reuse and Bun layout wins; drop smoke scheduling experiments
2026-10-13 02:58:56 -07:00
Jinwoo Hong b589bb3cc9 refactor(runtime): main alone starts setup and default tabs for an activated create (#28153)
* refactor(runtime): main alone starts setup and default tabs for an activated create

An activated CLI or paired create with a window open handed setup and default
tabs to the host window, and with navigation 'all' to paired clients too, so
both could run setup. Main now provisions them itself. Only when main tried to
start setup and failed does it hand setup to the host window, which retries it
where its output or spawn error is visible.

* fix(runtime): hand the window the whole create when the agent fails to start

Main provisioned setup and default tabs after a failed agent start and sent the
window only the startup. The window found tabs, seeded nothing, and the agent
never launched. A failed agent start now provisions nothing and hands startup,
setup and default tabs to the host window, as before this PR.
2026-10-13 05:51:06 -04:00
Neil 4857afde79 fix(ci): route the worktree ready toast's host check by its owner row (#28265)
The ready toast added in #28238 read the Active Server setting through
getKnownExecutionHostIdForWorktree, which the focus-read ratchet rejects,
so every PR's static-analysis job failed on main.
2026-10-13 02:24:27 -07:00
Neil 9e52645e6c Show Codex model capacity failures as red agent status (#28231)
* Show Codex model capacity failures in agent status

* Reduce Codex capacity detection work on terminal output

* Preserve Codex capacity notices across partial terminal frames
2026-10-13 01:58:00 -07:00
OrcaWinandOrca Worker 4559c250b3 fix(windows): restrict secure files in-process instead of spawning icacls (#28135)
* fix(windows): restrict secure files in-process instead of spawning icacls

Every secure write on Windows spawned icacls.exe five times on the calling
thread (the Electron main thread for most stores): verify, /reset,
/inheritance:r /grant:r, verify, verify. Process creation under endpoint
security costs ~0.6 s each, so each write froze the UI for seconds (#26027).
The /reset + /inheritance:r pair is also what behavioural EDR scores as
ransomware tradecraft (#25583).

Add native/windows-security (@orca/windows-security): a small N-API addon
over advapi32 that reads and writes DACLs in-process. It exposes the token
user SID, a DACL read as SDDL, a DACL write (sync and on the thread pool),
a create-with-DACL file write, and an additive grant. Policy and
verification stay in TypeScript.

- writeSecureFile creates each temp file already carrying the protected
  user/SYSTEM/Administrators DACL (CreateFileW + SECURITY_ATTRIBUTES), reads
  it back once, and renames it. No ACL is modified on the write path and no
  process starts. Before: 5-7 spawns, 94-138 ms per write. After: 0 spawns,
  ~0.5 ms.
- A secure directory is verified once per process. It is rewritten only
  when verification fails, on the thread pool, because the write walks
  every descendant (~2 s on a 29k-entry userData).
- The verifier follows OpenSSH's rule: only the user, SYSTEM and
  Administrators may be granted anything, and the path must be protected
  (or, for a file, inherit from a secure parent). DACLs written by the
  icacls-era hardening pass unchanged, so there is no migration.
- If the addon cannot load, the write still happens and reports
  unrestricted, logged once. There is no icacls or PowerShell fallback.
- grantDirAcl, the startup userData grant, and the install-dir probe and
  package repair use the same addon, so whoami.exe and icacls.exe are no
  longer spawned anywhere at runtime.
- orcad's Windows slots ship the addon beside their bundles (built per
  arch, PE-machine checked). Its data-root privacy check fails closed, so
  without the addon a Windows orcad would not start.

Fixes #26027
Fixes #25583

* refactor(secure-file): harden existing Windows files through the sync lane

The read path called restrictWindowsPathSync directly and recorded success
itself; the existing sync lane already does both. One call site fewer.

* refactor(windows-security): one load, one rule, no fallthrough (review #28135)

- The descriptor parser is anchored, so a conditional ACE (its body holds
  parentheses) or anything else it cannot read fails closed instead of
  verifying the ACEs before it.
- findSecureDaclViolation is one flat rule: protected, allow rules only for
  the user, SYSTEM and Administrators (OpenSSH's ACE rule), and full
  control for the user. The inherits-from-a-secure-parent exception is gone:
  it accepted exactly what loosening the parent reaches.
- The addon and the user SID load once, behind one wrapper that adds the
  extended-length prefix to every path and runs async DACL writes to one
  path in order, so a startup grant cannot land after a re-lock and restore
  the broader DACL.
- With the addon loaded, a failed born-restricted create throws with the
  matching Node error code instead of falling back to a plain write.
- A grant leaves a NULL DACL untouched instead of turning 'everyone' into
  'only this SID'. WriteFile runs once and fails on a short write.
- The artifact create-intent store writes through writeSecureFile and drops
  its own temp writer, directory LRU and synchronous directory re-lock.
- Test seams the global fake makes redundant are gone.

* fix(packaging): fail a Windows build whose workspace addon binary is missing or foreign-arch

The @orca/windows-* workspace links exist on every host, so their presence
proved nothing: a missing or wrong-architecture .node only surfaced at
runtime, as unrestricted secure files or an orcad that refuses to start.
beforePack now reads each addon's PE machine against the target arch.

* refactor(windows-security): prune what the native ACL left dead (review #28135)

- Sync-spawn ratchet: hardenSecurePath and the sync-flag exemption it alone
  used are gone, and the advice and baseline header no longer say secure
  writers run icacls.
- The install-dir probe reads ACEs through parseSddlDacl, so an ACE it
  cannot parse fails the whole reading closed instead of being skipped; AC
  is a resolved alias there now.
- The packaging check reads the addon binary through node_modules, the copy
  that ships.
- No winCode-to-errno table: nothing reads .code off a failed secure write.
- The load memo is not mutated; secure-path keeps its own log-once flag.
- grantInstallDirPackageAcl is a plain function, and secure-file restricts
  a Windows directory and a POSIX path directly instead of through one
  two-platform helper.

* fix(windows-security): resolve LA in real-ACL tests; tear a file whose close fails

- The GitHub Windows runner is the built-in Administrator (RID 500), whose
  SID reads back as LA. Production already resolves it through
  localDomainSidOf; the win32 test helpers parsed without it. One shared
  readDaclOf resolves aliases for every real-ACL suite, and the verifier's
  unit test covers an LA-aliased directory and LA as a stranger.
- createFileWithDacl treats a failed CloseHandle like a failed write (lost
  data on a network volume) and deletes the torn file.
- Drop a duplicate test reset and a typo.

* fix(windows-security): load only from inside the app; read DACLs as structure (review #28135)

- Loader: orcad's staged binary first, then the workspace package only if
  its real path is inside the app (process.resourcesPath, or this
  checkout). A bare specifier otherwise walks every parent up to
  C:\node_modules, which any local user may create, and orcad holds
  credentials.
- The addon reads a DACL as { protected, aces: [{ type, flags, mask, sid }] }
  via GetAce, with a SID only for plain allow/deny ACEs and null for a NULL
  DACL. findSecureDaclViolation and the install-dir probe check that
  structure, so conditional, callback and object ACEs fail closed. The SDDL
  parser, its alias table, LA/localDomainSid resolution and getDaclSddl are
  gone; SDDL is only the write format.
- Install-dir tree pass: files flagless as before, but a directory only when
  its own DACL is protected (inheritably). Re-granting inheriting
  directories re-propagated each subtree (3.2 s for 1,093 directories). The
  root is no longer granted, or counted, twice. The two passes are plain
  functions behind a { root, tree } seam.
- One namespacing (path.win32.toNamespacedPath) at the addon boundary, also
  the per-path ordering key; the comment states the real sync-grant
  invariant.
- restrictWindowsDirectory(dir): Promise<boolean> replaces the callback
  lane; the reporter is guarded once, so the 'settle' stage is gone.
- Sync-spawn ratchet: the secure writers no longer spawn or block, so they
  leave the gate (109 -> 61 uses).
- Errors name the Win32 call and code only; a failed
  GetSecurityDescriptorControl fails the write instead of defaulting to
  unprotected.

* test(secure-file): assert the durable POSIX write's outcome, not the old chmod order

writeSecureFile now chmods the temp file to 0o600 before fsyncing it, so
the fsync also covers the mode change and the file is owner-writable when
opened. Assert what matters under umask 0o200: the write succeeds, the
temp file is fsynced read-only, and the published file is exactly 0o600.

* fix(windows-security): namespace paths with the host's toNamespacedPath

path.win32.toNamespacedPath rewrote POSIX temp paths (/tmp/x -> \tmp\x) in the
Linux runs of the Windows-logic unit tests, so the fake addon wrote to the wrong
place. The addon only runs on Windows, where the host function is the win32 one;
elsewhere it is the identity. The long-path assertion runs on Windows only.

* test(windows-security): assert the install-dir long-path prefix on Windows only

The prefix comes from the host's toNamespacedPath, which is the identity off
Windows; the Linux run of this suite expected the win32 escape.

* fix(windows-user-data-acl): grant the root even when its children cannot be listed (review #28135)

A readdir failure on userData aborted the whole grant, so the root grant
that could repair a DACL refusing the listing was never attempted. The
listing failure is now recorded, the root is still granted, and the
marker stays withheld so the next launch retries.

* test(windows-security): wait for relock propagation, accept Entra ID SIDs (review #28135)

- The large-relock test waited only for the parent to turn protected,
  which happens before propagation reaches the children, then read a child.
  It now waits on the parent and both ends of the child range.
- The token-user test rejected S-1-12-1 (Entra ID) accounts, failing the
  suite on Entra-joined dev machines.

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
2026-10-13 01:56:55 -07:00
Neil 7246a0e269 Fix delayed agent launches such as sleep 30 && claude (#28205)
* fix(terminal): preserve preparation and discovery for delayed agent launches

* refactor(agents): centralize launch intent recognition

* refactor(agents): keep launch intent in one module apart from process recognition

Move recognizeAgentLaunchCommand next to the sleep-prefix scanner so the strict
process-table matcher is untouched, name the module away from the agent-launch
funnel files, share one executable-name normalizer, and colocate the
preparation tests with their modules.
2026-10-13 01:55:18 -07:00
OrcaWinandm4air acea005ed8 fix(linux): a server run from an extracted AppImage registers the stable launcher (#28241)
A supervised serve started through the stable launcher runs from one extracted generation with
no $APPIMAGE. Its CLI registration then refused Orca's own ~/.local/bin/orca-ide (a link to
the stable launcher) as a non-Orca command, and pointed the bare `orca` dispatcher at the
generation's launcher, which a later update prunes. Both now resolve to the stable launcher.

Fixes BUG-8 from the real-host Linux test run.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 01:55:07 -07:00
Jinwoo Hong aceebea0a4 fix(terminal): name a new tab's first pane so its saved layout is never empty (#28168)
* fix(terminal): name a new tab's first pane so its saved layout is never empty

createTab now always mints the first leaf id, so the window never saves a
terminal tab with an empty layout root. With no empty roots coming from the
window, main's save-time swap that kept its own root over an empty window
root (from #1909) has nothing left to guard, and is deleted.

* test(persistence): an empty-root layout from an old session still loads and gets its pane

* fix(persistence): name an old session's empty layout root once at load

A session saved before tabs named their first pane can hold an unmounted tab
with an empty root. If main bound a terminal there, the window's next save of
that tab dropped the binding once the save-time swap was gone. Name the pane at
load instead (the same pane the window would mount), so no save carries an
empty root. The rootless-pane resolver moves to shared so main and the window
pick the same pane.

* test(persistence): name the bind-then-stale-write order the load repair covers

* fix(persistence): name an old empty tab's pane with the stable headless leaf id

The load repair fell back to a random id, so an unsaved headless serve gave a
phone a new tab::leaf id on every restart. Use deriveHeadlessLegacyTerminalLeafId,
which phones already saw for these tabs. Also import the rootless resolver from
shared directly and return the loaded state unchanged when nothing needs repair.
2026-10-13 04:48:20 -04:00
OrcaWinandm4air 5929350944 fix(linux): direct AppImage serve honours the chosen profile and --supervise (#28227)
* fix(linux): run a direct AppImage serve through the CLI so it keeps its profile and supervisor

A direct `Orca.AppImage serve` stayed in the Electron process and skipped the CLI's serve
front end, so it ignored ORCA_USER_DATA_PATH and silently dropped --supervise. It now execs
into the bundled CLI (same pid, so service managers and signals still reach it), translating a
leading --user-data-dir into ORCA_USER_DATA_PATH. Also lists terminal-daemon and reference as
CLI commands so a direct binary launch of them reaches the CLI.

Fixes BUG-1, BUG-3 and BUG-10 from the real-host Linux test run.

* fix(linux): drop desktop switches anywhere in a direct serve launch

* fix(linux): keep a direct serve's --no-sandbox for the Electron server the CLI starts

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 01:45:54 -07:00
Neil 8cd5bb2a74 feat(wsl): deploy and launch orcad inside a WSL distro (WSL-via-orcad C4) (#27819)
* feat(wsl): deploy and launch orcad inside a WSL distro (WSL-via-orcad C4)

* fix(wsl): keep the install-dir fallback on the PATH detection searched, so a /mnt/c shim cannot re-enter

* fix(wsl): call the install-dir resolver exactly as before when no PATH is given

* fix(wsl): import orcad artifacts from their new orcad/ home

* fix(wsl): adopt an orcad serving in the distro that the activation record does not name

* fix(wsl): filter /mnt/<drive> PATH entries only in an orcad launched as a WSL host

SSH-managed orcad inside a distro and Orca under WSLg kept detecting
drive-mounted CLIs before this stack; the setsid launch now marks itself
with ORCA_WSL_ORCAD_HOST=1 and only that process filters.

* fix(wsl): keep the install-dir fallback on the process PATH outside a WSL host orcad

On Windows the preflight env merges the persisted registry Path, which
the fallback never searched before; only the marked WSL host runtime
now passes a filtered PATH.
2026-10-13 01:29:19 -07:00
OrcaWinandm4air bc519c57fa fix(serve): say what headless serve actually needs, and stop repeating the supervisor's restart line (#28230)
- A headless serve with no X display told the user to run `orca-ide serve`, which they just
  ran. Serve now gets its own message: it needs an X display, Wayland alone is not enough, and
  which X virtual framebuffer package to install (now including Arch's xorg-server-xvfb).
- The supervisor's restart line read 'Orca serve Orca serve exited via SIGKILL.; restarting'.
- The supervisor and 'serve service status' gave different advice after giving up; both now
  give the same, correct advice.

Fixes BUG-2 and BUG-9 from the real-host Linux test run.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 01:28:02 -07:00
Neil 93e66e1f0e Close worktree ready notification when its workspace opens (#28238)
* fix: dismiss worktree ready toast when its workspace opens

* fix: keep ready toast bound to its host and settled navigation

* fix: project ready notification ownership for paired hosts

* fix: retain captured host for legacy ready notifications
2026-10-13 01:09:51 -07:00
OrcaWinandm4air 1b9a408b8c test(daemon): a Node-hosted launcher keeps a busy Electron-hosted daemon and its terminals (#28211)
* test(daemon): a Node-hosted launcher keeps a busy Electron-hosted daemon and its terminals

Runs the desktop daemon launcher under Electron (ELECTRON_RUN_AS_NODE), opens a terminal on the
daemon it starts, then relaunches the launcher on plain Node at the same and at a newer version.
The busy Electron daemon is adopted as a normal target with its shell intact, and only after it
retires on its own does a Node daemon take the endpoint. Linux only.

* test(daemon): stop every launcher a failed adoption test leaves running

Share the launcher window and session harness through the fixture, track each launcher child,
kill it if its startup line never arrives, bound quit, and close any left open in afterEach.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 00:42:38 -07:00
OrcaWinandm4air 49a1129aa6 build(linux): carry the pinned Node inside the AppImage so serve's slot works offline (#28204)
* build(linux): carry the pinned Node inside the AppImage so orca serve's slot works offline

Linux packaging places the pinned glibc Node at resources/node-runtime/bin/node before the
glibc-floor gate, proves it serves one PTY with the packaged daemon entry, and deb/rpm exclude
it through fpm. orca serve's orcad slot copies that Node (hash-checked) instead of downloading.

* test(serve): type the bundled Node fixture

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 00:39:39 -07:00
e9285f0f58 fix(floating-workspace): open the floating panel instead of blanking the main window on host reveals (#28184)
* fix(floating-workspace): reveal workspaces where they live instead of selecting the floating one

Every renderer path that takes the user to a workspace hand-wrote the main-window
selection sequence, so a floating workspace id (terminal switch, CLI focus, agent
launch, notification and mobile reveals, terminal handle links) became the main
window's selection and blanked it while the floating panel stayed closed.

revealWorkspaceSurface is now the one way to show a workspace: the floating
workspace opens its panel and leaves the main window alone, any other workspace
becomes the main window's selection and a visit. selectWorkspaceSurfaceOwner is
its non-navigating twin for tabs opening beside the user. The ad-hoc floating
checks in worktree activation, http links, the editor close queue, Activity and
open-terminal-beside-tab now go through the same module.

Co-authored-by: Velm14 <10477408+Velm14@users.noreply.github.com>

* fix(notifications): bind clicks for floating and folder workspace terminals

A terminal notification only bound its click when the worktree id carried a
repo ("repoId::path"), so floating-workspace and folder-workspace terminal
notifications did nothing when clicked. ui:focusTerminal now reveals any
workspace where it lives, so the click binds whenever there is a pane to focus
and ui:activateWorktree is sent only when a repo exists.

Co-authored-by: YuriNachos <19365375+YuriNachos@users.noreply.github.com>

* refactor(floating-workspace): tighten the workspace surface reveal

Move the floating-owned check into floating-workspace-panel-reveal as
revealFloatingWorkspacePanelFor so worktree activation no longer depends on
workspace-surface-reveal, rename selectWorkspaceSurfaceOwner to
selectWorkspaceSurface with a named state type, reuse the panel visibility
selector, and flatten the IPC bridges' surface-owner branches.

Co-authored-by: Velm14 <10477408+Velm14@users.noreply.github.com>

* fix(floating-workspace): leave the floating setting alone before settings hydrate

Host reveals (CLI focus, mobile, notification clicks) can arrive before
settings load; re-enabling the floating feature then would overwrite a
saved `false`. Unhydrated settings now skip the reveal.

Co-authored-by: Velm14 <10477408+Velm14@users.noreply.github.com>

* refactor(floating-workspace): drop extra reveal concepts

Co-authored-by: Velm14 <10477408+Velm14@users.noreply.github.com>

* fix(floating-workspace): keep main's setActiveWorktree call shape for plain reveals

Co-authored-by: Velm14 <10477408+Velm14@users.noreply.github.com>

---------

Co-authored-by: Velm14 <10477408+Velm14@users.noreply.github.com>
Co-authored-by: YuriNachos <19365375+YuriNachos@users.noreply.github.com>
2026-10-13 03:33:11 -04:00
Brennan Benson e2751d4318 After a restart, an agent tab asks the terminal host what is running, never "Couldn't confirm the agent started" (#28043)
* fix(agent-launch): after a restart a launch pane is an ordinary pane, never "couldn't confirm"

A launch pane's spawn read the launch record (and the tab's saved outcome) when no launch was
running for it, so a row left pending by a quit showed "Couldn't confirm the agent started." The
record never observes the process; the terminal host does. With no launch running in this process
the pane now spawns exactly like any tab: a live agent reattaches, an exited or absent one gives a
fresh shell, and a gone daemon shows the normal unavailable state.

- the running launch tells its pane how it ended in memory (finish carries the verdict); only a
  definite failure says "couldn't start", an unknown outcome leaves an ordinary pane
- deleted: agentLaunchPaneVerdictFromRecord, listAgentSessionOperationRowsOwningPane, the
  `unconfirmed` verdict and its notice string, the tab's persisted launch pane, ownedPane writes
- rows written by an older build that carry ownedPane are ignored; they expire with the row

* test(agent-launch): the restart pane test joins the attach suite it shares mocks with

* fix(agent-launch): a launch pane whose agent couldn't start keeps its notice for the session and never spawns a shell under it; a reload saves only a pending launch

* test(agent-launch): drop assertions on code that is gone, and the taking-back case the IPC suite already pins

* fix(agent-launch): narrow the finished-pane check, and test the saved session's launch pane with a typed tab

* fix(agent-launch): a launch whose outcome is unknown still says "Couldn't confirm the agent started" for the session, and attaches its agent if it turns up

* fix(agent-launch): main keeps a failed or unknown launch's answer for its pane until it quits, so the pane never spawns a shell under its notice; the window's spawn gate goes

* fix(agent-launch): a failure kept for a pane goes when the pane is closed during its launch, moved to another tab, or its workspace is removed; comments say what an unknown outcome and a reload now do
2026-10-13 00:31:12 -07:00
Brennan Benson f84451842d feat(settings): move Permissions for new chats into the Chat page's Behavior section (#28212)
The new-chat permission default sat alone above Appearance with its own header.
It is a behaviour choice, so it now renders as the first row of the Behavior
card, laid out like the rows already there. Its search entry and section id are
unchanged, so search and deep links still land on it.
2026-10-13 00:24:16 -07:00
OrcaWinandm4air 8e4e7be869 feat(daemon): pace automatic terminal restores on the desktop too (#28202)
* feat(daemon): pace automatic terminal restores on the desktop too

The desktop daemon now enforces the restore budget that orca serve and orcad
already enforce: the visible pane first, at most 3 automatic restores at once
(1/s), at most 8 live per machine, and the rest stay sleeping until opened.
ORCA_TERMINAL_SPAWN_ADMISSION=observe rolls newly launched daemons back to
count-only.

* fix(daemon): never put a user's own resume back to sleep; keep every refused old-client restore

A user-resume past the per-client allowance is still paced as automatic work
but is no longer deferred for a pause, the live cap or its deadline, so a visible
pane is never put back to sleep in front of the user. The legacy restore record
holds as many refusals as the host could run.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 00:18:08 -07:00
NeilandSamuel Vila f118137dd3 chore(editor): credit earlier close and selection fix (#28063)
Samuel Vila (@SamuelAdigos) independently submitted both editor guards
and regression tests in #28063 before #28120 was opened. The narrower
implementation landed in #28120; this follow-up records credit for his
earlier contribution.

Co-authored-by: Samuel Vila <svila.smr@gmail.com>
2026-10-13 00:05:25 -07:00
Neilandm4air 687190e9f1 fix(ssh): let existing profiles migrate without losing client history (#28141)
* fix(ssh): migrate released profiles with retained client state

* fix(ssh): reuse the shared adoption rule when the local and host copies overlap

The host copy replaces the older local one only where it holds tabs, the
catalog places the workspace on that host, no other host claims it, no
worker fence or close record disagrees, and local drafts are kept. Elsewhere
both copies export and must agree, as on main.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 00:04:25 -07:00
Neil 099bb76501 feat(wsl): detached distro holder re-adopted from a pid file (WSL-via-orcad C3) (#27800)
* feat(wsl): detached distro holder re-adopted from a pid file (WSL-via-orcad C3)

* fix(wsl): observe an early holder exit from spawn, not after the record write

* fix(wsl): release polls through a mid-exit unverifiable read until the holder's exit is proven
2026-10-12 23:59:13 -07:00
Jinwoo Hong d31f37c2dd chore(session): delete three session paths nothing calls any more (#28152)
* chore(session): delete three session paths nothing calls any more

- session:set-sync IPC (bridge, type member, web adapter stub); quit uses
  app:stage-before-unload-sync
- the session-write persist gate (shouldSchedulePersist /
  subscribeToPersistGateOpen); the one production subscriber passes neither
- reconcileDeadSessions and the binding's reconcileIfSessionDead; the live
  reconcileIfSessionMissing path stays

Tests that drove these are retargeted to the live paths or removed.

* chore(session): name shouldPersistWorkspaceSession in the deferral comment
2026-10-13 02:52:09 -04:00
Brennan Benson f0ccfcc0d3 fix(native-chat): seed the chat permission default from Claude's and Codex's own arguments (#28100)
* fix(native-chat): seed the chat permission default from the Yolo/Manual toggle as it shows

The one-time copy into Settings -> Chat -> Permissions gave Full access only
when every agent's arguments were exactly the bypass flag, so a profile the
toggle shows as Yolo (agents set differently, or an extra flag) got Ask.
Follow the toggle: Manual seeds Ask, anything it shows as Yolo seeds Full access.

* fix(native-chat): seed the chat permission default from Claude's and Codex's own arguments

The Yolo/Manual toggle has no saved value: it summarises every agent's arguments
and shows Yolo for any mix, including after Manual when another agent keeps custom
arguments. Seeding from it would grant Full access to people who chose Manual.
Read what Claude and Codex chats checked before they had modes instead: Full
access when both launch with their bypass flag, otherwise Ask.
2026-10-12 23:47:37 -07:00
BearMett 52e88e4469 fix(editor): keep a pinned duplicate open on close and ignore setActiveFile for a missing file (#28120)
* fix(editor): keep a pinned clean sibling open when closing its same-owner twin

Closing a document also closes clean same-owner duplicate records; a record
whose tab is pinned is now left open with its tab.

* fix(editor): ignore setActiveFile for an id with no open file

A stale tab or pane id could make a missing file active and persist it as the
workspace's active file.
2026-10-12 23:42:06 -07:00
Jinwoo HongandYEONGUK LEE d26b3b83a7 fix(i18n): translate Settings help as whole sentences instead of fragments (#28185)
* fix(i18n): correct Korean Settings translations

Consolidates the Korean Settings corrections from the community audit
(#27820) into one change. 514 catalog values are corrected: reversed
meanings (session search privacy notice), literal machine glosses
(Custom as 관습, gutter as 배수구, Open as 열려 있는), the terminal
caret named after the Cursor app, and Latin terminal/agent/repo left
inside Korean prose. Every value is pinned in the ko key overrides so a
catalog repair cannot revert it.

Co-authored-by: YEONGUK LEE <contact@abruption.dev>

* fix(i18n): keep the contributor's wording where it was already correct

Co-authored-by: YEONGUK LEE <contact@abruption.dev>

* fix(i18n): translate dictation shortcut help as complete sentences

* fix(i18n): retain existing dictation copy in other locales

* fix(i18n): translate complete settings count sentences

* fix(i18n): translate Git settings as complete rich sentences

* fix(i18n): clarify fast-forward protection in Korean Git help

* fix(i18n): translate repository hook guidance as complete sentences

* fix(i18n): delete settings fragment keys replaced by full sentences

The four settings sentence rewrites left their old fragment keys in every
catalog, kept alive only by tests asserting the new es/fr/ja/zh sentences
equal the old fragments concatenated. Drop those tests and the 32
now-unreferenced keys from all catalogs and the Korean overrides.

Co-authored-by: YEONGUK LEE <contact@abruption.dev>

* fix(i18n): align Korean dictation, Git, and setup-wait help with the English

Name the dictation modes with the same 토글/길게 누르기 labels as the mode
buttons, drop the Git fast-forward clauses the English does not contain,
and replace the leftover Latin "agent" in the setup-wait option.

Co-authored-by: YEONGUK LEE <contact@abruption.dev>

* fix(i18n): translate the new settings sentences faithfully in es, fr, ja, and zh

The sentence rewrites were assembled from the old machine-translated
fragments, carrying over English plural "s" suffixes (ja/zh), broken
agreement and an inverted meaning (fr), ungrammatical clauses (es),
word-salad word order (ja/zh), and missing spaces before "when one exists".
Retranslate each from the English. Also name zh's Hold dictation mode 按住
instead of 抓住 ("grab") so the button matches its description.

Co-authored-by: YEONGUK LEE <contact@abruption.dev>

---------

Co-authored-by: YEONGUK LEE <contact@abruption.dev>
2026-10-13 02:37:08 -04:00
Neil 1e48f446fb feat(wsl): orcad host transport over wsl.exe (WSL-via-orcad C1) (#27792)
* feat(wsl): WslOrcadHostTransport — orcad host transport over wsl.exe

* fix(wsl): key the WSL orcad identity to the runtime environment
2026-10-12 23:32:38 -07:00
Brennan Benson 484a54081a feat(feature-tips): make Enable Now the full-width action beside a plain Leave Off (#28199)
Drop the 'New agent tabs still open in the terminal' line and the taller
frame it needed.
2026-10-12 23:28:50 -07:00