Commit Graph
299 Commits
Author SHA1 Message Date
a7c9d19048 fix(file-explorer): offer permanent delete when moving to Trash fails (#33956)
Offer confirmed permanent deletion when moving an item to Trash fails.
Preserve authorization and workspace ownership checks, cancellation behavior,
text-snapshot undo, remote compatibility, and all supported translations.

Fixes #33944

Co-authored-by: nori <dosukoicrypto@gmail.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 22:25:01 -07:00
Neil 362104ca18 fix(wsl): background Git and the roots catalog never start a stopped WSL distro (E9) (#34231)
* fix(wsl): background Git and the roots catalog never start a stopped WSL distro

git status ran on the UNC project root 0.45 s after a terminate, next to the
explorer read; either boots the distro. Background Git (status, conflict
operation, upstream status, branch compare, the upstream-ref watch) now asks the
shared running gate first and refuses for a stopped distro, including host
paths whose Git runs through wsl.exe. The authorized-roots rebuild skips a
stopped distro's repo and leaves it dirty, and the detected-worktree scan fails
as unavailable, so rows are kept and the next scan after the distro runs lists it.

* fix(wsl): the active workspace's first status and a wake read's roots rebuild may start WSL

- Drive-path projects whose Git runs through WSL had no wake path: the active
  workspace's first git:status after it becomes active now passes
  wakeWslDistro, so Source Control starts the distro; later polls stay gated.
- A user act runs in an async scope naming its distro; gated work inside it
  (the authorized-roots rebuild an authorization miss triggers, the detected
  scan, the Git) may start that distro and no other. External worktrees on a
  stopped distro no longer fail a wake read with access denied.
- After a user act wakes a distro, background reads stop trusting the older
  'stopped' read and probe again.

* fix(wsl): explicit WSL launches refresh the running read; wake only on tab change; gate the home probe

- Any wsl.exe Git/CLI run (commit, push, fetch) or WSL terminal spawn for a
  distro last read as stopped records that it started, so background reads probe
  again instead of refusing for up to 60 s.
- The active editor tab wakes only when the active tab changes; effect re-runs
  driven by git status or overview views read without waking.
- The authorization roots' WSL home probe no longer runs wsl.exe in a stopped
  distro when the home is uncached.
- The settle window no longer imports the orcad liveness module (it pulled main
  code into the web typecheck); a test pins it to EXIT_SETTLE_MS.

* fix(wsl): deferred work and running-list listeners never inherit a user act

A user act's async scope could leak into work it triggers indirectly: a drain of
deferred tasks it caused, or listeners of a running-list probe started inside
it. Both now run outside the scope, so only the act's own work may start its
distro.

* fix(wsl): keep shared modules free of main-only gate imports

worktree-logic.ts and wsl-running-distro-cache.ts are also compiled by the web
project, which cannot see main-only modules (AsyncLocalStorage, wsl.exe).
getAllowedRoots now injects the gated home lookup into computeWorkspaceRootWithin,
and the background gate's own cache subscriptions run outside the user-act scope
instead of the cache knowing about it.
2026-10-26 22:23:07 -07:00
Neil fe82078909 fix(wsl): background file reads and watches never start a stopped WSL distro (E9) (#34222)
* fix(wsl): background file reads and watches never start a stopped WSL distro

Any Windows touch of a \\wsl.localhost path boots a stopped distro. After a
terminate, the dying explorer watcher's overflow refresh ran realpath on the
project root 0.23 s later and booted the distro again. Background reads, stats
and watch installs now ask a fresh running list first (shared, with a 5 s lease
and a stop signal from the watcher exit and the hook relay link) and refuse when
the distro is stopped. Opening the workspace and Retry still start it. A stopped
watch waits for the distro and resyncs the explorer when it runs again.

* fix(wsl): trust a confirmed running read for 60 s without a stop signal

* fix(wsl): user acts wake; unverifiable is not stopped; settle after a stop

- Opening a workspace, expanding a folder, opening a path (explorer, quick-open,
  links), the active editor tab's load and every Retry pass wakeWslDistro on
  readDir, readFile, stat and readFileChunk. Background reloads, restored-tab
  scans and watchers stay gated.
- A failed running-list read is 'unverifiable', not 'stopped': the gate re-reads
  once past the failure backoff (once per failure window) and otherwise refuses
  with 'WSL didn't answer', never touching the path.
- After any stop signal, a running read that started within EXIT_SETTLE_MS of it
  never counts, in isWslDistroRunning itself, so neither the watcher's own
  overflow refresh nor the hook relay's restart check can read a stale listing.
- A confirmed read that sees a distro stop records a stop signal, resetting the
  60 s lease.

* test: user-opened stats now carry the WSL wake flag
2026-10-26 21:17:07 -07:00
NeilandClaude 284411d893 fix(wsl-host): uninstall and startup release WSL holders; a partial Remove keeps the host pending (#33843)
* fix(wsl-host): uninstall and startup release the WSL distro holders Orca left running

The detached wsl.exe holder outlives the app, so an uninstall left its distro,
orcad and shells running. The uninstaller now runs Orca with
--orca-uninstall-release-wsl-holders after killing the app and its daemon; it
ends only the holders this profile recorded, each verified by pid, start time
and command line, and keeps any it cannot verify.

At startup the WSL host service now releases holders whose distro is no longer
a host (a failed add or remove), and every holder while WSL hosts are off; a
closed gate releases them too.

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

* fix(wsl-host): a Remove that can't prove the server stopped keeps the host, pending

A partial Remove dropped the host anyway, leaving a server whose live
terminals block the next add's activation. Remove now drops the host only on a
proven stop; otherwise it records a pending stop on the WSL record, keeps the
host listed and says why (live or unverifiable). Remove again retries without
ever booting a stopped distro (it says to start it); Connect or Add on the same
distro keeps the host; a distro that is no longer registered finishes. Nothing
reconnects a pending host on its own.

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

* fix(wsl-host): E11 review — keep holders when records are unreadable; finish removals a stopped or renamed distro proves

- Startup keeps every holder when the WSL host records can't all be read
  (unverifiable), and no longer re-adopts a pending host's holder.
- Remove matches a renamed distro by GUID (isWslDistroRegistered), and a
  stopped distro finishes a pending Remove: the cold probe proves the stop.
- Only the user's Connect or Add withdraws a pending Remove; other connects
  are refused, and re-adding respects startIfStopped.
- Settings' Remove carries the kept result, so it warns instead of 'Removed'.
- A holder record without a start time is never killed on its command line
  alone, except the one this process just spawned.

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

* fix(wsl-host): E11 review 2 — a closed gate keeps live hosts' holders; stop a renamed distro by its current name

- With the gate closed, a launch releases only orphan holders (no host record,
  or a pending Remove), under the same keep rule as startup; a user with no
  holder records costs one folder check, nothing else.
- The keep rule re-reads host records per holder and keeps an Add in flight.
- Remove resolves the distro's current name from its GUID and stops it there.
- The uninstall command arms its exit timer first and exits 1 if setup throws;
  NSIS launches it only when a userData holder folder exists.

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

* fix(wsl-host): never boot a host whose Remove is pending at the next launch

Early wake built its host list from every record, so a host focused when its
Remove ended pending was booted at each launch, undoing the stop's proof. It
now skips pending records, and Remove forgets the host's early wake whatever
the outcome.

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

* fix(wsl-host): no wake for a pending host; the e2e fake stops an unbridged server like the real one

- mayWake skips a host whose Remove is pending, so a due automation can't
  boot it (focus already couldn't).
- The e2e fake connector read a host with no bridge as stopped. Since E9 a
  re-enable connects nothing, so Remove after off/on left the host's shells
  running. Like the real connector, it now reconnects the always-running fake
  distro to stop its server.
- Status bookkeeping moves to WslHostStatusBoard, and the pending-host connect
  rule to admitConnectToPendingHost, to keep the service under max-lines.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 20:17:53 -07:00
Brennan Benson 29a5f89b8a Keep same-machine folders with matching Git remotes in separate projects (#32272)
* WIP: same-host same-remote checkouts keep their own project id

* WIP: claim the shared project id per checkout surface; drop the display-only clone split

* WIP: index derived ids by repo in the hydration normalizer

* Resolve workspace project affiliation from current checkout owners

* fix: preserve concrete project ownership across catalogs and operations

* fix: combine recent project selector imports

* fix: enforce canonical catalog reads and preserve search continuity

* fix: scope catalog lint exceptions to renderer files

* Resolve project search ownership before native candidate limits

* Combine duplicate session scope imports

* fix: derive returned history row ownership on the host

* Reconcile full session history replies by content

* Require authoritative project catalogs for terminal snapshots

* Preserve registered project claims and partial history results

* test: check orphaned setup cleanup state without assertions

* fix: align catalog callers and native search fixture contracts

* test: check full repo shapes in runtime routing fixtures

* Fix checked catalog inputs in compiler regression fixtures

* Keep checked PTY fixture repos mutable

* test: align catalog fixtures with canonical readers

* test: check catalog and runtime fixture inputs

* test: check catalog fixtures without outer assertions

* test: follow persistence harness relocation

* Adapt catalog test inputs to integrated main checks

* Test History hashing across cached depth revalidation

* test(settings): expect host-qualified setup removal

* test: capture host split listings and scope relay recovery

* ci: regenerate merge ref

* test: type host-split listing diagnostics
2026-10-26 19:07:06 -07:00
Brennan Benson 6e3c10c835 Honor browser preferences and modifiers for HTML preview links (#33622)
* fix(browser): honor preview link destinations and modifiers

* Clarify the source browser provider contract

* test(browser): check preview guest before reporting modifiers

* fix(browser): report system link failures and cover preview routes

* test(browser): combine HTTP link destination imports

* refactor(browser): require source ownership for preview links

* test(browser): type the forbidden Active Server getter

* fix(i18n): retain required preview error catalog entry
2026-10-26 18:43:50 -07:00
NeilandClaude 2e67ba5a64 perf(wsl-host): start booting only the focused WSL host early at launch (E9, replaces #33141) (#33924)
* perf(wsl-host): start booting the distros the last run had open work on as the app launches

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

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

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

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

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

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

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 14:35:11 -07:00
NeilandClaude 2dd8207369 fix(wsl-host): boot only the focused WSL host, and keep a stopped one down (E9 A) (#33838)
* fix(wsl-host): boot only the focused WSL host, and keep a stopped one down

E9 connect policy, part 1. A stopped distro now boots only for an explicit user action
or when its host becomes focused:
- Visible work is the active workspace plus workspaces focused earlier in this window
  that still have tabs. Saved tabs alone no longer count, so a launch with two hosts
  boots only the focused one.
- After a confirmed stop (wsl --shutdown, WSL update) the host is parked. Liveness no
  longer reboots it even when it is visible, and polls get "<distro> was stopped"
  instead of a boot. Re-focusing the host, Connect, or the distro running again lifts it.
- Liveness recovery always needs a confirmed-running distro, so a distro that stops
  mid-recovery is never booted again.

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

* test(wsl-host): launch boots one of two hosts; polls never boot; lost contact never parks

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

* fix(wsl-host): only a focus entry or a user action boots a WSL host (E9 review)

Review of #33838:
- Re-focus never lifted a park: a host focused earlier stayed in the visible set, and
  the renderer skips unchanged reports. The renderer now sends a separate focus entry
  (focusHost) each time the user switches to a workspace on a WSL host, including the
  launch restore; only that, or Connect, lifts a park and may boot.
- Runtime calls could boot: ensureForRuntimeCall connected any visible, unparked host.
  It now reads the host's reachability first: a confirmed-stopped distro parks at once,
  an unreadable running list refuses, and only a distro confirmed running is
  reconnected (for visible work). Visible work itself never connects anything.
- Turning WSL hosts on no longer boots every visible host, and focus isn't recorded
  while they're off; the window re-reports its focused host instead.
- Each window's visible work is kept apart and unioned, so one window can't drop
  another's.
- wakeForAutomation/isConnected move to the automation PR, which uses them.

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

* fix(wsl-host): a poll waits for liveness's verdict right after an exit (E9 re-review)

Right after `wsl --shutdown` WSL can still list the stopping distro as running (the
supervisor waits and re-reads for exactly this). A poll's cold probe then read
'unreachable', reconnected, superseded the pending distro-stopped verdict and booted
the distro again. The supervisor now reports when it is settling (a verdict in
progress, or a watch/holder exit within the last few seconds), and a runtime call
refuses instead of reconnecting then; the verdict parks the host as before.

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

* test(wsl-host): a new supervised entry starts with no recorded exit

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 12:52:16 -07:00
den4ikandNeil 0afedab10d fix(lifecycle): keep UI listener failures from vetoing the shutdown checkpoint (#21029)
A throwing ui-changed listener (e.g. webContents.send on a destroyed
secondary window) propagated out of store.updateUI() during
app:stage-before-unload-sync and cancelled the shutdown checkpoint,
leaving the user unable to quit. notifyUIChanged now isolates each
listener, the ui:stateChanged broadcast skips destroyed webContents, and
the staging failure cause is returned to preload so the error toast
names it.

Fixes #20897

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 09:15:45 -07:00
Neil a93f73c032 fix(terminal): skip an escape tail an abandoned hidden-output restore would print (#33905)
* fix(terminal): skip an escape tail an abandoned hidden-output restore would print (#33766)

Main drops a hidden pane's renderer delivery after its model ingests the
bytes, so the first chunk sent on reveal can begin inside an escape whose
start was dropped. When the restore is abandoned, the renderer resets its
parser and writes the queued chunks, and xterm printed the tail (';242m',
the rest of a Codex OSC title).

Main tracks each PTY's escape state over every accepted payload and labels
the first delivery after a hidden or pending-cap drop with the escape it
resumes inside (gapEscapeState). Only the abandon path strips that
continuation; a successful restore keeps every byte so the snapshot's
pending escape tail can complete. No label means no change.

* fix(terminal): make the escape-continuation scan's switch exhaustive (#33766)
2026-10-26 06:33:23 -07:00
NeilandTian-yi Liang c9eee6b54c fix(runtime-environments): every window sees a server saved from the CLI (#33930)
`orca environment add` writes the saved-server file directly. Main already
watched that file but only repaired the Active Server preference, so every
renderer surface listing saved servers (the Agent Session History host
picker, host menus, the status bar) kept the old list until something
else refreshed it. Main now tells every window when the file changes, and
the renderer refreshes through the existing coalesced catalog refresher.

Co-authored-by: Tian-yi Liang <tianyilt@qq.com>
2026-10-26 06:00:15 -07:00
Jinwoo Hong a66f6bf011 fix(agent-resume): keep a background agent launch's flags when it is resumed (#33776)
* fix(agent-resume): record a background agent launch's recipe so resume keeps its flags

* test: narrow the reveal's notifier so the test needs no cast

* refactor(agent-resume): one recipe registration path; skip adopted panes

* test: add the launch-recipe listener to the remaining window mocks
2026-10-26 01:49:54 -04:00
Brennan Benson bfc633af8f Offer to resume chats after managed server updates (#28978)
* Guard managed server restarts with host work reservations

* Protect legacy server update requests with host admission

* Reserve chat-safe restarts in SSH and WSL server updates

* Keep activation host fixtures within the module line limit

* fix(orcad): preserve session queue timing during admission

* Explain chat-safe update deferrals and superseded restarts

* Clarify managed server Force upgrades and retry instructions

* Separate chat entry delegates from conversation creation

* Report child work through main's child evidence in the restart drain test

* Drive main's snapshot-room tests through the restart reservation

Main's room tests deployed over a serving incumbent with a census that has no
chat work count and no restart admission, so the update deferred before the
room probe ran. Give them the same idle census and slot admission as the other
activation tests, and pin the probe before the reservation instead of before the
recount it replaced.

* fix(native-chat): an update keeps waiting on a chat start after its conversation is closed

The restart check counted a start only while its conversation stayed open,
so an idle close during a stalled start let a managed update through.
Every tracked attach, create, start and open now counts as restart work
in the same tracker that counts the session queue.

* fix(native-chat): keep the structured session view within its line limit once formatted

Main's copy sat at 400 lines only because one line was left unformatted; the
merge's formatter pushed it to 401. Inlining the one-use question list keeps it
at 400 with identical behavior.

* fix(orcad): a recovery stop request stops the server; only an older client's empty request waits for idle

Stopping a slot and restarting it for an older client's update were both an empty
.orcad-stop-request file, so routing that file through restart admission let a
crash recovery, stranded-setup release or rejected-candidate rollback leave the
server running. New clients now write "stop-now" into the request (renamed in
whole), which stops at once as before; an empty or unrecognized request takes the
chat-safe restart, and a deferred restart logs why. Also gives the restart
admission activation fixtures the now-required recount.

* docs(orcad): say a directory at the stop-request path is refused, not restarted

* docs(orcad): the plain stop request's comment states both of its meanings

* style: format the restart admission files for the format check

* test(wsl): count the incumbent's recount bridge after the reservation's

* fix(orcad): a Windows stop request retries its rename while antivirus holds the new file

Renaming the just-written stop-now request can briefly fail with EPERM, EACCES
or EBUSY on Windows; the stop now retries those with the same bounded delays as
record-publish instead of answering SIGNAL_FAILED and leaving the server up.

* test(orcad): a real Windows host stops on the slot's stop-now request and relaunches

* test(orcad): recovery stops a real server whose restart admission refuses

* test(orcad): the recovery-stop cell tunnels over the cell's SSH connection

* test(orcad): the recovery-stop cell names itself in the CI log

* fix(settings): a deferred WSL update shows its full reason below the row

* test(orcad): fixtures pass releaseIncumbentAdmission; the census test calls its own method

* test(orcad): the capable-server census in the fence test reports idle chat work

* Record server chat restart offers and desktop creation history

* Offer interrupted chat recovery per managed runtime

* Ship the remote chat resume action labels in the runtime catalog

* Update removal contracts for desktop chat history cleanup

* Scope remote chat recovery to each server occurrence

* Preserve recovery choices and uncertain continuation outcomes

* fix: preserve uncertain restart action outcomes

* Fix restart recovery CI imports and fixtures

* test: align resume assertions with unconfirmed outcomes

* test: bound restart recovery work across scaled populations

* fix(native-chat): title the remote resume dialog with the restart

The dialog can appear out of nowhere when another desktop updates a shared
server, so its title now says what happened: "<machine> restarted".
2026-10-25 17:15:55 -07:00
Kelvin Amoaba 1b0e56e385 feat(browser): make Orca shortcuts, split focus and mouse back/forward work inside pages (#31859) 2026-10-25 22:57:53 +00:00
Kelvin Amoaba eb499478da feat(browser): show agent browsing live, with a jump to the page from chat (#33075) 2026-10-25 22:15:00 +00:00
Brennan Benson 883b768bc7 A chat never starts writing a conversation a terminal is still writing, and restored panes respect open chats (#30930)
* fix(native-chat): one ownership index with link roles, and a chat refuses to start while a terminal writes its conversation

Each chat link now carries its role (head or earlier) and key; Session History names
the chat continuing a conversation first, duplicate adoption checks only head links in
both the pre-commit check and the store transaction, and terminal resumes stay refused
exactly as before. The terminal-writer check now also runs inside acquireOwner before
the spawn, refusing with the typed pre-spawn reason conversationOpenInTerminal.

* fix(native-chat): hold a terminal start Orca issues until its terminal reports it

An in-memory registry of managed terminal starts per conversation, registered in the
same step as the resume admission (terminal.send with a resume command, createTerminal
with a command), bound to the PTY execution that runs it, and ended only when that
terminal's hooks report the conversation or the execution is gone. A chat's agent
start refuses while an entry may hold its conversation.

* fix(terminal): an automatic pane restore never resumes a conversation an open chat continues

Resume recipes built from a pane's saved facts (cold restore, deferred and late reattach,
sleeping wake, host mobile materialization) carry resumeOrigin 'saved'. The execution host
decides before any command is issued: while an open chat continues the conversation, or a
chat may be writing it, the pane starts its plain shell with the started-fresh notice and
its saved claim is forgotten; with unreadable records only a saved restore is refused and
its record kept. An admitted resume registers its managed start in the same step, so the
chat's agent start refuses until the terminal reports it or exits. Clearing the last saved
record now reaches disk.

* Fix saved terminal resume ownership and effective launch results

* Preserve conversation case and clear refused cold restore identity

* fix: publish effective terminal launch results on attachment

* fix: preserve terminal launch callback and candidate ownership

* fix: keep existing terminal attachments observational

* fix: consolidate terminal launch imports

* test: document snapshot runtime fixture boundary

* fix: preserve terminal launch identity types

* fix: accept reattach payload policy sessions

* fix: preserve terminal result validation contracts

* refactor: separate terminal create contract

* test: document partial terminal runtime fixtures

* test: align sleeping resume store fixture

* Fix terminal create type contracts

* fix: return the terminal main started to its waiting view

* fix: register reattached terminals before publishing their handles

* Check unavailable-resume test fixture types

* Complete sidebar resume test store fixture

* test: bound saved resume ownership and refusal work

* Settle refused saved resume claims from actual launch results

* Fix saved resume test type contracts

* test(e2e): capture exact terminal parking diagnostics

* test: verify parked terminal with fresh host inventory

* Consolidate agent session imports in remote terminal transport

* Clarify terminal conversation refusal guidance

* Admit note-only saved conversations without hiding live writers

* Retain terminal writer proofs through final admission
2026-10-25 14:39:05 -07:00
Neil 82a3214049 fix(sleep): reopen a slept agent whose tab is gone in a fresh tab instead of stranding it (#33598)
A slept agent whose tab disappeared now resumes in a fresh tab (with --resume, through the existing duplicate/host guards) when its workspace opens, and main's stranded workspace-sleep record is then dropped (only if no tab still lists that pane), instead of the record sitting forever while the workspace opens a bare shell.

Fixes #22657
2026-10-25 11:00:28 -07:00
Kelvin Amoaba 9485e73207 feat(browser): dock DevTools in the browser pane, with dock side, resizing and pop-out (#33003) 2026-10-25 16:41:56 +00:00
Neil 0b28553093 feat(ssh): show saved port forwards that couldn't start, with why, and let you remove them (#33450)
* feat(ssh): list saved port forwards that couldn't start, with why, and let you remove them (#32484)

A saved forward whose local port is taken, or that keeps failing, stayed
saved but invisible, retried in the background with no way to remove it.
The port-forward lists now show each saved forward that isn't open, with
the last start error, and Remove deletes it by its mapping.

* fix(ssh): a forward whose ssh exits after starting backs off like a failed start

* fix(ssh): re-register the new forward channels, close a forward a restore reopened before removing it, and update IPC fixtures

* fix(ssh): a flapping forward keeps its backoff streak until it stays up

* fix(ssh): translate the saved-forward row, say Stopped for a forward that died, toast a failed remove, and reset backoff on manual edits

* fix(ssh): keep saved forwards listed and removable while the host is offline; label the remove button; test the healthy-uptime reset

* fix(ssh): mirror saved forwards from main with a stale-read guard, including hosts that never connect

* fix(ssh): scroll the offline ports panel when saved forwards overflow it

* test(e2e): give the saved-forward restart case's timeout its reason
2026-10-25 02:37:30 -07:00
NeilandClaude Opus 5.5 8e9f86b119 feat(managed-server): Update and Update anyway for a managed SSH server, keeping its running terminals (#33397)
* feat(managed-server): offer Update and Update anyway on a managed SSH server's row

A managed SSH server only updated on connect, and every connect deferred while
a terminal ran there. Its row now offers Update when this desktop bundles a
newer build than the Orca that runs the host. When running terminals defer it,
Update anyway restarts the server past them; the terminal daemon carries them
across the restart.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(managed-server): Update anyway passes only counted live terminals and keeps Update's version admission

Update anyway now sends the incumbent build it confirmed over; under the host
fence it is refused if another desktop activated a build since, keeps the
newer-host downgrade refusal, and never passes an uncounted terminal census.
The offer also covers hosts activated before the Orca version was recorded,
for the build this desktop already deferred there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(managed-server): Update anyway also confirms a menu Update the row does not advertise

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(managed-server): the row shows one confirmation at a time

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* ci(e2e): route managed-server update sources to the Update anyway Docker spec

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 22:49:18 -07:00
Kelvin Amoaba 25b9ce5168 feat(browser): show a hovered or focused link's URL in a bubble at the bottom of the page (#32978) 2026-10-25 03:09:30 +00:00
Kelvin Amoaba 76f0f35bad feat(browser): speaker icon on tabs playing sound, with tab mute (#32981) 2026-10-25 02:51:37 +00:00
Neil b900d9843f refactor(shared): colocate Jira rules and direct imports (#33164) 2026-10-24 06:46:07 -07:00
Kelvin Amoaba 785daec1e1 fix(browser): show profiles changed outside the window in the profile menu without a reload (#32723) 2026-10-24 05:06:34 +00:00
Kelvin Amoaba 5dc197e5ec feat(browser): history controls: Chrome-style Escape, removable suggestions, history view (#31846) 2026-10-24 04:46:47 +00:00
NeilandJesse Sanford 7cafdb072b feat(ssh): Recover server for a managed host refused on a stale lock, and surface that refusal in seconds (#32951)
* feat(orcad): run --reclaim-stale-lock on a managed host's active slot

The desktop can now dry-run and confirm the stale instance-lock recovery
on a Linux managed host, serialized with launches, then start the server
again and reconnect the way the restart action does.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* feat(settings): offer Recover server for a managed host refused on a stale lock

When a managed orcad start names --reclaim-stale-lock, the SSH host row
offers Recover server. The dialog dry-runs the check, shows the host's
evidence, and clears the lock only after the user confirms no other
machine sharing the home runs Orca.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* feat(mobile): point a host refused on a stale lock to the desktop's Recover server

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(settings): mount the Recover server dialog per opening

A fresh mount starts each opening from a new check instead of resetting
state in an effect.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(orcad): end the readiness wait once the host proves the launch exited

A managed orcad refused at start (such as on a possibly stale instance
lock) left the client waiting out the full readiness deadline. Each
host-side wait now also checks the launch's PID file with kill -0 and
ends early on a proven exit, so the caller reports the same pending
readiness, with the orcad.log tail, within a poll. No PID, a denied
probe or a reused PID keeps the old deadline.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(orcad): refuse a managed slot without --reclaim-stale-lock before running it

An older orcad ignores the flag and starts serving in the foreground. The
same remote exec now checks that the slot's server bundle names the flag
and answers unsupported otherwise, without invoking orcad.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(settings): show the manual stale-lock command as literal mono text

The rendered dialog ran the command into the sentence, so it was hard to
read or copy. It now sits in its own mono block, like Details.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(settings): offer only a manual delete when the host can't reclaim, and format the lock's age

An unsupported host was told to run the very command it lacks. Main now
names the lock path for that case, and the dialog shows only a copyable
rm of it with the shared-home caution. The lock's age uses the UI's
relative-time formatter instead of a hand-rolled minutes count.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(orcad): pin a confirmed stale-lock reclaim to the record the user approved

--yes reclaimed whatever record held the lock at that moment, so a lock a
same-named machine wrote while the dialog sat open could be cleared.
orcad now takes --expect-nonce and refuses unless the lock still holds
it; the dry run reports the nonce, the desktop sends it back on confirm,
and the managed slot gate requires a build that knows the pin. A
reclaimed result carries the evidence it acted on.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(settings): keep the Recover server dialog open through its own reclaim

The dialog's mount was gated on the status that offered it, and the
reclaim clears that note before its answer arrives, so the result was
never shown and the card kept the dialog marked open. Only the triggers
are gated now; an open dialog keeps the server it opened for until the
user closes it.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(settings): put the Recover server confirmation on the security surface

It asks permission to run a remote command that clears an ownership lock
and starts server code, which STYLEGUIDE puts on that surface.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(orcad): trust a gone launch PID only on the machine that launched it

The PID file sits in a home other login nodes may share, so a wait exec
that lands on another node read a starting server as exited. Both launch
paths now record the launching machine's boot id and node name beside
the PID, and the readiness wait ends early only when its own exec reads
the same record. No record, a host without a boot id, or another machine
keeps the deadline. The PID path is named once in the launch command so
it stays within its sent-byte ceiling.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(orcad): keep a slot's unreadable stale-lock answer from offering a manual delete

A slot that passed the gate but gave no JSON, or a status this client
does not know, read as unsupported and offered rm of the lock. It now
reads as no-answer, which points to the slot's own reclaim command, and
unsupported is left to a slot without the command, a non-Linux host or
no active version.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* style(settings): use the text-2xs step for the stale-lock command block

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(mobile): offer the desktop-recovery hint on the same refusal the desktop does

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* test(orcad): name the extra fields a fake stale-lock answer carries

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(settings): end the Recover server flow once the lock is cleared, and keep an unpinned reclaim manual

After a reclaim whose restart failed, the dialog kept the old evidence,
the enabled confirmation and manual recovery for a lock that was gone.
It now shows only that the lock was cleared and why the server did not
start, with Close. A slot that has the reclaim but not the nonce pin is
now told apart from one without the reclaim, and is pointed to its own
reclaim command rather than rm.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(orcad): keep a stale-lock reclaim's result when the restart after it throws

A wake or tunnel rebuild that threw after the lock was cleared discarded
the reclaimed result, so the caller skipped its reconnect and note
clearing and the dialog kept a confirmation for a lock that was gone.
The restart's failure now becomes the result's notRestarted reason.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* fix(orcad): report a reclaimed server as started when only its forward failed to follow

A tunnel rebuild that failed after the wake started the server was
reported as the server not starting. The rebuild now goes through
followLaunchedServerPort, as other relaunches do, which warns and leaves
the forward to the next connect. Also drops a caller test that only
covered behaviour the fix did not change.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

* test(mobile): re-record the execution-target goldens for the recovery hint field

The SSH gate's projected state gained `needsDesktopServerRecovery`, which
is false for every recorded reply (no recorded host sends a managed
server refusal). Re-recorded with `pnpm --dir mobile rpc:record` for the
two pilot recordings and the four execution-target reply partitions; the
only change is that field, plus the value pool reordering around it.

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>

---------

Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
2026-10-23 17:57:22 -07:00
861299e6cc refactor(ipc): remove unreachable runtime-environment provisioning and control-retry IPC (#32960)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-23 17:54:11 -07:00
f5f7f172a8 chore(ipc): remove unreachable hooks:createIssueCommandRunner IPC (#32953)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-23 17:50:37 -07:00
OrcaWinandOrcaWin 02d7214c1a refactor: remove four unreachable preload IPC bridges (#32950)
* refactor(repos): remove unreachable repos:getGitUsername IPC

* refactor(mobile): remove unreachable mobile:isWebSocketReady IPC

* refactor(skills): remove unreachable skills:deletePackageVersion IPC

* refactor(space): remove unreachable workspaceSpace:closeWindow IPC

* chore: prune repo-host-read baseline for removed git username handler

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 17:39:44 -07:00
OrcaWinandOrcaWin cdba9a7703 refactor(dashboard): remove unreachable popout spawn/sleep IPC (#32954)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 17:33:42 -07:00
OrcaWinandOrcaWin da620ad632 refactor(rate-limits): remove unreachable setPollingInterval and refreshMiniMax IPC (#32945)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 17:32:57 -07:00
OrcaWinandOrcaWin d1aef1eee9 refactor(worktrees): remove unreachable legacy worktree list IPC (#32942)
* refactor(worktrees): remove unreachable legacy worktree list IPC

The desktop and web preloads both always provide `worktrees.listDetected`,
so the renderer's fallback to `worktrees.list` never ran, and nothing calls
`worktrees.listAll`. Remove both IPC handlers, their preload/web wrappers,
the renderer fallback, and helpers only they used. Tests that observed
behaviour through the removed handlers now go through `worktrees:listDetected`.

* test(worktrees): drop removed list channels from SSH listing matrix

Address review: the canonical SSH listing test built channel names dynamically
and still invoked worktrees:list/listAll. Also fold the detected-result reader
into the shared worktree test fixtures, refresh stale comments, and assert the
backfill no-op test listed authoritatively.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 17:30:59 -07:00
Neil cd59239927 fix(workspaces): add main-owned project move pause barrier (#32940)
* fix(workspaces): add main-owned project move pause barrier

* test(workspaces): type project move pause reply fixtures
2026-10-23 17:25:22 -07:00
Neil 1cc2a2afd8 refactor(shared): group remote runtime shared-control lifecycle (#32977) 2026-10-23 17:04:58 -07:00
Neil aeb039938f refactor(jira): colocate shared contracts and capabilities (#32927)
* refactor(jira): colocate shared contracts and capabilities

* test(jira): validate title width against panel budget
2026-10-23 14:31:05 -07:00
Kelvin Amoaba 846851237c feat(browser): per-repo or per-workspace browser profile for new tabs (#32039) 2026-10-23 15:20:11 +00:00
92dfb4fda6 test: trim redundant coverage and fix vacuous assertions (#32305)
* test: remove redundant cases and repair behavioral assertions

* docs: reconcile audit records with current main

* fix(deps): apply security updates from #32101

Apply the six-file DOMPurify 3.4.17 and Next.js 16.4.1 patch from PR #32101 to resolve the dependency security gate for this test audit. Original patch by Brennan Benson.

* test: satisfy changed-line quality gates

Add required braces and replace filter indexing with find. Rerun both CI quality gates and the 27 affected relay tests; refresh audit hashes and record the corrections.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-23 03:52:51 -07:00
OrcaWinandOrcaWin 0efc842028 [comment audit] Shorten preload comments (#32257)
* chore: audit preload root comments and track repository coverage

* docs: track repository comment audit coverage

* chore: keep comment audit tracker local

* chore: shorten preload API contract comments

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 02:16:59 -07:00
Jinjing 3f7b34106a Refine Agent Dashboard lifecycle handling (#32172)
* Track Agent Dashboard adoption and daily visible use

- Record enablement, board opens, and per-surface daily visibility
- Persist daily limits across restarts and respect consent and window visibility

* Track dashboard telemetry at surface roots
2026-10-22 21:49:13 -07:00
Jinwoo Hong fa71556085 Install and update Orca's skills on paired servers and SSH hosts (#31867)
* Add Orca's own bundled-skill planner and installer (not wired in yet)

One planner decides what installing Orca's bundled skills does to each
target folder; execute re-plans under per-path locks and runs only a plan
whose digest still matches; a shared summary derives badge, wording and
exit code. A copy counts as Orca's untouched one only when its SKILL.md
bytes match a version some build shipped (resources/skills/released-digests.json,
generated from git history and checked add-only).

Nothing calls this yet; the npx path is unchanged.

* Report left-alone folders as warnings and keep backups in the home

A leave is no longer a failure: the outcome line says what happened plus
"N left alone: <reason>", and the exit code is 1 only for a failed or
changed op. Backups for every scope go to <home>/.agents/.orca-skill-backups
on the executing host, so a project Replace never writes into the repo;
moving there falls back to copy, verify, then remove across filesystems.

* Update Orca's skills with Orca's own installer instead of npx skills

The app's Update skills dialog, badge, nudge and status pills now read the
bundled-skill plan and summary, and Update executes the reviewed plan's
digest. `orca skills install|update` runs the same planner in-process with
--dry-run, --force, --json and per-summary exit codes. Removes both npx
spawn sites, the freshness inventory modules and the npx round-trip CI.

* Update only where the skill already is; one provider-root rule for app and CLI

installedOnly now drops every location that holds nothing (keeping the shared slot
only when an existing agent link points at it), so Update never adds a skill for
another agent. The app and CLI resolve the Claude skills folder through the same
rule in localBundledSkillInput; a test asserts both plan identically.

* Compact Update skills dialog: one row per skill, locations named by agent

summarizeBundledSkillPlan now returns each skill's locations, labelled by
agent (or "Shared folder") with a ~-collapsed path; the dialog shows one row
per skill that needs something, collapses up-to-date skills into one line, and
lists every location behind "Show all locations". The result reads "Updated N
skills · M left alone". Under installedOnly a Replace with no shared copy
replaces in place instead of adding one.

* fix(skills): keep location paths readable by putting the state under the path

* fix(skills): hold the last plan in state, not a ref mutated during render

Split the update dialog's rows, headline and footer into components, move the Update label
next to the other plan copy, and use z.strictObject for the request schemas.

* Escape non-ASCII characters in bundled-skill regex and wording

The orcad bundle rejects a literal non-ASCII character in a regex.

* fix(cli): escape non-ASCII apostrophes in the skills install help text

* Plan and update Orca's skills on paired servers, SSH hosts and WSL

* Show the skills pill for paired hosts; real-WSL installer test

* test(orcad): check the bundled CLI plans a skill install without npx

Drop the deleted roundtrip workflow's group from the closed-PR cancellation fixture.

* Let the WSL installer create the backups folder itself

* Review fixes: follow the active workspace's host, keep hosts' plans and runs apart, never boot WSL for a background check

* test: execute requests carry the plan request; CLI pill follows the local target

* Write large WSL skill files in chunks that stay under the command-line limit

* Make bundled-skill test fixtures link folders the way the product does on Windows

Directory links in fixtures are junctions on Windows, which need no
Developer Mode; the one file-link fixture is skipped there.

* Let a client ask a host to install named Orca skills, not only update installed ones

* Plan an SSH workspace on the managed server that serves its host; ask to connect otherwise

* Translate the remote skill states into every locale

* Resolve legacy skill agent keys canonically

* Reject stale skill replacements when auxiliary content changes

* Remove the Windows-hosted WSL bundled skill installer

* Wait for active workspace ownership before planning bundled skills

* Keep ordinary bundled skill classification shallow

* Leave unreadable skill replacements alone without aborting plans

* Pass force-all through shallow planning and describe unreadable copies

* Clarify skill update statuses and folder details

* Keep selected skill replacements in place with one status

* Report completed skill replacements with their backup confirmation

* Clarify available skill updates and skipped copies

* Keep skill update results in preview order

* Show each skill skip reason once

* Count skipped skills instead of skipped folders

* Make installer input and link tests work on Windows

* Bound bundled skill classification reads and parse names linearly

* Keep workspace skill roots inside the resolved workspace

* Compare workspace skill roots with native path semantics

* Restrict bundled skill backups to their owner on POSIX

* Keep bundled skill updates on the proven local workspace host

* Keep recovered skills needing attention until they are updated

* Count completed skill updates in the status tooltip

* Sync the runtime localization catalog
2026-10-22 22:50:05 -04:00
Jinwoo Hong d3dbd9683f Update Orca's skills with Orca's own installer instead of npx skills (#31688)
* Add Orca's own bundled-skill planner and installer (not wired in yet)

One planner decides what installing Orca's bundled skills does to each
target folder; execute re-plans under per-path locks and runs only a plan
whose digest still matches; a shared summary derives badge, wording and
exit code. A copy counts as Orca's untouched one only when its SKILL.md
bytes match a version some build shipped (resources/skills/released-digests.json,
generated from git history and checked add-only).

Nothing calls this yet; the npx path is unchanged.

* Report left-alone folders as warnings and keep backups in the home

A leave is no longer a failure: the outcome line says what happened plus
"N left alone: <reason>", and the exit code is 1 only for a failed or
changed op. Backups for every scope go to <home>/.agents/.orca-skill-backups
on the executing host, so a project Replace never writes into the repo;
moving there falls back to copy, verify, then remove across filesystems.

* Update Orca's skills with Orca's own installer instead of npx skills

The app's Update skills dialog, badge, nudge and status pills now read the
bundled-skill plan and summary, and Update executes the reviewed plan's
digest. `orca skills install|update` runs the same planner in-process with
--dry-run, --force, --json and per-summary exit codes. Removes both npx
spawn sites, the freshness inventory modules and the npx round-trip CI.

* Update only where the skill already is; one provider-root rule for app and CLI

installedOnly now drops every location that holds nothing (keeping the shared slot
only when an existing agent link points at it), so Update never adds a skill for
another agent. The app and CLI resolve the Claude skills folder through the same
rule in localBundledSkillInput; a test asserts both plan identically.

* Compact Update skills dialog: one row per skill, locations named by agent

summarizeBundledSkillPlan now returns each skill's locations, labelled by
agent (or "Shared folder") with a ~-collapsed path; the dialog shows one row
per skill that needs something, collapses up-to-date skills into one line, and
lists every location behind "Show all locations". The result reads "Updated N
skills · M left alone". Under installedOnly a Replace with no shared copy
replaces in place instead of adding one.

* fix(skills): keep location paths readable by putting the state under the path

* fix(skills): hold the last plan in state, not a ref mutated during render

Split the update dialog's rows, headline and footer into components, move the Update label
next to the other plan copy, and use z.strictObject for the request schemas.

* Escape non-ASCII characters in bundled-skill regex and wording

The orcad bundle rejects a literal non-ASCII character in a regex.

* fix(cli): escape non-ASCII apostrophes in the skills install help text

* test(orcad): check the bundled CLI plans a skill install without npx

Drop the deleted roundtrip workflow's group from the closed-PR cancellation fixture.

* Make bundled-skill test fixtures link folders the way the product does on Windows

Directory links in fixtures are junctions on Windows, which need no
Developer Mode; the one file-link fixture is skipped there.

* Resolve legacy skill agent keys canonically

* Reject stale skill replacements when auxiliary content changes

* Keep ordinary bundled skill classification shallow

* Leave unreadable skill replacements alone without aborting plans

* Pass force-all through shallow planning and describe unreadable copies

* Clarify skill update statuses and folder details

* Keep selected skill replacements in place with one status

* Report completed skill replacements with their backup confirmation

* Clarify available skill updates and skipped copies

* Keep skill update results in preview order

* Show each skill skip reason once

* Count skipped skills instead of skipped folders

* Make installer input and link tests work on Windows

* Bound bundled skill classification reads and parse names linearly

* Keep workspace skill roots inside the resolved workspace

* Compare workspace skill roots with native path semantics

* Restrict bundled skill backups to their owner on POSIX

* Keep recovered skills needing attention until they are updated

* Count completed skill updates in the status tooltip

* Sync the runtime localization catalog
2026-10-22 22:35:14 -04:00
Jinwoo HongandClaude 41661e3312 feat(sidebar): main runs workspace sleep; the window follows (P3b) (#31564)
* fix(sidebar): land flip-a's switch-on fixes on main, still dark (no flip)

The fixes found while the sidebar ran from main's feed, without turning
that on: ORCA_SIDEBAR_INPUTS_IS_MAIN stays false, and none of flip-a's
stop-gaps come along.

- Main stops counting a closed tab's terminal once it was asked to stop
  and no pane shows it; a failed or refused stop takes the request back,
  and a host out of contact stays unverifiable.
- Main fetches a paired server's rows with the transport's normal bound,
  so a server slower than 5 s still lists.
- A deferred unread raise flips the folder row it was decided for, and a
  read while the owner check is out cancels it.
- Phone: no worktree.ps flash before the feed; a host's last installed
  feed stands in while a fresh read is out; it highlights its own
  last-opened workspace and a fold never scrolls; projects file under
  their project group with the desktop's indent; the collapse spinner
  shows only after 500 ms; "Reopen to update" keeps the rows on screen.
- e2e helpers and journeys for the switch-on suite.

* fix(sidebar): keep an owed relay stop marked, clear a thrown stop, and prune pending unread raises

- A stop-and-wait that throws takes its stop request back, like one that fails.
- A final stop the legacy relay still owes stays marked, since the relay retries it.
- Pending unread raises are tracked only while one waits, so the map no longer grows.
- The paired-server fallback poll test gives its third fetch a reply and asserts live.

* feat(sidebar): main publishes cached snapshots and announces its own stores; detected, view and live-content domains (inert)

* fix(sidebar): keep links confirmed only by a new git run, no rescan on metadata writes, no phone wait on detected checkouts

* fix(sidebar): rescan the workspace rows when the Windows runtime default changes

* feat(sidebar): one lifecycle queue per workspace in main, with in-progress hints (switch-gated)

Create, delete, terminal.closeAll, terminal.sleep and worktree.sleep now run through one
first-in, first-out queue per host-qualified workspace: strict order, no merging, delete
cancels what has not started and waits for what has, an unconfirmed outcome pauses until
the host's own answer. Hints publish in a new inProgress feed domain (no reader yet); the
creations domain is its projection. A finished create or delete keeps its hint until a scan
started after it applies, in the same revision. Adds the paired-server metadata serializer
(saving domain, no caller yet). Replaces the creation registry.

* fix(sidebar): a create never queues behind the previous occupant's delete

* feat(sidebar): main runs sleep; the window follows (P3b)

* fix(sidebar): keep electron out of the headless server's sleep path

The desktop registers how sleep reaches paired servers; a headless serve has none.

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

* test(sidebar): type-check the sleep e2e specs; drop the removed VM suspend stub

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

* fix(sidebar): resume a paused workspace by re-observing, never replaying

- A command issued while paused waits behind the pause; when the owner answers again main
  re-reads terminal liveness and the listing, then carries on. A forced delete runs past it.
- Commands keep their arrival order across a workspace lookup; deletes by name key by the
  resolved id, so they wait for that workspace's running sleep.
- A second delete with different options is refused as already in progress.
- Close and delete read lost contact as sleep does.
- A create always frees its own queue entry, even after a retry took over its id.
- Drops the unused opId, and the paired-server write serializer and its feed section,
  which land with their first caller.

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

* fix(sidebar): main is the only writer of a sleep's wake records; sleep classifies only lost contact as unconfirmed

- The window no longer captures wake records for a sleep main runs; it takes main's records
  from main's answer, which its wake and tab-open resume then read.
- A workspace reopened during its sleep keeps its VM running (the window and a phone's
  activation tell main).
- Only lost contact pauses: a definite chat-stop failure or a server's still-live answer is a
  plain failure with today's toast.
- A paired server's chats are asked with the Sleep mark, and again without it when an older
  server refuses the field, instead of reading an unprobed status.
- A phone's worktree.sleep is answered on acceptance and its activation no longer waits on a
  queued wake, so neither can outlast the phone's request timeout. The web client passes
  markChatsAsleep and keeps the receipts.
- One desktop adapter, passed where the desktop builds the runtime, replaces the two module
  slots; a headless server gets none.

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

* chore(sidebar): share worktree.sleep's params with the RPC catalog; lint fixes

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

* test(sidebar): test the paired-server sleep where main runs it; drop the window's copies

The window no longer sleeps a paired server's terminals, so its convergence and order tests for
that path move to main (remote-workspace-terminal-sleep.test.ts) or follow main's answer.

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

* test(sidebar): retry the sleep spec's liveness read while terminals stop

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

* fix(sleep): main resumes every workspace-sleep wake; the window only attaches

- Main claims and starts each slept pane through its windowless resume path, with or
  without a window: the "window present" check is gone.
- A phone's open queues main's wake, which finishes only once the resumes have started,
  and always notes the reopen so a running sleep leaves the VM up.
- The window no longer relaunches a workspace sleep's records in fresh tabs; opening a
  slept pane asks main to resume it and the pane's spawn attaches to main's terminal.
- A window save cannot overwrite main's workspace-sleep records.
- A VM that would not suspend no longer reads as "kept open": the terminals slept, and
  the toast says the machine is still running.

* test(e2e): main resumes a slept pane once, in place, and keeps its record

* chore(i18n): add the VM-still-running sleep message

* fix(sleep): a phone's or the CLI's failed sleep shows the desktop toast again

* fix: restore main's final P2 test fixes a merge reverted

* fix(sleep): window saves never write or clear main's sleep records; headless wake report counts only real sleeps

* test: a same-id twin's grace follows the rows' change, not the removed catalog hook

* fix(sleep): drop the 1 s settle wait after an observed exit, and wake a slept workspace's mounted agents on phone open

A workspace sleep stopped each terminal through main's stop-and-verify, which polled for a
further second after the exit it had already seen. And a phone opening a slept workspace no
longer reached the window's mounted panes of agents that had finished before the sleep, so
they stayed asleep until the window opened their tab.

* test: give the workspace-sleep wake record its prompt field

* refactor: match slept-agent records to the workspace with worktreeIdsEqual

* chore(sleep): one import from sleep-record-pane-claim

* test(sleep): route the disconnected-sleep SSH spec, declare the desktop sleep adapter, and open the workspace after its sleep starts

* test(sleep): delete a workspace the spec creates, not the seeded one later specs share

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 19:39:07 -04:00
Kelvin Amoaba e0bd073930 feat(browser): Chrome-style page context menu and DevTools window shortcuts (#31821) 2026-10-22 22:36:18 +00:00
Kelvin Amoaba 44ab202965 fix(native-chat): show spelling suggestions when right-clicking chat inputs (#32035) 2026-10-22 21:55:57 +00:00
Neil 9c4ad143bb refactor: colocate Jira favourite-filter contracts (#32102) 2026-10-22 14:30:36 -07:00
Neil 59497680d8 refactor: colocate Jira issue summary generation (#32099) 2026-10-22 13:42:03 -07:00
Jinjing 8fc1698ebb Add Resource Manager PTY inventory and checked terminal termination (#31593)
* feat(resources): end local terminals with checked identity checks

- Add a PTYs view to the Resource Manager that lists local terminals and can end one. Before stopping, the host confirms the terminal's incarnation, agent ownership, and attachments. This prevents ending a same-ID replacement that started after the list was read.
- Bump the daemon protocol to v50 and gate the new fenced kill on it. Older daemons ignore the extra fields, so the client refuses End instead of sending an unchecked kill.
- Admit diagnostic reads (PTY listing and memory snapshot) only while the Resources view is visible, so a hidden window does no background scanning.
- Report incarnation and host on spawn and exit events so the renderer can match them to the terminal it showed.
- Replace the popover's terminal-session list with the new inventory and move memory polling into the Resources view.

* Show unrouted daemon PTYs in the Resource Manager

* Simplify PTY controls and clarify safe termination

* Format local build compatibility protocol lists

* Add PTY resource management localization strings

* Harden PTY resource manager test fixtures

* Use typed IPC event in PTY kill test fixture

* Refine local PTY resource view model typing

* Refine local PTY resource view model typing

* Include local host identity in PTY lifecycle event tests
2026-10-22 12:20:01 -07:00
Jinjing f1189be850 Offer Resolve with AI for paused merge, rebase, and cherry-pick (#28569)
* Offer Resolve with AI for paused merge, rebase, and cherry-pick

A paused operation can need recovery after every conflict is staged, but the Resolve with AI action only appeared when unmerged paths remained. The operation banner now offers it whenever AI actions are visible and an operation is in progress.

Starting an AI conflict-resolution agent is also blocked while a Git operation is running. The composer, the banner and card buttons, and the agent launch itself check the running-operation state, so a launch that began during agent detection cannot start while Git is still running.

* Block paused-operation recovery only on Orca's own Git work

The previous gate scanned the host's process table and refused "Resolve with AI" whenever it could not prove no Git process was running. That refused recovery on older paired hosts, on Windows whenever any Git process ran anywhere on the machine, and while a paged `git reflog` or `git grep` was open in a terminal.

- The host tracks Orca's own mutating Git commands per worktree (including ones still queued) and reports them through `git.mutationInFlight`. Reads and fetch/push/ls-remote are not tracked.
- Recovery is refused only when the host reports that work. Older hosts without the method keep today's behavior.
- The gate applies only to launches from the paused-operation banner and conflict card, not every resolveConflicts launch, so the Checks panel's PR-conflict flow is unchanged.
- The agent prompt now tells the agent to stop if index.lock exists or another git command is running, which covers Git started outside Orca on every host. With no unmerged files, the prompt asks the agent to find why Git paused instead of listing zero conflicts.

* Preserve Git mutation state until terminated commands exit

- Cancel stale recovery checks and agent launches when their dialog or scope closes
- Guide rebase recovery agents to amend fixes after failed exec steps

* Cover failed rebase exec recovery with real Git

* Recognize global Git options in worktree mutation tracking
2026-10-22 12:08:38 -07:00
Neil a1448f9f58 refactor: colocate Jira image and stream contracts (#32079) 2026-10-22 11:10:10 -07:00
Brennan Benson 726c572da7 Attach a long paste as a text file, and say a message is too large before it is sent (#30398)
* fix(native-chat): attach a long paste as a text file, and say a message is too large before it is sent

A paste of 32 KB or more (or one that would push the message past the 256 KB
send limit) into a structured chat is saved as a file the agent reads, through
the same pending-chip and @path route a dropped file takes: Orca's paste folder
here, or the chat's attachment store on its paired server. Claude gets the paste
folder as an allowed directory. A message still over the limit is handed back
before it is sent, on desktop and the phone, with words naming the limit instead
of the generic 'not sent, send it again'.

* test: Claude launch parity snapshot grants the paste folder

* fix(native-chat): a long paste replaces the selection at once and settles in place

A long paste now puts an inline Pasted text pill where it went, replacing any
selected text immediately, and the saved file (or inline text, or the original
selection on failure) replaces that same pill when the save finishes, in its own
chat's draft. Nothing reads the caret later, so order and position hold. The
paste never joins the image row, so image numbers are unchanged. The size check
measures the real message body with the selection replaced and images included.
A server that keeps no files takes the paste inline when the message still fits.
A pending paste a restart lost shows Paste not saved, and Send says so.

* fix(native-chat): type the pasted-text parser and the composer's missing draft scope

* fix(native-chat): admit paste references before goals and commands

* fix(native-chat): resolve staged paste paths without editing the draft

* fix(native-chat): consolidate paste imports for code quality checks

* fix(native-chat): retain checked string types for saved paste paths

* fix(native-chat): retain completed paste facts through history and delimit paths

* fix(native-chat): keep structured question rendering within file limit

* fix(native-chat): pasted or inserted text that looks like a paste token stays literal

* fix(web): keep the browser's UI bridge under the file length limit

* style: format the files #29982 merged unformatted

* fix(native-chat): retain oversized drafts before send admission

* fix(native-chat): keep the composer handle's merge resolution to main's destructure
2026-10-22 10:16:32 -07:00