Commit Graph
2105 Commits
Author SHA1 Message Date
Kelvin Amoaba 846851237c feat(browser): per-repo or per-workspace browser profile for new tabs (#32039) 2026-10-23 15:20:11 +00:00
NeilandClaude d10626876e Watch only the files Orca needs in its settings folder and .git, instead of the whole folders (#32410)
* perf(watch): stop watching all of userData and .git for a handful of files

On macOS a directory fs.watch is a recursive FSEvents stream. Two watches used
that to notice a few files:

- The Active Server preference watched the whole userData directory for
  orca-environments.json, so Orca's own writes there (agent-hooks status,
  terminal history, browser caches; ~10 events/s measured) were routed back
  to it.
- The shallow git metadata watch ran fs.watch on each repo's whole common
  .git dir (and .git/logs), receiving objects/, refs/, lfs/ and every linked
  worktree's churn to see six files.

Both now watch the individual files (kqueue on macOS, no fseventsd) through a
new rebinding file watch: events and a 30s sweep re-stat the path, rebind when
a rename-replace or deletion moved it, and pick up files created later. Events
are confirmed by a stat (size/mtime/ctime/inode) because macOS raises an
attribute event for every mmap read of the index and packed-refs; the watch is
one-shot with a backing-off window so a file every git process maps costs about
one rebind a second instead of a wakeup per read. The registry path is
unchanged, so CLI/serve readers and older peers are unaffected. Linux and
Windows keep the non-recursive directory watch for shallow subscriptions.

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

* fix(watch): don't hang unsubscribing an errored watcher; find late metadata files sooner

- Node closes an errored fs.watch handle without emitting 'close', and a later
  close() is a no-op, so awaiting 'close' could hang a watcher-child unsubscribe
  and every subscribe queued behind it. Errored watchers are now dropped without
  a close, and closeFileSystemWatcher also settles on 'error' or after 1s.
  Applies to both the macOS file watch and the Linux/Windows directory watch.
- Missing metadata files (packed-refs from pack-refs/gc) are re-statted every
  2s instead of waiting for the 30s rebind sweep.
- On macOS the delivery probe watches a file, matching the kqueue path the
  shallow subscriptions now use.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-23 05:29:47 -07:00
NeilandClaude a233040067 File watching rides out a slow system instead of restarting, and turns itself back on after a cooldown (#32397)
* fix(watcher): back off on system event stalls and let the crash fuse recover

The watcher child's canary treated any missed delivery as a native deadlock
and exited. When the OS event source itself is stalled (an overloaded macOS
file-event daemon), each restart recreated every stream, adding load, and
after three restarts in two minutes the crash fuse disabled native watching
until the app restarted.

- Before exiting on a starved canary, probe the same dir with an independent
  fs.watch. If fs.watch delivers, it is a child deadlock: restart as before.
  If both stay silent (and fs.watch was proven to work on this host), it is a
  system stall: keep the child and its streams and back off the canary
  (30 s doubling to 5 min) until delivery resumes.
- The crash fuse now half-opens after an exponential cooldown (5 min doubling
  to 60 min) so native watching is retried; callers keep their polling
  fallback while it is open. A trial crash reopens it immediately; a trial
  that stays healthy for 10 min resets the escalation.
- Arm the canary while a native subscribe is pending: always on macOS (its
  subscribe does not crawl), and after a 10 min grace on crawling backends,
  so a subscribe stuck behind a deadlock no longer disables the check.

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

* fix(watcher): bound stalls, keep callers fresh, and let the fuse reopen reach callers

Review follow-ups for the watcher stall/backoff change:

- fs.watch proof is no longer a cached startup probe. Any delivery in the
  process (including the canary's own fs.watch) proves it; a failed shallow
  probe is re-measured after 30 s instead of failing shallow subscribes forever.
- The canary keeps one long-lived fs.watch on its dir and checks whether it
  delivered since the probe started, instead of opening one per probe (which
  makes macOS rebuild the shared event stream).
- Any native callback in the child during the probe window counts as proof the
  child is not deadlocked. A stall that lasts 15 min forces a restart, still
  rate-limited by the crash fuse.
- The child reports delivery health (healthy/stalled) to the host. A stall that
  outlasts one backoff period makes the host send an overflow (rescan) to every
  subscription on that cadence, and once more on recovery.
- Roots that fail while the crash fuse is open are no longer cached as
  unwatchable until shutdown, and the git-common narrow watch's polling
  fallback retries native events every 5 min. Log wording no longer claims
  every caller polls.
- Linux/Windows keep the canary disarmed during a pending crawl (huge or
  network trees); macOS stays armed.
- Fuse escalation resets only after the trial child's canary has confirmed
  delivery for 10 min, not merely after it survived 10 min.

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

* fix(watcher): back off stall rescans and end stalls when the canary disarms

- Host rescans during a stall now back off with the canary (30 s doubling to
  5 min) instead of every 30 s for the whole stall, and stop once no
  subscription is live.
- A canary that disarms after a stall (no live roots, or a crawl on
  Linux/Windows) reports 'unknown', which ends the host's stall mode with one
  rescan; the stall is re-detected once the canary re-arms. The crash fuse
  ignores 'unknown'.
- Health reports are ignored after supervisor disposal (they were already
  limited to the current child).

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-23 05:20:42 -07:00
Neil 551108aea8 test: finish fixture work before unit-test cleanup (#32285) 2026-10-23 02:56:38 -07:00
Neil 88de2dbacb fix(web): the browser client advertises the desktop's chat capabilities, so its host opens chats (#32253)
* fix(web): the browser client advertises the desktop's chat capabilities, so its host opens chats

The browser client's handshake never named agent-session.structured.v1, so a paired
host refused every agentSession call with structured_agent_session_unsupported and
withheld chat tabs. The desktop window, the Electron remote handshake and the browser
client now build their lists from one shared array of what the renderer's chat implements.

Fixes #32145

* refactor(web): keep the browser client's capability list beside the desktop's in shared

The host-side test parses both handshakes with the host's own parser, which the node
typecheck project can only import from src/shared.

* test(web): assert close-intent support in the auth frame, not the whole capability list
2026-10-23 02:44:40 -07:00
Jinjing 54e8ee5e96 Scope daemon inventories for safe worktree teardown (#32171)
* Fix scoped daemon inventories without changing terminal input routes

* Serialize daemon owner inventory refreshes safely

* Serialize daemon owner inventory refreshes safely

* test(daemon): protect baseline inventory budgets and recovery
2026-10-22 23:01:16 -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
Neil d7f6234274 fix(ssh): scope launch-session verdicts to managed environments (#32047) 2026-10-22 20:30:38 -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
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
Brennan Benson 814bb59ef6 fix(runtime): release remote streams when the renderer reloads (#29104)
* fix(runtime): release remote streams when the renderer reloads

* ci: re-run code scanning (no source change)
2026-10-22 11:42:13 -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
Brennan Benson 9613563f5c refactor(pty): one commit step for both terminal start lanes (#31596)
* refactor(pty): one commit step for both terminal start lanes

The window's pty:spawn commit and the host runtime controller's commit were two
copies of the same job (ownership, binding save, registration, size, hidden
mark, publication, reservation settle), so every fix had to land twice.

Both lanes now call one commitPtySpawn and supply what differs as data: the
binding each lane builds, its registration facts, pane key and aliases, the
Codex launch env and memory session id. Three inputs still select behavior:
hiddenDelivery (the renderer-scoped mark is refreshed here; the runtime-owned
mark stays at the host runner's await boundary), earlyExit (the window drains an
exit during start, the host throws) and joinPayload (what reservation joiners
and the caller receive).

One publication order for both lanes: note commit, Codex pane account, renderer
hidden mark, handle, size set with reflow, old-id size cleanup, serializer
readiness, restore records, command detector, telemetry, pane key and aliases,
memory registry, resume identity, inventory, Codex lifecycle, settle. Every
moved step was audited for read/write independence. Stable-owner adoption and
the adopted-claim publication set are unchanged.

Also pins that an agent launch whose record cannot open takes its tab back and
spawns nothing, and re-labels three TEMPORARY comments to their current owners.

* fix(pty): preserve adopted claim return scheduling

* fix(pty): keep shared commit reply types precise
2026-10-22 10:03:07 -07:00
Neil a3fa44ad07 fix(push): honor "only when desktop is away" on headless orca serve (#31956)
* fix(push): decide orca serve's desktop-away from attached desktops (#31570)

* fix(push): report away on sleep and lock, guard late reports and prune stale presence

* chore: justify the presence-reporter state slot widening

* fix(push): hold away from suspend or lock until resume or unlock

* fix(push): key presence sockets by connection instance so a replaced connection reports at once
2026-10-22 03:36:10 -07:00
Neil 6a9a80a7fe feat(telemetry): daily aggregate WSL usage snapshot on Windows (#31406)
* feat(telemetry): daily aggregate WSL usage snapshot on Windows

Adds a main-owned wsl_usage_snapshot event through the existing PostHog
track() pipeline (same consent, opt-out, build gate and validator): WSL
installed/version, distro counts (installed, running, WSL1/2), WSL-backed
project counts (distro fs vs Windows drive, git vs folder), distinct project
distros, and the internal WSL-hosts gate. Counts are bucketed; no paths or
names leave the machine. At most once per 24h per install, Windows only.

* fix(telemetry): bound WSL snapshot retries and name the default distro

Stamp before gathering so a failing gather isn't repaid hourly, treat a
future stamp as due, resolve 'default distro' to its name for distinct
counts, narrow the store type, and cover the running-probe choice and the
closed WSL-hosts gate in tests.
2026-10-22 03:34:31 -07:00
Neil 8967b10d41 chore: remove verified dead code and calibrate Knip entries (#31903)
* chore: remove verified dead code and calibrate Knip entries

* fix: include mjs consumers in dead-code analysis
2026-10-22 02:19:04 -07:00
Neil dc315a4e5a refactor(ssh): remove the dead SSH filesystem provider and desktop SSH file watcher (#31922)
* refactor(ssh): remove the dead SSH filesystem provider and desktop SSH file watcher

Nothing in production has registered an SSH filesystem provider since the
relay removal (#27214/#27215), so every getSshFilesystemProvider read
returned undefined. Delete the provider table and the remote watcher
subsystem, and collapse the call sites to that always-undefined behaviour:
fs:watchWorktree/fs:unwatchWorktree ignore SSH roots, the worktree base
watcher only resolves local repos, and worktree removal skips the desktop
watcher for SSH paths.

* test: drop the nested SSH watcher catalog case that can no longer occur

The base-directory watcher never carries a connection id now, so the
host-blind-event guard it exercised is gone. Also prune the deleted remote
watcher suites from the shard timings and the nested-SSH wording from the
worktree catalog reliability gate.
2026-10-22 01:54:29 -07:00
Jinwoo Hong 4165c9545c Layout groundwork (switched off): main tells the window whether its start resumed a pane's agent, so the restored banner and reopen count come back (#31908)
* feat(terminal): the window's store shows main's pane start status (layout-owner build)

A status-only frame changes one store entry and no pane tree, so the pane's view stays mounted.

* refactor(terminal): keep the frame sync within its line budget

* feat(terminal): every pane main starts shows 'starting' from before it is written (layout-owner build)

* feat(terminal): a pane main is starting waits and attaches; a failed start shows why (layout-owner build)

Fixes owner-visible row 15: a failed agent or setup start no longer opens a plain shell.

* test(terminal): iterate store listeners directly

* fix(terminal): an exit that reports no code keeps its pane, as lost contact (layout-owner build)

* test(terminal): a pane main started attaches to main's terminal at its own grid

* test(terminal): detach census tests assert main's move and frame with the switch on

* fix(terminal): a restored pane paints history only from its terminal's host, never the window's copy (layout-owner build only)

* fix(terminal): main releases a painted cold restore only for the pane's current terminal (layout-owner build only)

* test(terminal): typed ack args in the painted cold-restore test

* test(terminal): exited-pane tests assert main's close with the switch on

These 8 have failed switch-on since #31130 moved the exit close to main.

* feat(layout): main starts the panes a client's startPane or wake names, through its one restored-pane starter (layout-owner build only)

The model's start and stop effects reach the runtime once the command is written, never the
reply. startPane starts a pane whose binding has a start status, and a slept pane from its record.
A wake keeps a pane's resume record until its start binds; a failed start keeps it and shows why.
With the switch on, main owns a running agent's wake even with a window open.

* fix(layout): a window's wake of a pane it resumed itself is record-only, so main does not start it again (layout-owner build only)

* test(layout): a client's startPane starts the pane before any other trigger

* Revert "fix(terminal): a restored pane paints history only from its terminal's host, never the window's copy (layout-owner build only)"

This reverts commit a646d89b26.

* test(terminal): the cold-restore repaint ack names its pane in the layout-owner build

* fix(layout): a wake keeps the pane's resume record in the pane-owned form, so a host crash resumes the agent again (layout-owner build only)

* test(layout): a failing start in the pane-start runner test throws

* feat(terminal): main writes and starts every split of a pane it holds; the window attaches (layout-owner build)

The window's split, a startup split with its command, and a CLI split all go through main's
terminal.split; main's frame mounts the pane, with or without a window intent. Deletes the
window's split wait and withdraw, the split appear intents, and the queued-split skip and cancel.
The e2e helper uses the real split. A startup split leaves focus on its source pane.

* fix(terminal): the attach-only wait leaves sleeping, resuming and held panes to their restore path

* fix(terminal): a split pane attaches to the terminal main bound it to; a taken pane id is refused

Also restores the proof that a split closed while it starts gets one answer and leaves no
pane or start status behind.

* Reapply "fix(terminal): a restored pane paints history only from its terminal's host, never the window's copy (layout-owner build only)"

This reverts commit 420e605ad0.

* fix(layout): a trigger between a restored pane's start and its bind write joins that start, not a second one (layout-owner build only)

* fix(terminal): a window split main cannot start still shows its pane, failed, with why

* fix(terminal): keep the switch import the D1b-1 merge dropped from the layout restore

* feat(layout): main's starter shows a restored pane starting before any await, and a failed start with its reason; startPane starts a pane whose bound terminal ended (layout-owner build only)

* feat(terminal): a window's attach-only view of a pane attaches to its terminal or starts nothing, keeping the binding for main's start (layout-owner build only)

* feat(terminal): a restored pane with no live terminal asks main to start it and attaches once main binds it; the window's wake, hibernated wake, restart-on-show and gone-terminal fallbacks route through main (layout-owner build only)

* fix(terminal): check a taken pane id first, keep the start's own error, clear a gone pane's status

Three test stores gain the pane-start field the window's store always has.

* test(terminal): the admission stub answers whether its pane is still written; a closed pane's failed start clears

* test(terminal): with the switch on, the window's restores, wakes and restart replacements ask main to start the pane and attach to the terminal main binds, starting and resuming nothing themselves

* refactor(terminal): the rebound workspaces' bindings show through one call in the bindings module

* fix(terminal): a held pane connects as today so main's refusal holds it; main's start follows output; a capacity death after main's resume keeps the resume (layout-owner build only)

* fix(layout): main passes its start options only for commands that start panes; a windowed open resumes the agent under main (layout-owner build only)

* refactor(terminal): break the pane start module cycle; typed test fixtures

* test(terminal): a pane main wrote and the user closed mid-start drops its failed status

* fix(terminal): every waiter on main's start runs, a failed or refused start settles and is asked again on the next view, a hidden gone pane waits for its view, a twin main hands back stays on today's path, and lost contact never starts a pane (layout-owner build only)

* test(terminal): iterate the store listeners directly

* test(terminal): a cold-restore paint applies no window resume with the switch on

* fix(terminal): a split main starts is listed to phones and session.tabs without a window's report

* test(terminal): name the main pane start test helper as a fixture

* fix(terminal): a reconnect shows its pane starting and why it failed; a lost owner race shows no failure; a split no one asked to see keeps the phones' tab

* fix(terminal): a kept create another owner won shows no failure; the window attaches to the winner

* fix(terminal): a pane main starts at relaunch keeps its full history and starts before the window's graph lists its tab (layout-owner build only)

* feat(terminal): main replaces the empty shell a hibernated agent left and resumes the agent when a view asks; a start main could not attach shows main's own terminal_not_started (layout-owner build only)

* test(terminal): main seeds its copy of a restored pane even when a window declared one, with the switch on

* fix(terminal): a pane main started hidden paints once when its view attaches (switch-on builds only)

The view's attach snapshot, taken after main unmarks the hidden gate, already holds the bytes main
dropped, so the reveal no longer asks a second restore from main's buffer.

* refactor(terminal): main's pane start reads the pane from its own layout, not the client projection (switch-on builds only)

* fix(terminal): a pane restart stops its terminal before writing the pane unbound, so a stop that fails keeps the pane (switch-on builds only)

* test(terminal): a start main could not bind shows terminal_not_started through the window's wait, from one copy site (switch-on builds only)

* fix(terminal): main's pane start resumes an agent recorded under the pane's number, as the window did; stale switch-on tests show main's start and the known banner loss (switch-on builds only)

* fix(terminal): review round: a visible view alone retires main's hidden-start drops, by episode; main reads a split pane's numbered record by its number; the window keeps a shell main kept (switch-on builds only)

* fix(terminal): main's start of a pane a window view is attaching to leaves it visible, so the view paints once (switch-on builds only)

* fix(terminal): a window view that attaches while main starts its pane takes main's start, with no second provider attach (switch-on builds only)

* fix(terminal): review round: a view takes main's start only when it carries a payload and still owns its terminal; attaching views are counted, keep main's pre-spawn mark off, and a failed attach hides only what it kept visible (switch-on builds only)

* test(terminal): checked test doubles in the view-join and numbered-record tests; reattach options fit the file budget

* test(e2e): with the switch on, the mount-authority spec keeps the window's bindings, which only main's frames write

Claude-Session: W5b

* test(e2e): the mount-authority spec fits its line budget; the layout-owner build check is one helper

Claude-Session: W5b

* test(layout): an unbound pane holding a resume record starts and keeps the record, since main's start resumes from it

Claude-Session: W5b

* fix(terminal): a pane main resumed holds a running agent's record, so it reads awake, not sleeping (switch-on builds only)

Claude-Session: W5b

* fix(terminal): in a split where no pane owns a numbered record, main resumes the tab's one conversation in pane 1 only (switch-on builds only)

Claude-Session: W5b

* fix(terminal): main marks only the record a resume started from live, never a sleep captured after it (switch-on builds only)

Claude-Session: W5b

* test(terminal): with the switch on, a windowless resume leaves the pane's record a running agent's

Claude-Session: W5b

* test(terminal): the resumed-record test double typechecks

Claude-Session: W5b

* refactor(terminal): with the switch off, main's pane start reads no resume record for the live mark

Claude-Session: W5b

* fix(terminal): main publishes whether its start of a pane resumed the agent, for the window's banner (switch-on builds only)

Claude-Session: W5b

* fix(terminal): a pane main started shows its "session restored" or "resume unavailable" banner again (switch-on builds only)

Claude-Session: W5b

* test(terminal): the resume-banner store double carries no type assertion

Claude-Session: W5b

* fix(terminal): main records a resume outcome only when its start wakes the pane's own sleeping record, and each new start clears the old one (switch-on builds only)

Claude-Session: W5b

* fix(terminal): a renderer reload shows no resume banner again for a pane main started, and the window stops waiting once that pane holds another terminal (switch-on builds only)

Claude-Session: W5b

* refactor(terminal): the merged files fit their line budget: the folder-fallback notice and a hidden pane's wait for its first view are helpers, and the answering-transport lookup moves to its one test caller

Claude-Session: W5b

* fix(terminal): main's resume outcome arrives in the same frame as the terminal it names, a same-id respawn included (switch-on builds only)

Claude-Session: W5b

* fix(terminal): the reopened-terminals toast counts agent sessions main resumed again (switch-on builds only)

Claude-Session: W5b

* refactor(terminal): the attach's resume check names the window's resume type

Claude-Session: W5b

* test(terminal): pin the resume outcome's wire contract: an outcome alone rebinds nothing, it shows once per start, and no saved session holds it

Claude-Session: W5b

* refactor(runtime): the window's layout apply fits the runtime's line budget after the main merge

Claude-Session: W5b

* test(terminal): any create through main that wakes a pane's record publishes its outcome, and the sidebar resume keeps its restored banner (switch-on builds)

Claude-Session: W5b

* refactor(runtime): the layout stream takes main's pane facts from one source, keeping the runtime in its line budget

Claude-Session: W5b

* fix(terminal): a relaunch resume into a pane kept under its saved terminal id shows its banner again, and a start whose bind fails leaves no outcome (switch-on builds only)

Claude-Session: W5b

* fix(terminal): the reopen toast counts only a resume main made for the attached terminal since the attach began, and the banner reads main's outcome once at attach (switch-on builds only)

Claude-Session: W5b

* test(terminal): two pane test stores carry main's resume outcomes, which every attach now reads

Claude-Session: W5b

* test(terminal): the hidden-output repro's test store carries main's resume outcomes

Claude-Session: W5b

* fix(terminal): an SSH same-id resume whose bind writes nothing new keeps its banner, and a start that lost its pane leaves the winner's outcome (switch-on builds only)

Claude-Session: W5b
2026-10-22 04:35:42 -04:00
Neil 73841a0720 fix(worktrees): pick a repo's catalog watcher transport from its resolved SSH target (#31872) 2026-10-22 00:02:14 -07:00
Neil 57f1fce9bb refactor(runtime): type worktree query stores with checked guards instead of casts (#31864) 2026-10-21 23:53:30 -07:00
Neil 35596d16a5 chore: replace electron-toolkit utilities with Electron APIs (#31824)
* chore: replace electron-toolkit utilities with Electron APIs

* refactor: reuse development flag within startup preflight
2026-10-21 21:52:08 -07:00
Neil 0a7d6bb2d5 refactor(main): group ephemeral VM lifecycle modules (#31771) 2026-10-21 21:31:21 -07:00
Jinjing a53c2a2a72 Add onboarding language selection (#31784)
* Add onboarding language selection and system locale detection

- Detect and synchronize native/browser language preferences safely
- Load catalogs before rendering onboarding and support recovery
- Let users choose a supported language or request another language

* Add onboarding language experiment cohorts and detection recovery

* Stabilize onboarding language detection tests

* Test persisted onboarding language cohort behavior
2026-10-21 19:43:22 -07:00
NeilandClaude 56143a9a5e feat(ssh): open a plain SSH terminal to a host whose move to its Orca server is blocked (#31716)
* feat(ssh): open a plain SSH terminal to a host whose move to its Orca server is blocked

A refused or unserved host fails the whole connect, so the user had no way to
reach their work there. The blocked-move banner and the SSH host row now offer
an unmanaged, unpersisted ssh login in a non-modal window. Main builds the argv
from the saved target (no -T, BatchMode or Orca multiplexing; the config alias
stays bare so ssh_config applies) and spawns ssh with an argv array through the
local PTY spawn primitive.

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

* fix(ssh): claim a host before awaiting, wait for ssh on quit, and share the preview terminal's keys

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

* fix(ssh): give the plain SSH terminal Orca's Unicode widths, kitty flags and spawn-helper repair

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

* refactor(terminal): one standalone terminal for the agent preview and plain SSH

Extracts the preview's xterm setup (Unicode widths, links, IME bridge, kitty
flags, copy/paste and shortcut policy, user-input routing) into
openStandaloneTerminal, so the plain SSH terminal reuses it instead of a second
copy. Plain SSH output is now acked once rendered, and main pauses ssh while too
much is unrendered.

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

* fix(ssh): plain SSH answers terminal queries, keeps early exits, and ends a paused pty on Windows

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

* fix(ssh): plain SSH applies theme changes live and never refits while minimized

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

* fix(ssh): a native call on a just-exited plain SSH pty never crashes main

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

* test(ssh): give the plain SSH test's ResizeObserver stub unobserve, which Tooltip needs

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 19:35:32 -07:00
NeilandClaude 7a912a3a24 Autosave relies on the guarded save instead of pause flags; identical saves don't rewrite; non-UTF-8 files aren't autosaved (#31768)
* Autosave relies on the guarded write instead of pausing restored or moved tabs

Delete the pendingDiskBaselineVerification and pendingLiveDiskVerification
pause flags. Every editor save is already a guarded write; a refusal raises
the changed-on-disk banner, which is what stops autosave until an explicit
save.

A guarded write now succeeds when disk changed but already holds exactly the
text being saved (local/host compare is byte-exact; client-side fallbacks
compare decoded text and refuse when it holds U+FFFD), so a restored draft
that matches disk goes clean instead of showing a banner.

The restore scan only raises the banner early for tabs that arrive dirty; a
watch resync no longer re-checks dirty tabs.

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

* fix(editor): skip guarded saves when disk is already identical

Return a compatible optional no-op result from hosts and client fallbacks, clean the tab, and clear its provisional self-write stamp without rewriting identical bytes.

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

* fix(editor): refuse lossy automatic saves, keep identical-skip on older hosts, flag dirty tabs on resync

- Autosave and pre-restart saves refuse when disk text can't be decoded losslessly, so a
  baseline that decoded to U+FFFD can't authorize overwriting different bytes.
- New files.write.identical-noop.v1 capability; for hosts with only the v1 guarded write the
  client compares first, skips identical saves, then delegates to the host's guarded write.
- Watch resync compares dirty tabs against disk and shows the changed-on-disk banner.
- Local guarded writes check for identical content before the write-only regular-file probe.

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

* fix(editor): tell non-UTF-8 files apart from disk changes, and quiet false resync banners

- Local guarded writes judge losslessness by bytes, so a valid UTF-8 file containing U+FFFD
  autosaves again. A file that really isn't UTF-8 is refused with its own reason, 'not-utf8'
  (older clients read it as 'changed'), which pauses autosave for that file with one notice
  until an explicit save converts it.
- A watch resync whose disk read fails leaves dirty tabs alone; the guarded save still catches
  a real conflict.
- Resync and restored-tab checks treat disk holding the tab's own just-written save as an echo.
- On hosts with only the v1 guarded write, only automatic saves read the file first; explicit
  saves go straight to the host's guard.

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

* fix(editor): lift the non-UTF-8 autosave pause when its edits end, and report disk changes first

- The pause is released once no dirty tab of the file remains (close, reload from disk,
  discard), so a reopened or reloaded file's next autosave asks the host again and notifies.
- Client-side precondition checks compare the signature before looking for U+FFFD, so an
  external rewrite shows the changed-on-disk banner rather than the non-UTF-8 notice.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 19:20:04 -07:00
Jinwoo Hong ed13ca1e6f Layout groundwork (switched off): main starts and restores every pane, and the window only attaches and paints the host's history (#31567)
* feat(terminal): the window's store shows main's pane start status (layout-owner build)

A status-only frame changes one store entry and no pane tree, so the pane's view stays mounted.

* refactor(terminal): keep the frame sync within its line budget

* feat(terminal): every pane main starts shows 'starting' from before it is written (layout-owner build)

* feat(terminal): a pane main is starting waits and attaches; a failed start shows why (layout-owner build)

Fixes owner-visible row 15: a failed agent or setup start no longer opens a plain shell.

* test(terminal): iterate store listeners directly

* fix(terminal): an exit that reports no code keeps its pane, as lost contact (layout-owner build)

* test(terminal): a pane main started attaches to main's terminal at its own grid

* test(terminal): detach census tests assert main's move and frame with the switch on

* fix(terminal): a restored pane paints history only from its terminal's host, never the window's copy (layout-owner build only)

* fix(terminal): main releases a painted cold restore only for the pane's current terminal (layout-owner build only)

* test(terminal): typed ack args in the painted cold-restore test

* test(terminal): exited-pane tests assert main's close with the switch on

These 8 have failed switch-on since #31130 moved the exit close to main.

* feat(layout): main starts the panes a client's startPane or wake names, through its one restored-pane starter (layout-owner build only)

The model's start and stop effects reach the runtime once the command is written, never the
reply. startPane starts a pane whose binding has a start status, and a slept pane from its record.
A wake keeps a pane's resume record until its start binds; a failed start keeps it and shows why.
With the switch on, main owns a running agent's wake even with a window open.

* fix(layout): a window's wake of a pane it resumed itself is record-only, so main does not start it again (layout-owner build only)

* test(layout): a client's startPane starts the pane before any other trigger

* Revert "fix(terminal): a restored pane paints history only from its terminal's host, never the window's copy (layout-owner build only)"

This reverts commit a646d89b26.

* test(terminal): the cold-restore repaint ack names its pane in the layout-owner build

* fix(layout): a wake keeps the pane's resume record in the pane-owned form, so a host crash resumes the agent again (layout-owner build only)

* test(layout): a failing start in the pane-start runner test throws

* feat(terminal): main writes and starts every split of a pane it holds; the window attaches (layout-owner build)

The window's split, a startup split with its command, and a CLI split all go through main's
terminal.split; main's frame mounts the pane, with or without a window intent. Deletes the
window's split wait and withdraw, the split appear intents, and the queued-split skip and cancel.
The e2e helper uses the real split. A startup split leaves focus on its source pane.

* fix(terminal): the attach-only wait leaves sleeping, resuming and held panes to their restore path

* fix(terminal): a split pane attaches to the terminal main bound it to; a taken pane id is refused

Also restores the proof that a split closed while it starts gets one answer and leaves no
pane or start status behind.

* Reapply "fix(terminal): a restored pane paints history only from its terminal's host, never the window's copy (layout-owner build only)"

This reverts commit 420e605ad0.

* fix(layout): a trigger between a restored pane's start and its bind write joins that start, not a second one (layout-owner build only)

* fix(terminal): a window split main cannot start still shows its pane, failed, with why

* fix(terminal): keep the switch import the D1b-1 merge dropped from the layout restore

* feat(layout): main's starter shows a restored pane starting before any await, and a failed start with its reason; startPane starts a pane whose bound terminal ended (layout-owner build only)

* feat(terminal): a window's attach-only view of a pane attaches to its terminal or starts nothing, keeping the binding for main's start (layout-owner build only)

* feat(terminal): a restored pane with no live terminal asks main to start it and attaches once main binds it; the window's wake, hibernated wake, restart-on-show and gone-terminal fallbacks route through main (layout-owner build only)

* fix(terminal): check a taken pane id first, keep the start's own error, clear a gone pane's status

Three test stores gain the pane-start field the window's store always has.

* test(terminal): the admission stub answers whether its pane is still written; a closed pane's failed start clears

* test(terminal): with the switch on, the window's restores, wakes and restart replacements ask main to start the pane and attach to the terminal main binds, starting and resuming nothing themselves

* refactor(terminal): the rebound workspaces' bindings show through one call in the bindings module

* fix(terminal): a held pane connects as today so main's refusal holds it; main's start follows output; a capacity death after main's resume keeps the resume (layout-owner build only)

* fix(layout): main passes its start options only for commands that start panes; a windowed open resumes the agent under main (layout-owner build only)

* refactor(terminal): break the pane start module cycle; typed test fixtures

* test(terminal): a pane main wrote and the user closed mid-start drops its failed status

* fix(terminal): every waiter on main's start runs, a failed or refused start settles and is asked again on the next view, a hidden gone pane waits for its view, a twin main hands back stays on today's path, and lost contact never starts a pane (layout-owner build only)

* test(terminal): iterate the store listeners directly

* test(terminal): a cold-restore paint applies no window resume with the switch on

* fix(terminal): a split main starts is listed to phones and session.tabs without a window's report

* test(terminal): name the main pane start test helper as a fixture

* fix(terminal): a reconnect shows its pane starting and why it failed; a lost owner race shows no failure; a split no one asked to see keeps the phones' tab

* fix(terminal): a kept create another owner won shows no failure; the window attaches to the winner

* fix(terminal): a pane main starts at relaunch keeps its full history and starts before the window's graph lists its tab (layout-owner build only)

* feat(terminal): main replaces the empty shell a hibernated agent left and resumes the agent when a view asks; a start main could not attach shows main's own terminal_not_started (layout-owner build only)

* test(terminal): main seeds its copy of a restored pane even when a window declared one, with the switch on

* fix(terminal): a pane main started hidden paints once when its view attaches (switch-on builds only)

The view's attach snapshot, taken after main unmarks the hidden gate, already holds the bytes main
dropped, so the reveal no longer asks a second restore from main's buffer.

* refactor(terminal): main's pane start reads the pane from its own layout, not the client projection (switch-on builds only)

* fix(terminal): a pane restart stops its terminal before writing the pane unbound, so a stop that fails keeps the pane (switch-on builds only)

* test(terminal): a start main could not bind shows terminal_not_started through the window's wait, from one copy site (switch-on builds only)

* fix(terminal): main's pane start resumes an agent recorded under the pane's number, as the window did; stale switch-on tests show main's start and the known banner loss (switch-on builds only)

* fix(terminal): review round: a visible view alone retires main's hidden-start drops, by episode; main reads a split pane's numbered record by its number; the window keeps a shell main kept (switch-on builds only)

* fix(terminal): main's start of a pane a window view is attaching to leaves it visible, so the view paints once (switch-on builds only)

* fix(terminal): a window view that attaches while main starts its pane takes main's start, with no second provider attach (switch-on builds only)

* fix(terminal): review round: a view takes main's start only when it carries a payload and still owns its terminal; attaching views are counted, keep main's pre-spawn mark off, and a failed attach hides only what it kept visible (switch-on builds only)

* test(terminal): checked test doubles in the view-join and numbered-record tests; reattach options fit the file budget

* test(e2e): with the switch on, the mount-authority spec keeps the window's bindings, which only main's frames write

Claude-Session: W5b

* test(e2e): the mount-authority spec fits its line budget; the layout-owner build check is one helper

Claude-Session: W5b

* test(layout): an unbound pane holding a resume record starts and keeps the record, since main's start resumes from it

Claude-Session: W5b

* fix(terminal): a pane main resumed holds a running agent's record, so it reads awake, not sleeping (switch-on builds only)

Claude-Session: W5b

* fix(terminal): in a split where no pane owns a numbered record, main resumes the tab's one conversation in pane 1 only (switch-on builds only)

Claude-Session: W5b

* fix(terminal): main marks only the record a resume started from live, never a sleep captured after it (switch-on builds only)

Claude-Session: W5b

* test(terminal): with the switch on, a windowless resume leaves the pane's record a running agent's

Claude-Session: W5b

* test(terminal): the resumed-record test double typechecks

Claude-Session: W5b

* refactor(terminal): with the switch off, main's pane start reads no resume record for the live mark

Claude-Session: W5b

* refactor(terminal): the merged files fit their line budget: the folder-fallback notice and a hidden pane's wait for its first view are helpers, and the answering-transport lookup moves to its one test caller

Claude-Session: W5b

* refactor(runtime): the window's layout apply fits the runtime's line budget after the main merge

Claude-Session: W5b
2026-10-21 22:13:57 -04:00
Kelvin Amoaba e34b3709b3 feat(browser): new tab page with a workspace card and suggested sites (#31656) 2026-10-21 23:50:12 +00:00
Kelvin Amoaba c5e07bc3af feat(browser): per-site appearance and zoom, from the page menu and Cmd/Ctrl +/-/0 (#31621) 2026-10-21 23:47:12 +00:00
Brennan Benson d085427628 Keep model choices coherent across Claude updates (#30107)
* Use one model catalog per execution scope

* Accept a missing session record in host scope

* Merge duplicate launch-resolution import

* Fix catalog typecheck errors

* Align catalog tests with the one-list design

* Type the integration fixture's send without a cast

* Give the discovery test complete runtime dependencies

* Fix model catalog completion and scoped configured display

* Preserve model catalog authority across released clients

* Fix mobile first-frame catalog fixture narrowing

* Keep startup catalog persistence with one completion owner

* fix: preserve chat selections across CLI model updates

A newer CLI can omit a model that an existing chat still runs. Keep that chat's selected model and effort instead of replacing them from the available list.

Discover one model list per host, account, launch command and folder, refreshing after two minutes. Keep current values and the running model's exact effort choices with its chat. Show only the known effort when Claude supplies no matching menu.

Preserve older paired-client delivery and configured launch arguments. Make Codex use independent discovery and retain the established ACP and Pi paths.

Tracked in STA-10947.

* fix: keep the Pi options read within its file limit after main's growth

Tracked in STA-10947.

* fix: import the option snapshot's shared module once

Tracked in STA-10947.

* fix: keep Grok and Pi model menus and fast controls across restarts

Restore the established ACP and Pi catalog route: newer listed models and qualified startup defaults stay visible, and genuine retained effort menus survive later reads. Keep exact-child Fast and Speed controls. Update the phone option contracts and the remaining stale expectations to the selection rules.

Tracked in STA-10947.

* fix: share each workspace's model list and keep live Grok and Pi menus

New chats read their workspace's own model list through the one shared request for that workspace, so a second chat in the same folder starts on the model and effort the agent actually runs there, and a slow first answer can no longer overwrite a newer list. A running Grok, OpenCode or Pi chat keeps its live model menu when an older shared list arrives later. Update the tests that still expected the replaced behavior.

Tracked in STA-10947.

* fix: keep separate agent and chat model lists for Grok, OpenCode and Pi

A brand-new Claude chat now offers the selected model's effort levels before the first message, as it did before. Grok, OpenCode, omp and Pi again keep the list read from the installed agent apart from the list a running chat reports, and each newer list replaces only its own source. So a chat shows the model the agent is actually running with that model's own effort menu, and an effort change can no longer act on an older model's menu. Saved model lists on WSL are readable again without starting the agent.

Tracked in STA-10947.

* fix: keep desktop catalog storage out of the phone's type graph and show Grok's late model answer

The phone app's type check no longer pulls in desktop-only catalog storage. The model-list code no longer reaches the saved-catalog file through a type import. When a Grok model change times out and Grok later confirms the model, the chat shows the model Grok actually runs.

Tracked in STA-10947.

* Remove unrelated merge formatter and package manager churn

* Clarify independent catalog ownership and refresh contracts

* Declare picker demand callback as an effect dependency

* Complete mobile catalog surface and catalog merge types

* Complete catalog contract fixtures for current host types

* fix: preserve catalog source contracts and account fallback

* test: inject independent Codex discovery transport

* test: remove accidental client fixture assertion

* test: qualify the saved account fallback read

* fix(chat): preserve catalog evidence and current child controls

* Fix catalog CI types and mobile option readiness

* Reconcile session controls after inventory changes

* Fix catalog import and deferred test resolver types

* Keep model capability observations separate from picker views

* Use installed model choices for chat options

* Fix model catalog test fixture contracts

* Restore model option compatibility and stable settlement

* Return a catalog reply in provisional launch fixture

* Compose unreported live model defaults in the host

* Preserve explicit replacement model on recovery send

* fix(chat): use stable scoped catalogs on local desktop

* test(chat): preserve generic catalog runner type

* fix: scope catalogs to configured environment and keep saved reads passive

* fix: satisfy catalog regression and controller CI checks
2026-10-21 16:42:27 -07:00
Jinwoo HongandClaude bd0f326218 feat(sidebar): one lifecycle line per workspace in main, with in-progress hints (switch-gated) (#31553)
* 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

* 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: restore main's final P2 test fixes a merge reverted

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 19:34:14 -04:00
Neil a57e027cb3 fix(orcad): one update decision for SSH and WSL, with connect, Update and Force intents (#31682)
* fix(wsl-host): apply the SSH update rules to a WSL connect

A WSL connect deployed this app's orcad whenever the active build differed,
so a distro another, newer Orca had activated ended in an unconnectable
deferral, and a build the host had rolled back from was re-activated on
every connect. It now runs the same planManagedOrcadAutoUpdate decision SSH
uses and serves the active build when that plan skips.

* fix(wsl-host): serve the skipped-update incumbent only if it is still active

* fix(orcad): one update decision for SSH and WSL, applied again under the fence

The connect's update plan moves to its own module, and the fenced admission
every first deploy and WSL connect uses now applies it, so a transient
readiness failure or a race cannot reactivate a rolled-back build.

* refactor(wsl-host): adopt the serving build through the SSH first-deploy adoption

* fix(wsl-host): do not retry a candidate rejected earlier this launch

A rejected candidate is restored without recording rolledBackFrom, so WSL
retried it on every connect. SSH's launch-scoped failure memory moves to a
shared helper keyed per host, and WSL feeds it to the shared update decision.
A null adoption now re-reads the record before the deploy, as SSH does.

* fix(wsl-host): keep Force offered when a connect skips this app's build

The WSL connect's update admission moves to its own module, which returns a
forceable hint when it serves the incumbent over a rolled-back or failed build.

* fix(orcad): connect, Update and Force are the three update intents on SSH and WSL

Only a connect applies the skips; an explicit Update retries a skipped or failed
build (clearing the failure memory) behind the terminal census; only Force passes
the census. WSL's Update button now sends the update intent instead of a plain
connect. A connect that records a rejection serves the restored incumbent at once.

* fix(orcad): an explicit Update keeps the newer-host skip on SSH and WSL

Update lifts only a host's own skips (rolled back, failed before); Force lifts
all. SSH's explicit update now applies the same fenced admission, so stable
cannot replace a host a newer Orca activated without Force. A rejection retries
adoption only once the incumbent is back and no journal awaits recovery.

* fix(wsl-host): keep Update and Force offered on a deferred cold connect

A connect the host deferred with nothing serving now publishes its deferral, so
a host stopped after a rollback can still be retried from the UI. SSH's explicit
Update forgets a remembered failure only once it lands, and a restore that could
not be read keeps the rejection as reported.

* fix(wsl-host): offer only Force over a host a newer Orca runs, and keep failure memory until an Update lands

A host-newer refusal gets its own deferral code so the WSL row hides Update,
which can never pass it. An explicit Update no longer clears the launch failure
memory up front; only a landed deploy does, as on SSH.

* refactor(wsl-host): merge the intent type into the existing shared imports
2026-10-21 16:26:35 -07:00
Neil d22fb0d5b4 refactor(ipc): group Jira handlers with concrete owner imports (#31680) 2026-10-21 15:59:31 -07:00
Neil 15b2cd5828 refactor(ipc): group Linear handlers with direct owner imports (#31673)
* refactor(ipc): group Linear handlers with direct owner imports

* chore: keep module organization progress local
2026-10-21 15:41:13 -07:00
Neil fba3af0b48 docs(ssh): describe the orcad connect path without the removed relay (#31651)
Comments and one log line still said a host falls back to the relay, keeps
the pinned-relay ladder, or shares code with the relay's spawn and install
paths. No relay client exists; an unserved host fails its connect with a
reason, and the legacy bridge only keeps old relay terminals alive.
2026-10-21 13:55:25 -07:00
Neil 553a704403 refactor(execution-host): one resolver for the SSH target a repo row may dial (#31623)
getStoredRepoSshConnectionId and seven inline
getSshTargetIdForExecutionHost(getRepoExecutionHostId(repo)) spellings answered the same
question. Name it once in shared (getRepoDialableSshTargetId), build
getRepoRoutingConnectionId on it, and drop the getRepoHostedReviewExecutionHostId re-export
alias in favour of a direct import of getStoredRepoExecutionHostId.
2026-10-21 13:29:42 -07:00
Neil f9aeb34e00 refactor(ssh): import SSH and orcad names from the modules that define them (#31642)
Drops seven pass-through re-exports in the SSH, managed-server, orcad and
runtime-environment modules; each importer now names the defining module.
2026-10-21 13:28:15 -07:00
Neil 67886127dc refactor(ssh): delete SSH and orcad helpers nothing calls (#31629)
Removes the relay ladder's answered-failure predicate, the unused test-probe
joins, two dead renderer broadcast helpers, the bound-port reader the tunnel
no longer uses, the WSL terminal-verdict mapper the supervisor never called,
and an unused type.
2026-10-21 13:00:00 -07:00
Jinwoo Hong 1db95e308a fix(terminal): stamp ORCA_WORKSPACE_ID on every terminal main creates, not only folder ones (#31608)
The window stamps it (equal to ORCA_WORKTREE_ID) for every workspace kind and agent
wrappers forward it; terminals started from the phone, the CLI or a server's own create
in a git worktree lacked it.
2026-10-21 15:53:36 -04:00
Brennan Benson 8174208436 fix(terminal): every start in a deleted folder opens at the workspace root and says so (#30747)
* fix(terminal): start every terminal in the workspace root when its saved folder is gone, and say so

A terminal whose start folder was deleted opened at the workspace root only
when the window started it; the CLI, phone restore, orchestration and other
host starts failed with the raw "Working directory ... does not exist" error,
because the renderer had to opt in with a cwdFallback flag.

The execution host now makes that decision for every start that may create a
process (anything but a known live pane), with no caller flag. The fallback is
reported only when a process was proven started at the requested folder, so a
reattach or a crash restore in its recovered folder never claims "workspace
root", and only then does the saved start folder heal. A recovered folder that
was itself deleted yields to the request's resolved folder.

The notice reaches each caller through surfaces it already has: the window's
terminal line (now also written when a host-created tab attaches, and on a
restored reattach), the agent.launch warning (also for callers that show the
tab themselves), and a toast when a phone tap restores the tab.

* fix: recover terminal startup folders without healing unreadable paths

* fix: preserve saved start folder when revealing fallback terminals

* Reuse saved-tab lookup in cwd persistence test

* Import mobile tab activation result from its contract

* Check startup fallback response without a test cast

* Update expectation to catch up with accepted saved-folder metadata

* Preserve inconclusive WSL directory evidence when saving startup folders

* fix: project restored terminal ids for handle consumers

* test: return void from launch parity cleanup

* test: retain saved folder in shared spawn expectation
2026-10-21 10:21:36 -07:00
Jinwoo Hong 0eb2403ef8 Main closes, renames, sleeps and starts new tabs' terminals itself, with or without a window (dark, layout-owner build only) (#31571)
* fix(terminal): a CLI or phone close through main keeps a pinned tab, as the window-era close did

* feat(terminal): main applies phone closes, renames, pane titles, sleeps and agent-launch tabs itself, with or without a window (layout-owner build)

* fix(terminal): a tab close through main also ends the tab's dormant SSH relay session; agent-launch tabs main writes keep the window's focus rule, prompt and outcome (layout-owner build)

* feat(terminal): main starts a new tab's first terminal under the window's ids, and the pane attaches to it (layout-owner build)

* test(terminal): tests that counted the window's create calls or publications see main's start of a new tab

* fix(terminal): an account-switch restart binds only into a pane main's layout holds, with no window tree (layout-owner build, L197)

* test(terminal): the new-tab start tests hold no type assertions; the start's ledger row is L252

* fix(terminal): a new tab's pane attaches to any terminal main binds it to, and a failed start keeps the tab's startup

* test(terminal): a Claude account-switch restart's tests draw the pane main holds

* fix(terminal): a launch pane main takes back still tells the window why, which drops its hold and prompt; a rename through main answers the name it stored (layout-owner build)

* fix(terminal): a new tab another owner's terminal won attaches to it, and a failed start's startup never runs twice

* fix(terminal): main's pane close reads its stop result as a type only, so no runtime module loads before its base class

* fix(terminal): a phone's close through main drops the closed rows from what phones list at once, not at the window's next publish (layout-owner build)

* chore(terminal): mark the phone-close row drop interim (ledger L260)

* test(worktree-create): a new local tab's startup counts as run when main starts it (layout-owner build)

* test(worktree-create): record main's starts without a type assertion

* fix(terminal): a tab closed before main declines its start gets no startup back (layout-owner build)

* fix(terminal): the window's new tab starts in main when its own window asks over IPC, which labels itself a client (layout-owner build)

* fix(terminal): a refused close of a pinned tab leaves its running agent launch alone (layout-owner build)
2026-10-21 13:12:19 -04:00
Jinwoo Hong 92bbb380a6 Sidebar: land the switch-on fixes from the flip branch on main, switch still off (#31466)
* 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.
2026-10-21 12:24:27 -04:00
Kelvin Amoaba 6970cad0d3 feat(browser): ask before sites use camera, mic or location (#31158) 2026-10-21 14:45:15 +00:00
NeilandClaude 5dd5294294 perf(orcad): keep the server bundle ASCII so V8 stores it at half the size (#31495)
* perf(orcad): keep the server bundle ASCII so V8 stores it one byte per character

129 non-ASCII characters in regex literals (and three in a String.raw plugin
template) made V8 hold the whole ~11 MB orcad-server.js source as a two-byte
string. Write them as \uXXXX escapes and fail the build if any return.

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

* fix(orcad): keep license comments ASCII and name the module the guard trips on

esbuild gathers legal comments at the end of the bundle; escape that comment so
a dependency's license text cannot fail the ASCII guard, while licenses still
ship with the code. The guard now reports the offset and, from an unminified
rebuild, the module the character came from. A dark-switch build is covered.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 04:06:49 -07:00
Neil 9577c531c7 fix(ssh): a managed host's 'no desktop is sharing its browser' error names the browser routing setting too (#31444)
* fix(ssh): the host's 'no desktop is sharing its browser' error names the browser routing setting too

The desktop withholds the browser bridge from a managed SSH host whose pages browse from the
desktop's own network, but the host's CLI was told only to turn on the per-host CLI control
switch, even when it already was on (#31421).

* fix(ssh): name the per-host routing opt-out too, and guard the labels against UI copy drift
2026-10-21 00:28:46 -07:00
Neil c7f722bbdf fix(pairing): offer only addresses the runtime listener answers (#31447)
The runtime WebSocket listener widens to 0.0.0.0, which never accepts
IPv6, yet the Connection address picker and the default pairing address
offered global IPv6 interfaces, minting links nothing answers. Filter the
interface list by the family of the host the listener binds when serving
the network.

Reported-by: @fongyuan-2011
2026-10-21 00:11:21 -07:00