* 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
* 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
* 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
* 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
* 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>
* [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
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>
* 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.
* 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>
* 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>
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>
#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>
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>
* 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.
#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>
#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>
* 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
* 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.
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.
* Show Codex model capacity failures in agent status
* Reduce Codex capacity detection work on terminal output
* Preserve Codex capacity notices across partial terminal frames
* 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#26027Fixes#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>
* 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.
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>
* 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.
* 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>
* 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.
- 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>
* 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>
* 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>
* 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>
* 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
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.
* 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>
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>
* 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>
* 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
* 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
* 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.
* 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.
* 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>