Commit Graph
1878 Commits
Author SHA1 Message Date
Neil 55f353f4cc fix(ssh): keep old relay channels off the host's own SSH connection (#39435)
* fix(ssh): keep old relay channels off the host's own SSH connection

Each old relay still running a shell held one exec session on the target's
connection. At sshd's MaxSessions (default 10) every later exec failed, so the
host stuck at Connecting with 'Could not detect the remote platform: (SSH)
Channel open failure: open failed'.

* test: say why the session-limit repro needs a longer timeout

* test: note why the relay channel fakes are cast

* test: move the many-relays repro into the existing legacy relay bridge suite
2026-11-07 02:40:00 -08:00
Neil ee04233cf2 feat(pairing): show which devices still sign in with their original pairing code (#38949)
* feat(pairing): show which devices still sign in with their original pairing code

Settings lists paired phones and access links that signed in with a pairing
code but never exchanged it (apps from before single-use pairing) with
"Uses an older pairing method. Update ...". Display only; rows from older
builds are never flagged.

* fix(pairing): no update hint for links used by plain-http browsers or still pairing

A link that served a session-only browser key is marked, so the hint stays
off after a host restart drops those keys. Codes still inside the pairing
window are not flagged either: an updated client exchanges within moments.
2026-11-07 02:17:33 -08:00
Jinjing 76182c1cf5 Use Cmd+K for search on new Mac profiles (#38884)
* Use Cmd+K for search on new Mac profiles

Preserve existing search and terminal clear shortcuts during migration
on desktop and web.

* Preserve legacy Mac shortcuts during web profile migration

* Preserve keybinding resets across profiles and platforms

* Preserve legacy shortcuts and markdown link bindings

* Separate profile shortcut defaults from shared overrides

* Check shortcut conflicts when restoring defaults

* Fix tab shortcuts targeting floating workspace panels
2026-11-07 01:58:17 -08:00
Neil e1379b34f3 feat(pairing): Add server and orca environment add exchange the link for their own token (#38948)
* feat(pairing): Add server and orca environment add exchange the link for their own token

After verifying the host, Add server (and repair) swap the access link's
token for one generated on this computer when the host advertises
pairing.ticket-exchange.v1, and save that instead. orca environment add does
the same with a short best-effort probe. Any failure saves the link as today;
the host keeps accepting it until the new token is used.

* test(pairing): Add server and CLI leave links unchanged for a released host

* fix(pairing): Add server and orca environment add sign in once after exchanging, and the CLI rejects a refused code

After exchanging a link, sign in once with the new token so the host
retires the link right away instead of at the first later use; a host
downgraded in between would not know the new token.

orca environment add no longer saves a pairing code the host refuses
(for example one another device already used); it asks for a new code.
2026-11-07 01:48:16 -08:00
Neil ddd3a071c3 feat(pairing): a browser's saved device key retires the pairing link it came from (#38947)
* feat(pairing): a browser's saved device key retires the pairing link it came from

When a browser signs in for the first time with a saved device key forked
from a ticket row, the row's link token is replaced by a value nobody holds
(the row stays as the fork's anchor; orchestration fingerprint pinned).
Session-only keys re-register from the link on every page load, so they never
retire it. Links from older builds are untouched.

* fix(pairing): a browser key retires a link only during pairing and only if nobody claimed it

A saved browser key now retires its link only when it was registered within
the pairing window of the link's first sign-in, and only when no other
client already proposed its own token for it (that first claim wins, so the
desktop that proposed first is never locked out).

* test(pairing): the web key migration wire test expects a fresh link to be single use

* fix(web): say a refused pairing link may already have been used

A browser opening a single-use link after another device used it is
refused as unauthorized; the message now names that case and asks for a
new pairing link from Orca.
2026-11-07 00:42:11 -08:00
Jinwoo Hong 228263d566 feat(automations): launch desktop runs from main, not the renderer window (#39247)
Desktop automation runs now launch from the main process through the same launcher orca serve uses. The renderer dispatch path is deleted.
2026-11-07 03:04:56 -05:00
Neil b0a4b33908 feat(pairing): let clients exchange a pairing code for their own token (#38937)
* feat(pairing): let clients exchange a pairing code for their own token

New offers are marked as tickets. A client signed in with the pairing token
can call pairing.exchangeTicket with a token it generated; the host stores it
durably and keeps accepting the pairing token until the client first signs in
with the new one. That sign-in retires the pairing token and cuts sockets
still using it. Advertised as pairing.ticket-exchange.v1; clients that never
call it keep working exactly as before.

* fix(pairing): never retire a code other clients may already rely on

Exchange is offered only within 10 minutes of a ticket's first sign-in;
after that the code may be in use by several older clients and stays a
plain token. The first client to propose keeps its claim: a different
proposal is refused (that client keeps the code) instead of displacing it,
so two clients pairing at once can't lock out the first. Adds cross-version
tests against the pinned release: downgrade keeps exchanged and unexchanged
phones working, rows from an older host are never single-use, and the older
host doesn't advertise the exchange.
2026-11-06 23:57:05 -08:00
Jinjing 2ed0633a4a Fit file and browser tabs to their content (#39328)
* Fit file and browser tabs to their content

Keep terminal tabs at their preferred width and reserve stable editing
space while renaming tabs.

* Remove obsolete tab rename width hook
2026-11-06 22:58:41 -08:00
Neil 9f054bf264 feat(ai-vault): reveal an Antigravity session's artifacts folder (#39295)
* feat(ai-vault): reveal an Antigravity session's artifacts folder

* fix(ai-vault): detect agy artifacts from the discovery walk and open inside the folder

* test(e2e): pass onRevealArtifacts in the OMP child history fixture
2026-11-06 22:17:51 -08:00
Neil 97f2de9913 refactor(renderer): organize runtime clients and feature state owners (#39292)
* refactor(renderer): organize runtime clients and feature state owners

* fix(refactor): preserve incoming consumers and validation routing

* fix(refactor): consolidate defining-owner type imports
2026-11-06 21:32:59 -08:00
Neil 944ed9f2ca refactor(terminal): organize remaining pane features by owner (#39270)
* refactor: organize remaining terminal pane features by owner

* refactor(terminal): consolidate replay guard type imports

* refactor(terminal): retarget notification mocks and generated consumer import

* refactor(terminal): repair benchmark owner lookup and stale mock export
2026-11-06 19:45:07 -08:00
Brennan Benson f308486115 Show Source Control for folder workspaces (#38831)
* Separate editor tab placement from content ownership

* Show scoped Source Control sections for attached worktrees

* Preserve active diff refresh and validate section catalogs

* Complete folder section test worktree metadata

* Use contextual types for scoped Source Control actions

* Preserve optional scoped action parameters

* Preserve editor ownership through restore, mirroring and workspace removal

* Retire Source Control drafts only after confirmed owner removal

* Limit section work to visible expanded repositories

* Keep editor follow-up actions and bulk closes in their invoking views

* Track the consolidated editor order writer in its owning module

* Use complete typed fixtures for repair contracts

* Preserve live editor placement during layout readback

* Pass projected editor placement directly to serialization

* Read attached worktree lineage from shared graph module

* Retain inferred owner checks and scope placement retirement

* Preserve selection in untouched workspaces during purge

* Exercise editor placements in existing launch and lifecycle fixtures

* Preserve shared buffer prompts and editor strip order

* Pause inactive section context subscriptions

* Keep section recovery and file actions in the folder workspace

* Describe attached Source Control in folder workspace CLI help

* Attribute Git metadata signals once per dispatch

* Watch mounted source control sections outside the warm budget

* Resolve section watches only for served filesystem roots

* Restore restart-stable editor identity across SSH opens

* Apply section terminal routing to explicit Chat choices

* Include cross-store descendants in folder workspace panels

* Keep cross-host recovery on its existing workspace route

* Start cross-host section agents in their workspace without navigation

* Update memoized Source Control labels on language changes

* Remove unused terminal close-to-right implementation

* Suspend inactive Source Control body observers

* Retain base ref query while section observation pauses

* Cover retained base ref search across section visibility

* Resolve note menu ownership from the retained snapshot

* Preserve section agent working directories and background placement

* Keep Source Control sections active while their overlays are open

* Read current settings when Source Control commands execute

* Adapt editor and browser test stores to view subscriptions

* Preserve bound store hooks for ordinary app views

* Trust agent starts outside the placement workspace

* Trust the section worktree through transient launch ownership

* Extract editor follow-up file actions from the panel

* Fail section launches when trust capability lookup fails

Preserve explicit unsupported-host fallback, propagate lookup failures to the existing launch error path, and let the existing transport retry refresh rejected capability probes.

* Follow the moved pane launch test in web configs

* Preserve section file ownership during refresh and close

* Share tab order removal across editor close paths

* Verify companion editor close through the real store

* Close all workspace split copies for legacy mobile file requests

* Keep unmatched mobile close requests within their workspace

* Reuse the agent menu render snapshot

* Keep attached folder roots scoped to their resolved host

* Apply repository trust decisions to the launch trust owner
2026-11-06 18:25:57 -08:00
Neil 7823b122f1 refactor(renderer): organize terminal pane lifecycle and layout owners (#39242) 2026-11-06 17:52:55 -08:00
Neil 090945007b Ask once per repo before pre-trusting agent folders (#38946)
* Ask once per repo before pre-trusting agent folders

* Route the trust prompt's repo lookup by the launch host; use dialog primitives as designed

* Bound the first-launch trust hold and honour the answer for the launch

* Move agent folder trust settings into their own settings group
2026-11-06 17:02:46 -08:00
Brennan Benson ad4bb83fa1 Open the chat model picker without walking every worktree (#38660)
* fix(native-chat): list Claude and Codex models per account, not per folder

Opening the chat model picker rebuilt every worktree row to work out which
folder the read was for, because Claude and Codex model lists were keyed by
folder. Only the default model/effort depends on the project, so lists are now
keyed by account, WSL and the resolved CLI invocation and listed from the
account folder; the CLI is still resolved where the chat would launch. The
selected workspace is derived directly from its selector, and its own project
settings decide whether the account's default model and effort are shown.
The worktree projection and its cache are removed.

* test: merge duplicate node:os import

* fix(native-chat): list from Orca's probe folder, keep cwd-relative CLIs in their folder, one project-settings pass

- List Claude/Codex models from Orca's empty probe folder so a home folder's settings never read as another account's project settings.
- A command line naming files relative to the chat's folder lists there and is keyed to it.
- Read project settings once per binding for both the model and effort answers; per-model effort-only Claude settings keep the account model.
- A running chat's catalog withholds the account's configured choice where its project may pick its own.
- Bound the picker's workspace resolution so a stalled floating folder cannot hold it.

* fix(native-chat): catch quoted ./ arguments, list prewarm from Orca's probe folder, fake-timer the shared-listing test

* perf(native-chat): parse each project settings file once for both model and effort

* test: catalog e2e expectations list from Orca's probe folder; phone saturation keys per folder

* fix(native-chat): share a listing while any reader wants it; list custom command lines in the chat's folder; resolve a floating folder within the read's own wait

- A model listing shared by several folders keeps running while any reader still waits on it, queued or running, and stops (never starts) once the last one gives up.
- A Claude or Codex command line with user arguments or a relative command lists in the chat's folder; Claude reads only user settings there so project settings never narrow the account's list.
- A waiting read resolves a floating folder within its own deadline; a read that doesn't wait returns at once and starts the listing when the folder resolves.

* fix(native-chat): every reader of a shared model listing owns it until its own deadline; floating reads list their folder within their own budget

- Readers of the same request share one lookup that lives until the last reader's deadline, so later readers neither repeat CLI/settings setup nor lose the listing when an earlier one ends or is cancelled.
- A shared listing's requests carry no single reader's deadline: the provider timeout bounds them and the last reader leaving stops them.
- A floating picker read that doesn't wait starts its folder's listing under its own deadline and retirement, and says the listing is in progress so the picker follows with a waiting read.

* fix(native-chat): a shared model listing survives the chat that started it; unreadable workspaces list as the account

- Each reader of a shared lookup fences its own request, so one chat closing never ends another chat's listing; the lookup's budget is the latest deadline among readers still waiting, and its listeners are released when it ends.
- A picker for a workspace this host can't inspect (remote, WSL, ambiguous, stalled) lists as the account does from Orca's probe folder, never from wherever Orca itself runs.

* refactor(native-chat): readers of one model request share an ownerless setup and each own only their claim and the listing

- Same-request readers share one setup (folder, account, CLI scope and the folder's own default settings) that belongs to no reader: its budget is fixed when it starts, it ends with the service or the agent's retirement, and it is reused while it runs and while the listing it found runs.
- Each reader keeps its own claim, deadline and cancellation; a binding holds scope facts only and never cancels another reader's claim or a shared listing, so one chat closing never ends another chat's listing.
- A floating picker read that doesn't wait no longer asks to list the unresolved folder.

* fix(native-chat): shared catalog setups end on their budget or a workspace change, readers settle on cancel, and defaults and account seeding happen once

- A shared setup that runs out of its budget, or whose workspace or agent is retired, answers nothing at once and leaves the cache, so a reader with time left resolves afresh (a moved folder never reuses the old path).
- Cancelling a reader, or stopping the service, ends its wait at once.
- A folder's own default settings apply to its binding whenever they arrive; the account list is seeded once per shared setup, not per reader.
- A reader shares a setup only with readers whose own chat agrees on whether it may list.

* fix(native-chat): a settled catalog setup serves its whole listing, and a folder's default settings stay bounded and reach every reader

- A setup that has answered stays reusable while the listing it found runs, past its first reader's deadline, until it is ended or its agent retired, so later readers don't redo CLI and project-settings work.
- The setup's budget holds until the folder's default settings have answered too; settings that outlive it are read again while a reader still has time, and apply to the request's current binding whichever reader asked.

* refactor(native-chat): the catalog service owns each model refresh within one fixed budget; pickers only wait

A refresh (account, folder and CLI resolution, the folder's default settings,
admission and the listing) now belongs to the catalog service with one 30s
budget fixed before setup. Readers join it and wait only until their own
deadline or cancellation; none extends, shortens or ends it. Expiry withdraws
queued listings, stops the process and drops late answers. Defaults apply only
to the refresh's own binding, so a moved folder's late settings never describe
the new folder. A waiting read that used its whole budget is final.

Replaces per-reader claims, shared setups and reader-counted listing demand.

* fix(native-chat): retiring an agent or a chat's folder ends its catalog refresh at once, and a shared setup never rechecks the chat that started it

- Retiring an agent ends a refresh still stalled in setup, so a waiting picker
  answers at once instead of after the refresh's budget.
- A listing that runs in a chat's own folder stops, and its answer is dropped,
  when that folder's command context retires; listings shared across folders
  stay independent.
- Scope resolution uses only the passivity its readers had when they asked,
  so another chat's record going away mid-setup no longer turns it saved-only.
- A reader that stops waiting unsubscribes from the listing at once.

* fix(native-chat): one workspace's retirement no longer stops a catalog listing another workspace shares

A listing is keyed by the folder it lists in and the CLI invocation, so moving
one workspace never makes it describe the wrong folder; stopping it there
cancelled a listing another workspace on the same folder still needed. Agent
retirement and shutdown still stop listings at once.

* test(native-chat): a folder change keeps another workspace's shared catalog listing, and never answers the new folder with the old one's

* test(native-chat): a folder agent's listing survives another workspace on its folder moving

* test(native-chat): type the shared-setup harness's held stages without casts

* fix(native-chat): Claude and Codex pickers show the account's default in every folder

The picker no longer reads a repo's own model or effort settings for Claude and
Codex: they show the account's list and default everywhere, and the CLI still
applies the repo's settings at launch. OpenCode, OMP and Pi keep their project
checks. The model/effort split and the peek withholding go back to main's shapes.

* fix(native-chat): a Codex listing in the chat's folder never loads that folder's project config

A Codex command line that may name files in the chat's folder still lists there,
but now marks that folder and its parents untrusted for the listing, so a repo's
own model catalog can't replace the account's. The exported project-settings
check also answers no for Claude and Codex.

* fix(native-chat): Codex lists models only from Orca's probe folder

A Codex listing no longer starts in the chat's folder for custom or relative
command lines, so a repo's own config can never change the picker's list, as
other Codex hosts do. Chats still launch with the user's command line and folder.
Drops the untrusted-folder override.

* fix(native-chat): Codex listings never read project config above Orca's folder

With no project-root markers, Codex reads project config only from the listing's
own folder, so a trusted repo that contains Orca's profile can't supply the
account's model list.

* docs(native-chat): say what Codex listing isolation covers, and what managed config can still restore
2026-11-06 16:59:49 -08:00
Brennan Benson 5d1c2a8910 Honor agent defaults when setting up later (#38028)
Set up later saves the applicable visible Chat/Terminal and agent choices, preserves unvisited saved defaults and Blank, then opens the default agent through ordinary workspace activation in the captured workspace and host. First use and Help replay share the behavior, and failed saves remain retryable.

Independent reviews accepted the main-parent update. All 27 focused tests and final-head CI passed, including twelve unit shards, static/typecheck, changed E2E and packages. Real Claude/Codex Chat and Terminal, saved Blank and graceful-restart QA carries across the main merge. The final local changed-check prerequisite timed out in the resource queue before checks ran; this limitation is documented in the PR.
2026-11-06 16:53:48 -08:00
Brennan Benson 46575a257f Open fresh desktop profiles in a ~ folder workspace (#37898)
Fresh desktop profiles start in an ordinary folder workspace at the OS home directory, with the initial repo group named ~. Onboarding Continue saves the selected default agent and launches it in that workspace through the normal activation path. Existing profiles and user-renamed groups remain unchanged.

Independent reviews and prior real Claude/Codex QA are complete. Refreshed-head CI is green, including all unit shards, changed E2E, static/typecheck, packages, persistence and WSL. All 54 focused regression tests passed; three bounded local check timeouts are documented in the PR.
2026-11-06 16:29:36 -08:00
Kelvin Amoaba efc27ee8ee fix(terminal): finish a paste in its terminal when dictation or overlays move focus mid-paste (#39112)
* fix(terminal): finish a paste when focus moves to a non-input control mid-paste

External dictation tools and overlays can leave focus on a control outside the pane while the clipboard read is in flight, and the paste was thrown away as stale. Only cancel when another paste target (terminal, input, frame) took focus.

* fix(terminal): count Monaco and rich editors as paste targets

* test(e2e): a paste survives focus moving to a non-input control mid-read

* refactor(terminal): one focus rule for terminal and popout paste

* test(e2e): scope each focus-move script so later cases actually move focus
2026-11-07 00:18:12 +00:00
Brennan Benson d84abfb4f5 Offer terminal sign-in recovery in native agent chats (#39012)
* Offer terminal sign-in from native chats and retain refused worker tasks

* Handle sign-in terminal failures and complete failed-start cleanup callers

* Read retry task identity from its dispatch context

* Assert retained transcript identity through the bounded worker read

* Remove obsolete private structured retry teardown assertion

* Use real signed-out Pi and OMP error frames in regression coverage

* Route chat sign-in through explicit host terminal creation

* Keep paired agent launch owner explicit in the tightened terminal contract

* Keep focus baseline pruning limited to the removed reads

* Keep terminal login recovery available for unresolved model notices

* Keep the Grok diagnostic assertion scoped to its refused delivery

* Limit chat sign-in subscriptions to eligible failure rows

* Pass the execution host in terminal creation fixtures

* Scan Pi OAuth failures linearly and verify shared sign-in bounds

* Assert failure metadata and diagnostic routing without translated copy

* Bound diagnostic matcher steps at the Pi failure boundary

* Type the diagnostic matcher receiver explicitly

* Check sign-in button elements with a DOM type guard

* Recognize Pi credential failures and keep one recovery action

* Keep Pi sign-in diagnostics behind failure details

* Verify recovery action changes while refusal wording stays stable

* Use the recorded refusal sentence in the recovery fixture

* Type the recovery fixture as a submission rejection

* Make chat sign-in actions large primary controls

* Reuse primary action styles without duplicate notice subscriptions

* Keep translated primary chat actions within narrow notices
2026-11-06 16:06:14 -08:00
NeilandClaude a943631bd2 test(e2e): wait for the editor to see each pointer selection before Markdown Find takes focus (#39204)
ProseMirror reads a click's selection from the selectionchange event, which a
hidden Xvfb window delivers after Playwright's next step. The spec focused Find
right after clicking, so the editor still held an old selection when focus left,
and the Shift-click extended from the document start. Wait for that event after
the caret click and the range Shift-click; route Find sources to its specs.

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-06 16:00:54 -08:00
Neil 9cb56ebc4c test(e2e): wait for the shell-ready deadline after a startup exec (#39203)
* test(e2e): wait for the shell-ready deadline after a startup exec

Since #30978 the terminal host no longer probes for a prompt when a profile
exec drops Orca's ready marker; it submits the startup command once at the
15 s shell-ready deadline. The oracle allowed only 8 s, so the headless serve
case failed unless the exec barrier happened to run long. Wait until that
deadline (measured from terminal creation) plus the recovery budget, and
route the spec from the shell-ready barrier and shell startup sources.

* ci(e2e): route the startup-exec oracle helper to its spec
2026-11-06 23:31:07 +00:00
Neil cf47e79147 test(e2e): isolate same-path editor models across two real hosts (#39208)
The spec forged an SSH owner for a local file and relied on the read
falling back to local transport. Since #31617 a tab reads only from its
captured owner, so the forged tab correctly shows 'Couldn't verify which
host owns this file'. Use a paired client that opens the same checkout
locally and on its runtime host instead, and route editor model identity
sources to the spec.
2026-11-06 23:25:30 +00:00
Neil 95a4d9b9af test(e2e): give each CSV preview its own link so the link opens a new tab (#39196)
A link whose page is already open now reuses that tab (#32907), so the paged
preview's click of the same URL never added the second tab the spec counted.
Also route CSV viewer sources to the CSV specs.
2026-11-06 23:24:35 +00:00
Neil 051bc5bc15 refactor(terminal): organize PTY connection lifecycle owners (#39188)
* refactor(terminal): organize PTY connection lifecycle owners

* refactor(terminal): consolidate imports from concrete owners

* test(e2e): assert durable pending automation acknowledgement
2026-11-06 15:23:27 -08:00
NeilandClaude d5d92649ac plugins: show the publisher when two plugins or themes share a name (#39205)
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-06 15:15:26 -08:00
Neil c8ea52d37b test(e2e): drive the other-agents permission menu in agent-auto-permissions (#39202)
permission dropdown, and fresh profiles keep OpenCode on its own settings, so
the agents without Auto read Mixed after Full access -> Approve for me. Assert
that, track OpenCode in the stored-permission checks, and route the spec on
permission settings sources.
2026-11-06 23:08:29 +00:00
Neil f1ab15045f test(e2e): keep the descendant-kill stand-in's marker path out of argv (#39201)
Claude launches now get --plugin-dir prepended (subagent navigation, #33322),
so the stand-in read '--plugin-dir' as its marker path and the spec never saw
the detached child. Route the spec on descendant-kill and Claude launch-flag
sources.
2026-11-06 22:58:52 +00:00
NeilandClaude 4430743ab7 test(e2e): restart the WSL move fence spec from a phase startup recovery keeps (#39200)
Since #34683 a move journal promotes the WSL hosts gate to serve-only, so startup
recovery now runs and undoes a move interrupted before blobs-transferred. The
spec restarted at source-fenced and expected the fence to survive; assert the
undo there, fence from blobs-transferred, and expect the committed refusal to
name the host (#34880). Route fence and recovery sources to the spec.

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-06 22:55:03 +00:00
Neil 7b39d39aa4 test(e2e): measure terminal link tooltip geometry against the pane bottom padding (#39195)
Terminal padding now insets the bottom edge too (#36789), so the terminal sits
paddingY above the pane bottom. Route pane geometry sources to the spec.
2026-11-06 14:53:43 -08:00
Neil a2ad899954 test(e2e): keep the client-hosted browser tour off the convergence spec's suggestions (#39197)
The one-time 'This page renders on your desktop' tour opens beside the address
bar of the first client-hosted page and intercepts clicks on the address-bar
suggestion. Seed it as seen for this spec via a new paired-client launch
option, and route address-bar conversion sources to the spec.
2026-11-06 14:46:25 -08:00
Neil 97530ccaff test(e2e): pair runtime-host recovery spec with two distinct servers (#39198)
Since #31080 a client keeps one saved entry per server, so pairing the same
host a second time under another name is refused. The steady 'Direct host' is
now a different server than the interrupted one. Tooltip checks name the host
so a closing tooltip from the previous card cannot match. Route the spec from
its pairing-store and runtime-status sources.
2026-11-06 14:45:00 -08:00
Neil 880d7ca1f0 test(e2e): align GitHub project board spec with click-wake and localized error toasts (#39193)
Board drops send wakeWslDistro (#36230) and network failures toast localized
copy (#34621). Route GitHub Projects sources to the board spec so PRs run it.
2026-11-06 14:43:04 -08:00
Neil a1650f78d0 test(e2e): route confirmed paired preview links through the in-app link preference (#39190)
Since #33622 a confirmed HTML preview link honors openLinksInApp (default off,
so it opens the system browser) and no longer calls
openBrowserProfileTabInActiveWorkspace, so the spec's store spy never fired.
Opt the client into in-app links and observe the opened page URL directly.
Route doc-preview sources to the spec.
2026-11-06 14:35:35 -08:00
Neil c85d633837 test: fail unit tests that run a real agent CLI from PATH (#38961)
* test: stop unit tests from running the developer's real agent CLIs

A live relay test reached the host's real `claude --version` through the
inherited PATH. On a machine whose claude wrapper never exits, each run left
an orphaned loop behind (14 were found on one host, running for days).

- Add a unit-test setup guard that shadows agent CLI names on PATH with
  stand-ins that fail the test which ran them.
- Give the live relay test its own claude/codex stubs.
- Kill the whole process tree when the WSL guest's version probe times out.

* test: keep structured-session tests off the real codex CLI

These hosts get a scripted transport, but the at-rest `/` command read
spawns the resolved codex command directly, so on a machine with codex
installed each run started a real `codex app-server`. Point them at a
missing binary, as on CI.

* test: isolate agent discovery in session fixtures
2026-11-06 12:56:01 -08:00
Jinwoo Hong 16f2d38acb fix(automations): Run now returns the saved pending row; launcher parity (#38217)
* fix(automations): Run now returns the saved pending row; quiet, titled, retained run terminals

Run now answers with the durable pending row instead of waiting behind
the automation's lane; one detached handler records a launch failure.
Existing-workspace launches no longer surface their owner, a new
workspace's startup tab carries the run title, and finished-run cleanup
keeps a terminal a user opened after its process started.

* fix(automations): keep launched runs and user-opened run terminals intact

A failed flush after a launch no longer rewrites a dispatched run as a launch failure.
A user tab open marks the pane activation shows, read after any spawn it starts.

* fix(automations): own launch-failure recording in the service; quiet pending pane notice on mobile
2026-11-06 15:46:47 -05:00
Neil 10b8666c45 refactor(terminal): organize rendering and parked-view owners (#39146) 2026-11-06 12:11:27 -08:00
Neil 2462e9cac4 refactor(renderer): organize terminal PTY transport owners (#39134)
* refactor(renderer): organize terminal PTY transport owners

* test(terminal): mock concrete PTY shutdown owner
2026-11-06 11:36:05 -08:00
Neil 4941215ad1 refactor(terminal): organize input, clipboard, links and completion owners (#39113)
* refactor(terminal): group input, clipboard, links and completion owners

* test(terminal): mock concrete file action owners

* refactor(terminal): preserve file routing import admission

* test(acp): import host fixtures from defining owners

* ci: follow concrete journal item lifecycle owners
2026-11-06 11:12:24 -08:00
Neil 3228095e97 refactor(renderer): organize launch, workspace, browser and search owners (#38845)
* refactor(renderer): group launch, workspace, and browser owners

* fix(renderer): restore workspace name Enter focus to agent picker
2026-11-06 10:37:45 -08:00
Kelvin Amoaba 582044269b perf(mobile): share one clientEvents stream per host connection (#39011)
* perf(mobile): share one clientEvents stream per host connection

* perf(mobile): keep the shared clientEvents stream across a same-tick rejoin

* fix(mobile): let a later subscriber retry after the shared clientEvents open throws

* fix(mobile): guard the shared clientEvents cleanup after a throwing open

* test(e2e): give the phone list's socket client the shared clientEvents shape
2026-11-06 18:16:22 +00:00
Neil 0314da7ed8 refactor(main): group RPC and orchestration modules by owner (#38813) 2026-11-06 08:21:33 -08:00
Neil c5383afb6c Open a granted host file the way a workspace file opens (#38742)
* fix(files): open a granted host file the way a workspace file opens

A plain click on a host file outside every workspace opened it in the
editor through the grant's whole-file text read, so a video, a large
image or any text past 512 KiB failed with "too large to open from its
host". Granted files now go through the same reads as workspace files:
media streams to its viewer by range, images and PDFs page past one
reply, and large text pages into the editor. A host file is addressed
either by workspace path or by its grant, and the host gains
files.statTerminalArtifact to pair with files.readTerminalArtifactChunk.
The host names a large binary as binary before refusing its size, as
files.read does, and a streaming player renews a lapsed grant the way
the editor's reads do. Hosts without these methods answer
method_not_found, which the paged reads already turn into an
update-the-host message.

Refs #35968

# Conflicts:
#	src/main/media/media-preview-protocol.test.ts

* fix(files): page a granted binary with the grant that served it

A content read renews a lapsed grant without telling the tab, so a bytes
editor paged the file with the dead grant and failed on every reload. The
read now reports the grant that served it; the bytes editor uses that grant
and the tab keeps it, as a save that renews one already does.

Refs #35968

* fix(files): renew a granted preview on every host call and keep unsavable grants read-only

Review: renewal ran only before a media response returned, so a grant that
lapsed under a streamed chunk or a pdf.js range read over IPC failed instead.
Every host call for a remote preview now goes through one helper that renews a
lapsed grant once. A grant saves only text within one write, so a granted
binary or text past 512 KB now opens read-only instead of failing to save.

Refs #35968

* fix(editor): show an unsavable granted copy read-only in every view

Review: read-only reached only the edit surface, so a large granted notebook
or markdown file still opened its editable rich view. The editor panel now
treats the copy as a read-only tab, so rich views fall back to the raw source
view as they do for other read-only tabs. A renewed read-only grant also reads
as read-only and stays off the tab.

Refs #35968

* fix(files): renew a granted bytes read whole and never splice versions mid-stream

Review: a bytes editor opened after its grant expired kept failing, since its
paged read never renewed. It now renews and restarts the whole read. A stream
or PDF range that renews mid-read now continues only if the renewed grant sees
the same file version, so a rewritten file can't splice into one response.

Refs #35968

# Conflicts:
#	src/main/media/media-preview-protocol.test.ts

* fix(files): keep each preview response on its own grant and pin a bytes read's pairing

Review: a stream crossed to a grant another request had renewed without
checking the file version, and a bytes read that renewed during a re-pair
could read from the new host. Each response now keeps the grant it started
on and moves to a renewed one only after checking the version it serves, and
a bytes read pins its pairing before the first call.

Refs #35968

* fix(files): bind a preview's stat to the grant that saw it

Review: a stat cached from the old grant could start a response on a grant
another request had just renewed onto a rewritten file. The cache now keeps
each stat with the address that produced it, a response starts on that
address, and a renewal checks the version by stating the renewed grant
itself.

Refs #35968

* fix(files): keep a pinned read's pairing on its paged address

Review: the paged-read address dropped a caller's pinned pairing, so a re-pair
between a grant renewal and its retry could send the retry to the new host.
The address now carries the pinned revision.

Refs #35968

* test(e2e): give the granted video spec's timeout its reason

Refs #35968

* test(media): keep the granted preview renewal tests in their own file

Main trimmed media-preview-protocol.test.ts to local previews, so the tests
for renewing a granted preview's lapsed grant (burst, streamed chunk, rewritten
file, PDF range over IPC) now live in media-preview-protocol-granted.test.ts.

Refs #35968
2026-11-06 06:36:41 -08:00
Neil 1c950baf33 refactor(main): group session lifecycle and journal modules by owner (#38638)
* refactor: group structured session modules by owner

* test: retire status history work-count oracle suite

* refactor(main): organize journal storage and projection owners

* Consolidate restart recovery fixture imports

* Consolidate concrete session option model imports
2026-11-06 06:00:08 -08:00
3704d01615 fix(terminal): a host with a window keeps a pane a paired client moved to a new tab (#38840)
* fix(terminal): a host with a window keeps a pane a client moved to a new tab

Dragging a split pane onto the tab strip in a paired worktree whose host runs
the desktop app with a window flickered and snapped back. The client draws the
new tab and calls session.tabs.movePaneToNewTab, but the host answered
not_held whenever it had a window, because the window owns the layout and only
headless hosts committed the move. The client reverted, and even without the
revert the host window's next snapshot would have rebuilt the old tab.

Main now asks its window to make the move and waits for the answer, the way
other client requests reach a window-owned host. The window moves the pane
with its own drag-out path under the tab id the client already drew, at the
client's drop position, mounting a parked source tab first. A pane the window
cannot reach is refused, so the client puts it back; a host without the
window bridge still answers not_held. Older clients and hosts are unaffected.

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

* fix(web): rely on the optional pane-move bridge instead of no-op stubs

The web client never receives host pane-move requests, and the bridge
already skips registration when these members are absent; dropping the
stubs keeps web-ui-api.ts under the line limit after rebasing on main.

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

* test(e2e): a window host keeps a pane a paired client moved to a new tab

The window-host case asserted the old refusal, where the client drew the new
tab and put the pane back. It now drags a pane out on a paired client and
checks the pane stays in the tab the client drew: the host window holds the
leaf alone under that tab id, no snapshot pulls it back, and the source keeps
one pane. It fails on main, where the tab count falls back after the drop.

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

* fix(terminal): refuse a pane move the host window cannot answer

When a paired client asks a host with a window to move a pane to a new
tab, the host relays the request to that window. If the window is gone,
closes, or does not reply within 10 seconds, the relay rejects. The
host returned that rejection as an RPC error instead of a move result.

The host now answers { status: 'refused', reason: 'pane_unavailable' }
in that case. The client already puts the pane back on a refusal, and
this is the reply the relay timeout was sized for.

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

* fix(terminal): fence a window's pane move once the client heard it timed out

The relay told the client "refused" after 10s but left the window's move
running, so a late commit moved the pane on the host after the client had
put it back. Main now fences the commit: a move the client was told timed
out commits nothing, and a commit answers the client at once, before the
deadline can turn it into a refusal.

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

* fix(terminal): keep the pane-move fence Electron-free and let a claimed commit answer

The leaf-move IPC is shared with the plain-Node runtime, so the fence moves to its own
Electron-free module. A window that goes away mid-commit no longer refuses a move its commit
landed, and a second move cannot replace a fence a timed-out move still holds.

Fixes #37082

* chore(terminal): follow moved shared modules after rebasing the pane-move relay

Refs #37082

* fix(terminal): hold a client's pane move's source tab mounted until the move settles

The timed split-mount lease could expire while the window was still moving the
pane, so cold parking could unmount the source tab after main had already told
the client the move landed. The move now holds the tab mounted for its whole
duration and releases it when it settles.

Fixes #37082

* fix(terminal): don't toast the host window for a pane move another client asked for

Fixes #37082

* fix(terminal): relay a client's pane move only to a window that owns the layout

Where main owns the layout (the dark ORCA_LAYOUT_OWNER=main path), the window's
move goes back through main, which names its own tab, so the client's tab id
could not be kept. Main answers not_held there, as before this change.

Fixes #37082

* fix(terminal): name the renderer a relayed pane move belongs to

Fixes #37082

---------

Co-authored-by: Seunghwan <hyunsh.cycle@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 05:30:17 -08:00
Brennan BensonandJurassic Knights b039d4fe5b Keep published active tabs aligned with current selection (#38844)
Paired clients now publish the chat actually selected on the desktop as the active tab; saved layouts, CLI-created chats, closes and restarts keep it consistent. Carries community PR #34526.

Co-authored-by: Jurassic Knights <jurassicknights@gmail.com>
2026-11-06 04:00:10 -08:00
Neilandggbdpq a2661f93ff fix(trust): remove only the Codex and agy workspace trust entries Orca created when a worktree is removed (#38969)
* fix(codex): remove Orca-created pre-trust entries when a worktree is removed

Records which [projects."<path>"] tables Orca's preflight trust created in a
managed Codex config (with the exact bytes written), and on worktree removal
deletes only those, inside the existing trust-config mutation queue. Removal
paths await the purge so a removal is never reported before the entry is gone.

Ported from #24803 (commits 88d5469c, c1ffc5a4, 11b0bd74, f85606b3) onto
current main: conflicts resolved, stray re-export wrappers dropped, and tests
trimmed to AGENTS.md rules (ordering/timing, private-state, Cartesian and
lower-layer duplicate cases removed).

Co-authored-by: Neil <neil@stably.ai>

* fix(antigravity): drop Orca-added trustedWorkspaces entries on worktree removal

Generalizes the Codex pre-trust ownership ledger into a small factory
(agent-trust-ownership-ledger.ts) and uses it for agy: when Orca appends a
worktree path to ~/.gemini/antigravity-cli/settings.json trustedWorkspaces, it
records the exact entry, and worktree removal removes only that recorded entry.
Entries that already existed before Orca's grant are never recorded or removed.

* fix(trust): keep folder-workspace trust on session removal; isolate trust test userData

Only checkout-deleting removal paths drop Orca-created agent trust now.
Folder-workspace sessions and forgotten orphans leave the directory on
disk, so removing one must not strip the grant siblings still rely on.
Also point the execution-host trust test at a temp userData so the new
ownership ledger never writes to the real Orca config, and make the e2e
removeWorktreeMetadataAndHistory stub return its Promise.

---------

Co-authored-by: ggbdpq <ggbdpq@gmail.com>
2026-11-06 03:32:02 -08:00
Neil fb13022e0d fix(editors): launch Open In editors by id from settings (#37934)
* fix(editors): launch Open In editors by id from settings

* test(editors): drop settings casts by narrowing the shell store type

* fix(editors): import shell-open types from their moved path

* test(editors): type the shell test settings instead of casting
2026-11-06 02:23:35 -08:00
Brennan Benson 0b93cef445 One chat's status change wakes only that chat (#38883)
* perf(native-chat): one chat's status change wakes only that chat

The renderer status feed copied every retained summary and called every
listener on each one-session update, and the status bridge walked every
open tab. Adopt the common keyed-entity pattern: update the session in
place, wake only readers registered for that session, and give the bridge
a session-to-tabs index. Option state now reads only the runtime
permission answer, so a reply preview no longer re-renders the chat.

* fix(native-chat): keep the phone's permission projection and prune stale retry members

Restore projectRuntimePermission for the phone app, ignore a malformed
conversation-name list as the names fold does, drop superseded bridge
members from the retry set, key resume-run ids by the run's start, and
update the continuation test mock.

* perf(native-chat): retry and resume-run checks look only at the touched host and chats

Keep the bridge's retry set per host so another host's update never scans
it, and check only the resume-run entries an update touched.

* test: give the launch create-message feed fake the per-chat subscription

* test: drop call-count assertions from the bridge contact-loss test

Keep the behavior it guards: no throw, revocation applied, later listeners
still notified, and the reconnect snapshot projects.
2026-11-06 02:06:50 -08:00
Brennan Benson f9e346cf8e Avoid JSON round-trips for desktop chat updates (#38936)
* perf(runtime): pass local stream responses directly over IPC

* test(runtime): explain the partial dispatcher runtime double

* test(runtime): observe object streams in the desktop account fixture
2026-11-06 02:05:35 -08:00
Neil e648eb9f04 fix(plugins): say that full-access plugins can also control Orca (#37933)
* fix(plugins): say that full-access plugins can also control Orca

Worker plugins can use Orca's local runtime API, so the consent text now
mentions terminals and agents alongside files, network and programs.

* fix(plugins): keep the glossary term in the Japanese full-access warning

* test(e2e): expect the updated plugin full-access text

* test(e2e): expect the updated full-access text in the plugin demo spec
2026-11-06 01:11:55 -08:00