Commit Graph
1959 Commits
Author SHA1 Message Date
Brennan BensonandOrca Worker a54fd3830e Antigravity install: one clear message in the chat, with the message box staying in place (#30001)
* feat(native-chat): a chat whose host has no program to run shows one clear install message, with the message box staying in place, disabled

A new chat replaces its Start-a-chat copy with an install message (what it is, its size, one Install button, then steps, progress and Cancel). A chat with messages gets a slim strip above the composer instead. Settings' row is unchanged.

* fix(native-chat): the install message drops its Settings hint until that Settings row exists

* fix(native-chat): satisfy the not-found lint on the install card's phase lookup

* fix(native-chat): the install message follows the design system: a still full bar once the download is done, and a plain ghost Cancel

* fix(native-chat): the install card's size caption uses the download-size string main already has

Main's Antigravity work added the same "downloadSize" key to the install strings, so each locale
held it twice with slightly different text. The card now reads main's one string, so the hero's
caption under its button ends in a full stop like the Settings row's.

* refactor(native-chat): the install row keeps only its Settings layout

A chat now shows its own install card, so nothing renders the row's chat layout any more: Settings
> Chat > Providers and the Antigravity accounts section are its only users. The row and its view
lose the surface choice, the chat-only heading string goes from every locale, and the view always
says and offers what Settings did.

* fix(native-chat): the install message points to Settings › Chat › Providers again, now that main has that row

Only chats on this computer show it: that row installs here, not on an SSH or paired host.

* fix(native-chat): a disabled chat box keeps its placeholder and dims, so it says why it can't take a message

The editor drew its placeholder only while editable, so an install-blocked or held box looked
empty and enabled. The plain text box already dims and keeps its placeholder.

* fix(native-chat): keep setup reachable and honor composer input availability

* fix(native-chat): update picker availability after commit

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
2026-10-18 00:28:19 -07:00
Jinwoo Hong 559ece08d3 feat(sidebar): the host that owns a workspace stamps its Recent and Smart keys (dark) (#30235)
* feat(sidebar): the owning host stamps sort keys on its workspace records (dark)

* fix(sidebar): sort stamps title phase switch is exhaustive

* fix(sidebar): sort stamps reconcile seeded tiers, respect host and WSL move fence, follow PTY swaps

* fix(sidebar): one clock read per sort stamp event

* fix(sidebar): a first idle title is not Done; the WSL fence spares SSH records
2026-10-18 00:16:28 -07:00
Neil e6eaabb587 test(files): the native-ignore watcher test waits on delivered events, not a fixed sleep (#30236)
It flaked on loaded CI shards when a single write never reached the watcher. Files are now rewritten until seen, readiness is proven before the storm, and a sentinel written after the storm replaces the 300 ms debounce sleep. Disabling the ignores still fails it.
2026-10-18 00:10:44 -07:00
Neil f47337d852 refactor(worktree): one worktree path equality; the ipc copy folded WSL ext4 tails (#30227)
src/main/ipc/worktree-path-comparison.ts kept its own areWorktreePathsEqual and
dedupeWorktreesByPath. Its Windows branch lowercased a WSL UNC path's ext4 tail, so two
case-twin WSL checkouts merged into one row in removal safety, folder-upgrade dedupe and
the SSH listing fallback. Every caller now uses git/worktree-path-comparison, which gains
the macOS /private/tmp fold the ipc copy had. worktreePathComparisonKey keeps its exact
bytes (retirement namespace keys persist it) in worktree-path-comparison-key.ts, and the
worktree-logic re-export goes.
2026-10-18 00:02:29 -07:00
Neil 993fd20223 test(preflight): freeze the clock in the explicit-binary timeout test (#30221)
The budget is deadline - Date.now(), so a millisecond tick between the two reads made it 4999.
2026-10-17 23:45:27 -07:00
Neil 9810a5cc92 refactor(worktree): one comparison-only worktreeIdentityKey replaces three key wrappers (#30217)
worktreeIdComparisonKey (nullable '::' key), runtimeWorktreeIdentityKey ('\0' key) and
runtimeWorktreeLookupKey (JSON tuple) all folded the same path spelling. They become one total
key in shared/worktree/id.ts; a malformed id keys as itself. Also fixes id.test.ts literals that
were missing a colon, which made the WSL/UNC parity assertions compare null to null.
2026-10-17 23:43:55 -07:00
Neil d4aa9dcadc revert: restore pinned npx skills installer (#30207)
Reverts #30185 so the separate installer project can proceed. The restored shared command already pins skills@1.7.2 for CLI, desktop updates, and setup commands.
2026-10-17 23:24:02 -07:00
Neil ffb818bf61 Ship the locked skills installer instead of executing npx (#30185)
* security: ship a locked skills installer instead of running npx

* chore: remove retired skills process import exception

* test: include the locked installer in packaged layout fixtures

* test: reuse the real installer builder for package fixtures
2026-10-17 22:51:14 -07:00
Neil b5fa888a93 fix(worktrees): stop CLI-created worktrees flashing into a filtered sidebar (#30194)
* fix(worktrees): keep a CLI-created worktree out of listings until its metadata is saved

A watcher-driven listing during `git worktree add` surfaced the new checkout as a bare
external row. The host's default-terminal request then made that stale row active, so it
slipped past Hide sleeping and Hide CLI-created until the next refresh hid it (~1s flash).

* fix(worktrees): hold canonical checkout paths during creation
2026-10-17 22:38:23 -07:00
Jinwoo Hong b8264e860b Main drops the layout of workspaces the catalog no longer validates (dark, layout-owner build only) (#30177)
* feat(layout): main drops the layout of workspaces the catalog no longer validates (dark, layout-owner build only)

* rename the paired-host check so the switch-off bundle keeps its names

* a repo id two hosts register skips the listing purge
2026-10-17 22:19:35 -07:00
Kelvin Amoaba 5c4c1edc64 feat(terminal): tell users once that the diff panel in a Claude pane is Claude's own (#29818) 2026-10-18 01:49:10 +00:00
Jinwoo Hong ce2d60834c test(pty): the launch race join test no longer waits on real disk I/O (#30132) 2026-10-17 16:54:24 -07:00
Neil ba9c7eadbf Add Reveal in Finder to the file header menu (#30129)
* Add file location actions to the editor header

* Wait for the terminal spawn join before releasing race-test gates
2026-10-17 16:52:27 -07:00
Jinwoo Hong 45f7429600 Save-divergence detector: skip empty workspaces, see dropped tab-bar entries and kept pane trees (dark, layout-owner build only) (#30125)
* Save-divergence detector: skip empty workspaces, see dropped tab-bar entries and kept pane trees (dark, layout-owner build only)

- A workspace key that names nothing (or only places a stored closed-tab record) is no longer
  reported as "workspace added/removed" or "terminal row owner changed".
- A save that drops a terminal tab's tab-bar entry while keeping its row is reported, read from
  the stored session before the Loader rebuilds the entry.
- A pane tree main keeps over the window's (windowSaveForMain) is reported, so a window-side
  pane repair shows up.

* Detector: keep reporting empty-row flips, cover every overridden pane tree and one-sided closed tabs (dark, layout-owner build only)

* Detector: a save with no pane tree for a tab main keeps one for is reported too (dark, layout-owner build only)

* Detector: a closed tab record moved to another worktree in one save is reported (dark, layout-owner build only)
2026-10-17 16:49:24 -07:00
Neil 27cfee6f7e fix(ssh): a Disconnect stays disconnected, and Settings and the status bar agree (#30130)
A user's Disconnect of an SSH host is now recorded for the session, and background
dials (a managed server's tunnel and status checks, census, host-resume recovery,
pane and automation restores) refuse it until an explicit Connect. Disconnecting a
managed host from Settings also stops its server's status checks, and the status
bar's Disconnect of a managed server also disconnects the SSH host it runs on, so
both surfaces read the same verdict.

Fixes #30086
Fixes #30085
2026-10-17 16:25:42 -07:00
Brennan Benson 6287ff6f62 One spawn step writes a terminal's pane identity for both ways Orca opens terminals (#29884)
* refactor(pty): one spawn step stamps a terminal's pane identity for both spawn lanes

The window spawn controller and the host runtime's caller each wrote
ORCA_PANE_KEY/ORCA_TAB_ID/ORCA_WORKTREE_ID and jcode's runtime dir, in
different layers, so per-pane env behavior drifted (the jcode daemon
pre-warm exists only on the window lane). stampPtySpawnPaneEnv now writes
them in both controllers from the spawn's own tab/leaf/worktree ids;
buildTerminalWorkspaceEnv no longer stamps them. No behavior change: a
TEMPORARY prewarmsJcodeOnDaemonHost input keeps host daemon spawns from
pre-warming until its own PR.

* test(runtime): read a fake spawn's pane env without type assertions

* test(pty): host serializer-settlement spawns name their pane by tab and leaf, as the runtime does

* fix(pty): preserve caller runtime directory after managed preparation fails
2026-10-17 13:40:44 -07:00
Jinwoo Hong cd29f5f3c2 feat(sidebar): main keeps a registry of workspace creations in progress, checked against the window in dev and test (#30021)
* feat(sidebar): main keeps a registry of workspace creations in progress, checked against the window in dev and test

* fix(sidebar): open the runtime creation entry after the create's own repo resolve

* refactor(sidebar): one creation handle opened after the create's repo lookup; move create startup resolution to its own module

* feat(sidebar): put the creation registry behind the ORCA_SIDEBAR_INPUTS dark build switch

* test(sidebar): cover the creation registry with the switch off and the gated creation id
2026-10-17 12:43:12 -07:00
Jinwoo Hong 03cefcb84c feat(sidebar): main keeps one live set of paired-server rows, checked against the window in dev and test (#30027)
* feat(sidebar): main keeps one live set of paired-server rows, checked against the window in dev and test

* fix(sidebar): settle review findings; main also publishes paired-server host facts
2026-10-17 01:13:34 -07:00
NeilandClaude 98d8257b02 fix(ssh): a password SSH host waits for you at launch instead of prompting (#30025)
* fix(ssh): a host that needs a password waits for the user at launch instead of prompting

Restores the persisted 'last sign-in needed a typed credential' flag that
the relay removal (#27214) stopped writing, and at launch marks those hosts
as awaiting sign-in so background reconnects (startup restore, managed-server
status checks and tunnels) refuse without dialing instead of opening the
password dialog. The user's own Connect lifts it and prompts. The terminal
toast shows the refusal as an SSH state, not a bug to report.

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

* test(ssh): give the raw-connected fixture the cache query; annotate the harness-shaped registration

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

* refactor(terminal): keep the sign-in branch out of the toast component

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-17 01:10:48 -07:00
Neil 8f2810ab23 fix(ssh): link a folder workspace the server kept when a re-created SSH host moves again (#27285) (#30017)
* fix(ssh): link a folder workspace the server kept from an earlier move instead of conflicting (#27285)

* fix(ssh): resolve a server folder's host before linking it, and read folder lease owners

* fix(ssh): name a linked folder workspace in the connect's left-behind warning
2026-10-17 00:50:27 -07:00
Brennan Benson 32a53d3ec6 feat(native-chat): image messages wait in the queue like text (#28655)
* feat(native-chat): image messages wait in the queue like text

A message with images now queues behind the running turn and the cards
ahead of it, instead of skipping the queue. Cards show an image icon and
count, an image-only card names its image, and editing a card's text keeps
its images. The host publishes no card holding an image to a client that
has not advertised agent-session.queued-image-cards.v1, since released
clients edit by copying a card's text and deleting the card.

* test(native-chat): an image follow-up queues like text

* fix(native-chat): project queued images before phone frame limits

* fix(native-chat): preserve image sends from older clients

* Clarify direct text recovery at send admission

* fix(native-chat): expose queued image names to keyboard users
2026-10-17 00:07:29 -07:00
NeilandClaude ed147d5d68 fix(ssh): re-check a macOS host's ended launch-session warning so another desktop's restart can clear it (#29915)
* fix(ssh): re-check a macOS host's ended launch-session warning so another desktop's restart can clear it

The ended verdict was cached for the whole SSH session, so when another desktop restarted the server under a live session, this desktop kept the warning. It now expires like every other verdict: a live re-probe clears the note, and an unanswered one keeps the proven verdict.

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

* fix(ssh): only a live probe clears a proven launch-session end, and a failed recheck republishes it

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

* fix(ssh): a failed launch-session recheck restores the warning only for the same live connection

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-16 19:18:09 -07:00
Brennan Benson dd3bbf680e Catch up desktop chats from the newest page (#29125)
* fix(native-chat): retire acknowledged send echoes after catch-up

* test: follow phone lint rules in reconnect regression

* test: format reconnect message expectation

* Keep current chat requests independent of loaded history

* Read current chat requests in bounded cursor pieces

* Bound desktop catch-up after independent request support

* Fix current request subscription static checks

* Match generated request schema import ordering

* fix(native-chat): correct current request type boundaries

* Accept readonly client capability fixtures

* Exercise current request reads in wire compatibility inventory

* Align current request fixtures with provider commit and RPC surface

* test(native-chat): include current request browser capability

* Keep the mobile chat session hook within its line budget

* Format mobile current request readers

* fix(native-chat): reopen once for a current-request version whose read keeps failing

A deterministic read failure reopened the subscription, whose first frame re-read the same version and reset the backoff, so the pane resubscribed every 750 ms forever.

* test(native-chat): type the current-request snapshot fixture

* test(native-chat): wait for the hydrated open before driving the subscription
2026-10-16 17:46:54 -07:00
Jinwoo Hong 9aa537286d Report window saves that still change main's tab layout (dark, layout-owner build only) (#29886)
* feat(layout): report window saves that still change main's layout (dark)

In a layout-owner build, each window session save (session:set, session:patch, the shutdown
checkpoint) is projected to main's published layout before and after it is written. Any workspace
whose layout the save changed is logged, and appended to ORCA_LAYOUT_SAVE_DIVERGENCE_LOG when set,
so evidence runs can show which tab changes still reach main only through the save.

* feat(layout): name the fields a diverging save changed

* fix(layout): the save check diffs main's whole layout model and never fails the save

Review: a failed log write could reject a save that already landed; and the published layout omits
editor views, pane records (sleeping agents, incarnations, titles), closed-tab tombstones and the
workspace records, all of which a later save trim would drop.

* fix(layout): the save check covers record-only workspaces and row owners, and counts rebinding last

* fix(layout): the save check counts first binds as rebinds and keeps the count past the cut
2026-10-16 17:06:52 -07:00
Neil dd70294f0c fix(ssh): turn a host's orca CLI control on by default and stop resetting saved choices (#29856)
* fix(ssh): allow a host's orca CLI to control Orca by default, and stop resetting saved choices

An absent allowRemoteCliControl now means on; only an explicit false turns the
desktop browser bridge and relay-era orchestration commands off. Removes the
one-time reset of saved true values, the consent stamp writes and the reset
notice, which would have silently turned off hosts upgraded from stable.

* fix(ssh): keep the CLI control choice when adding a host from the sidebar

* fix(ssh): read an older client's omitted CLI control switch as off over RPC

* fix(ssh): check the managed fence before routing settings in browser bridge candidates
2026-10-16 16:08:37 -07:00
Brennan Benson 8c1ade9e44 Keep pending chat decisions available outside loaded history (#29121)
* fix(native-chat): retire acknowledged send echoes after catch-up

* test: follow phone lint rules in reconnect regression

* test: format reconnect message expectation

* Keep current chat requests independent of loaded history

* Read current chat requests in bounded cursor pieces

* Fix current request subscription static checks

* Match generated request schema import ordering

* fix(native-chat): correct current request type boundaries

* Exercise current request reads in wire compatibility inventory

* Align current request fixtures with provider commit and RPC surface

* test(native-chat): include current request browser capability

* Keep the mobile chat session hook within its line budget

* Format mobile current request readers

* fix(native-chat): reopen once for a current-request version whose read keeps failing

A deterministic read failure reopened the subscription, whose first frame re-read the same version and reset the backoff, so the pane resubscribed every 750 ms forever.

* test(native-chat): type the current-request snapshot fixture

* test(native-chat): wait for the hydrated open before driving the subscription
2026-10-16 16:01:58 -07:00
Brennan Benson fa923c67e3 fix(projects): a manual folder-to-Git change proves the folder is the Git root first (#29282)
* fix(projects): refuse a folder-to-Git type change that would hide folder workspaces (STA-10638)

A folder project's extra workspaces exist only as metadata rows that the folder listing shows. Changing the project to Git switches it to `git worktree list`, so those workspaces drop out of the next refresh and their saved tabs are purged as if they had been deleted. Only the automatic upgrade checked for this; `orca project setup-update --kind git`, repo updates and clone-into-folder did not.

The check now lives in the one repo write every type change goes through, so any caller gets the same refusal and nothing is written. The automatic upgrade and both clone paths use the same check and keep the project as a folder project.

* test(repos): give the repo handler store mock the metadata read the clone path now uses

* fix(projects): a manual folder-to-Git change proves the folder is the Git root first (STA-10638)

Only the automatic upgrade checked that a folder project's path is the top of a Git repository and recorded Git's spelling of that root. A manual change (orca project setup-update --kind git, repo updates, clone into a folder project) flipped the type without either, so a project inside another repo became a broken Git project, and a project whose path Git spells differently lost its main workspace's id and tabs on the next refresh. All of them now run the same proof and write the proven root with the type change. SSH projects keep the unverified change because their Git runs on a host this process can't probe.

* Revalidate folder-to-Git conversion targets after Git proof

* Explain when a project changes during its Git check

* Fix clone conversion for replaced folder project

* test(runtime): create real Git root for clone upgrade fixture

* test: normalize runtime clone root stamp expectation

* test: check clone registration identity without unknown access

* chore: restore main's pnpm-lock.yaml that the main merge reverted
2026-10-16 15:53:12 -07:00
Brennan Benson 69d877e272 fix(pty): window daemon spawns wait for a WSL guest's Pi/OMP relay, like host spawns (#29780)
A Pi or OMP agent started from the window inside WSL, with the terminal
daemon on, could start before the distro's hook relay was up. It then
reported no working/idle status for that session. Host starts and
local-provider starts already waited (#21721); the window's daemon path
was the one left out.

The shared host-env step now always runs the wait on the daemon spawns
it builds, so the lane input that skipped it for window starts is gone.
The wait is a no-op for anything but an explicit Pi/OMP launch in WSL.
2026-10-16 15:50:04 -07:00
Jinwoo HongandClaude afcca77a5e Window pane trees drawn from main's layout frames (dark, build switch off by default) (#29788)
* Window pane trees drawn from main's layout frames (dark, build switch off by default)

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

* Review fixes: paired-server saves keep their trees, last-pane guards count pending closes, draw main's answer when no frame is coming, redraw main's tree after a zoom

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

* Delta review: a closed stream's frozen cache never redraws pane trees; the frame reconciler never closes a tab's last pane

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

* Second delta review: draw the activation tab only when no frame showed it; a stream not yet open counts as coming; a redraw re-queues only its tab's workspace

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

* Independent review: a late record of a split main asked for restores it only if main took it back; a closed stream never redraws pane trees

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

* Delta review: deny a late record only for a split main wrote and did not take back itself; pane_closed only where the tab is; a reply before the stream opens waits for its first frame or end

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

* Re-review: replies wait only once the window opened its stream; a record that lands while main takes its split back waits for the outcome

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

* A record waits only while main is taking its split back

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

* refactor(layout): main keeps the pane of a split it asked for

Drops the timed withdraw and the window's late record of a main-asked split: main writes the pane and keeps it, a refused write fails the split, and a tab's first mount leaves queued main-asked splits to their request so the startup command still runs.

* refactor(layout): drop the start-without-pane option no caller uses

* refactor(layout): drop an always-false check in the queued main-split filter

* test(layout): main-asked splits into an unmounted tab, with the stream down, and with no start

* test(layout): type-safe withdraw stub

* fix(layout): equalize draws itself when no frame is coming

* refactor(layout): name the frame-tree pane moves for their role

* refactor(layout): frames' pane trees reach the store through the frame store patch

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-16 15:24:12 -07:00
NeilandClaude e0e2001701 refactor(legacy-relay): one ask-wait clamp and no needless exports (#29835)
optionalAskTimeout computed exactly what cappedWait does (an undefined timeout stays undefined;
anything else clamps to 0..ORCHESTRATION_ASK_MAX_TIMEOUT_MS), so the ask call uses cappedWait.
Three functions used only inside their own file lose their export, and the per-host switch's
doc names the orchestration commands it has gated since #29571.

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-16 14:11:36 -07:00
Jinjing 005f06bbc7 Run automated workspace setup in a dedicated Setup tab (#29819)
* Run automated workspace setup in a dedicated tab

* Preserve native-chat setup route coverage after placement retirement

* Preserve Setup tab design and independent review evidence

* Classify activation test fixtures consistently for routing checks

* Sync runtime English catalog after removing setup preferences

* Update listener savings model after retiring setup action
2026-10-16 14:05:50 -07:00
Neil 1e39482f9d fix(wsl-cli): keep the WSL CLI status check from timing out on a cold or slow-profile distro (#29814)
* fix(wsl-cli): keep the WSL CLI status check from timing out on a cold or slow-profile distro (#29497)

* fix(wsl-cli): run install/remove without the login PATH; a PATH-check timeout reports PATH unknown
2026-10-16 12:45:01 -07:00
Brennan Benson 6a760682f7 fix(projects): refuse a folder-to-Git type change that would hide folder workspaces (#29257)
* fix(projects): refuse a folder-to-Git type change that would hide folder workspaces (STA-10638)

A folder project's extra workspaces exist only as metadata rows that the folder listing shows. Changing the project to Git switches it to `git worktree list`, so those workspaces drop out of the next refresh and their saved tabs are purged as if they had been deleted. Only the automatic upgrade checked for this; `orca project setup-update --kind git`, repo updates and clone-into-folder did not.

The check now lives in the one repo write every type change goes through, so any caller gets the same refusal and nothing is written. The automatic upgrade and both clone paths use the same check and keep the project as a folder project.

* test(repos): give the repo handler store mock the metadata read the clone path now uses
2026-10-16 12:41:56 -07:00
Brennan Benson 2fa848395b refactor(pty): one host-env step for both terminal spawn lanes (#29297)
* test(pty): pin where the two spawn lanes build a daemon spawn's host env differently

Characterization on main's code before the host-env step merges: which failed env builds sweep
per-PTY state (minted ids only, both lanes), the empty-id split, the host-only WSL Pi/OMP guest
readiness wait, and that a host create operation still waits on a managed Codex login.

* refactor(pty): one host-env step for both terminal spawn lanes

The window (pty:spawn) and host (runtime controller) lanes each carried a copy of Codex resume,
Codex home selection, the managed-auth wait, backfill recovery and the daemon host-env build.
Both now call resolvePtySpawnHostEnv. Lane differences are explicit inputs: two TEMPORARY ones
(the host-only WSL Pi/OMP guest readiness wait; the host skipping host env for an empty id) and
three that mean the same in both lanes. The resume step's launchEnv was never read and is gone.

* test(pty): pin that both lanes hand Codex resume prep the request's CODEX_HOME

orca serve (#29209) skips resume prep for a launch whose env names a client-sent CODEX_HOME.

* test(pty): type the new lane-pin requests instead of asserting them

* test: pin selected Codex home on terminal restart
2026-10-16 10:32:03 -07:00
Brennan Benson 85254f9ecd refactor(runtime): plan paired agent sessions with the host planner (#29041)
* test(launch): pin what a paired agent session spawns today

Characterization on main's code before createAgentSession moves onto the
host planner: plain launch, short/long/multi-line prompts on macOS, a
stdin-prompt agent starting clean, Windows PowerShell and cmd quoting, and
the identity-required refusal when no launch can be built.

* refactor(runtime): plan paired agent sessions with the host planner

terminal.createAgentSession built its own launch command beside the planner
every other host launch uses, and the two had drifted. It now hands the
request to createTerminal as a startupAgent, so one planner builds it.

The planner gains a draft delivery input, and one TEMPORARY input
(startupPromptCarry: 'force-line') keeps what createAgentSession did: the
prompt always rides the typed line, and an agent that reads its prompt
after start launches clean. The later change that delivers uncarried
prompts after start removes it. A launch that can't be built still refuses
with agent_session_identity_required.

* test(accounts): pin that the selected account wins over Settings agent env

A paired agent session now layers the host-selected account env the way
every other host launch does.

* fix(runtime): report prompt carry truthfully on the planner's direct path

Review round 1: a stdin-prompt agent's text never rides its launch line, a
draft comment that overstated the carry rule, the error class's name, and
formatting the cherry-picked commit skipped.

* docs(runtime): scope the account-order and draft comments accurately

Review round 2.

* test(launch): drop paired-session parity rows that pin nothing new

The no-prompt and short-prompt rows plan the same with or without
force-line, and the Windows cmd row repeats the OpenCode-model Windows
row's createAgentSession runtime and cmd quoting. The long-prompt,
aider, PowerShell, refusal and account-env pins keep the coverage.

* docs(runtime): label the draft's carry-rule exemption temporary

Skipping the typed-line carry rule for drafts is createAgentSession
parity, not design: a draft on the line has the same hazards as a
submitted prompt. The one prompt/draft delivery policy removes it with
force-line.

* fix(runtime): keep main's error name for an unbuildable agent launch

Overriding the name made every other planner caller's stringified
error read 'AgentLaunchUnbuildableError: ...' instead of main's
'Error: ...', which renderer code that strips an 'Error:' prefix
would show raw. createAgentSession matches by instanceof, so the
override bought nothing.
2026-10-16 10:29:23 -07:00
Neil 469ae09c97 fix(agents): a resumed agent's chat is readable on the phone before its first new turn (#29664)
* fix(agents): a resumed agent's chat is readable on the phone before its first new turn (#10923)

* fix(agents): skip a dropped Codex resume and keep the seeded identity across restart

* fix(agents): seed resume identity before the spawn's first await and keep it through terminal evidence

* fix(agents): seed after the spawn commits, and name the session on host-built resumes
2026-10-16 05:39:25 -07:00
Neil 6622b8298c fix(terminal): tell panes their daemon died at once and say when typed input was lost (#29660)
* fix(terminal): tell panes their daemon died at once and say when typed input was lost

* fix(terminal): use the info toast the terminal suites already stub
2026-10-16 05:39:07 -07:00
NeilandGideon c8ad8ea313 fix(projects): list symlinked folders as folders in the remote Add Project browser (#29658)
A symlink to a directory was listed as a file on SSH and managed hosts, so
projects behind a linked path could not be reached. Follow links when
classifying entries; broken links and loops stay files.

Co-authored-by: Gideon <jjin6573@naver.com>
2026-10-16 05:21:44 -07:00
Neil 62bf1d68c3 fix(projects): adding a project through a symlink alias reuses the existing project (#29651)
* fix(projects): adding a project through a symlink alias reuses the existing project

On a managed host, adding repo-link (-> repo) created a second project for the
same checkout while re-adding repo was deduped. Compare the real path, resolved
on the host that owns the files, so an alias finds the tracked project; distinct
checkouts keep distinct real paths and stay separate. Local folder workspaces
get the same check.

* test: run fixture git through process-host
2026-10-16 05:15:32 -07:00
NeilandClaude 52554b303f fix(ssh): keep desktop 2 connected with its live relay terminal when desktop 1 already moved the host (STA-10604) (#29625)
* fix(ssh): keep a host connected for its bridged relay terminals when another desktop already moved their project (STA-10604)

Desktop 2's move onto the server desktop 1 already runs refused to link a
project its own relay-era terminal still runs in, and the connect then failed
outright: this version has no relay to fall back to. The decision now keeps
that host connected and unmoved, starts the legacy relay bridge, and the old
tab reattaches its shell through it. The SSH host card names the terminals and
how to clear them; the next connect after they exit links the project.

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

* fix(ssh): release a bridged ssh: row pane's claim on detach too

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

* fix(ssh): admit the bridged mark in the renderer, and remount bridged tabs even when the connect reply lands first

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

* fix(ssh): keep the unverifiable line for a bridged host whose terminal can't be confirmed

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

* fix(ssh): keep the linked-project terminal guidance neutral; only the live bridged line reassures

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-16 04:21:24 -07:00
Neil b051ba90e6 fix(orcad): a restarted managed server keeps the tab titles of terminals it adopts (#29623) 2026-10-16 04:14:00 -07:00
NeilandClaude f1677dbf4e fix(ssh): stop a relay-era shell when its bridged tab closes (#29620)
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-16 04:08:56 -07:00
Neil 8eaaab88bd feat(wsl-mover): the ledgered desktop rewrite stage that finishes a committed move (D1b-7b) (#29597)
* feat(wsl-mover): the ledgered desktop rewrite stage that finishes a committed move (D1b-7b)

* fix(wsl-mover): a move finishes its rewrite only once every store exists (D1b-7b)

* fix(wsl-mover): chats never move per decision C, the journal enforces registry completeness, stores time out (D1b-7b)
2026-10-16 04:03:09 -07:00
Neil 294fd2ac06 fix(agent-hooks): bound retained agent exits (#29600)
* fix(agent-hooks): bound retained agent exits

Proven exits were only forgotten by a successor claim, so closed tabs and
retired panes kept theirs forever and every save rewrote them. Drop an exit
when its tab closes, its pane retires or its PTY is really torn down (not a
reconnectable disconnect), and prune exits older than the hydrate window
at save.

* fix(agent-hooks): closing a moved pane's former tab keeps its exit

* fix(agent-hooks): keep an aged exit while its retained resume row remains

* fix(agent-hooks): launch-authority retirement keeps a proven exit
2026-10-16 03:01:41 -07:00
Neil b16a71c7fb ci: reuse Windows hook builds and shorten test setup and shutdown (#29439)
* ci: remove Windows build and persistence test overhead

* ci: collect unit phase diagnostics during PR checks

* test(ci): seed hook reuse fixture from the canonical prebuild

The hook reuse regression first built into a missing private --output, so it
always reached Cargo (74s warm on Windows). Build through the default output
instead, which reuses a warm canonical prebuild, then copy its executable and
fingerprint into the private fixture root.

* fix(lint): clear inherited max-lines and broad object tab parameter after main merge

Combine the duplicate shared/execution-host imports in runtime-host-services
(301 -> 300 lines) and type the overlap test's tab mapper with the
RuntimeMobileSessionClientTab owner type instead of object.

* fix(ci): align inherited runtime and workflow contracts

* test: establish changed runtime probe signatures deterministically

* test: await asynchronous daemon profile cleanup

* test: shut down owned daemons before deleting profiles

* test: clean up oracle daemons during final app close

* test: recognize verified Linux zombie exit during daemon teardown

* fix: preserve folder SSH ownership when project groups conflict
2026-10-16 02:52:22 -07:00
Neil f387c5d19b fix(ssh): relay-era terminals' orca orchestration commands work again, behind the per-host switch (STA-10765) (#29571)
* fix(ssh): relay-era terminals' orca orchestration commands work again, behind the per-host switch (STA-10765)

* fix(ssh): attest bridge-verified relay terminals for legacy records, replay settled receipts, cancel on disconnect

* fix(ssh): admit retained legacy coordinators, their delivery targets, and legacy receipt replays

* fix(ssh): reject emptied retry ids, match moved panes by leaf, replay completed retries after reassignment

* fix(ssh): answer --help in a relay-era terminal without running the command

* fix(ssh): exempt only matching mutation replays from relay CLI scope; keep legacy retries replayable after reassignment

* fix(ssh): relay CLI security review: pane-bound legacy coordinators only, revoke and cap calls, exact-hash replays, target-aware identity, consent copy

* fix(ssh): admit settled legacy workers only with a committed receipt; honor exact reply replays
2026-10-16 02:50:24 -07:00
Neil a77cf64121 fix(accounts): open the browser for a WSL account sign-in (#29566)
* fix(accounts): open the browser for a WSL account sign-in

A WSL Add account / Sign in again ran the provider CLI inside the distro,
where stock distros have no opener, so no browser opened. Claude's link is
now caught by the same BROWSER stand-in Copy link uses, Codex's by the link
it already prints, and the desktop opens it after validation.

* fix(accounts): never open a cancelled WSL sign-in's link; wait the full login window

Addresses review: watch the login's cancel signal before opening, give auto-open
the whole login window to receive Claude's link, log the refused host, and cover
cancel-before-delivery and service wiring in tests.
2026-10-16 02:35:04 -07:00
Neil 6edf9e7a81 fix(ssh): clear the launch-session-ended verdict after this client relaunches the server (#29579) 2026-10-16 02:31:25 -07:00
Jinwoo Hong 127704b5f5 Drag a pane out to a new tab through main (dark, build switch off by default) (#29351)
* feat(layout): add the dark layout.apply channel and route pane splits through main behind ORCA_LAYOUT_OWNER

A build made with ORCA_LAYOUT_OWNER=main registers layout.apply: main applies the
window's layout command to the stored partition through the shared applyLayoutCommand,
minting new ids. A user split then waits for main's answer and mounts the pane id main
minted. Every other build substitutes 'window', so neither branch is compiled in.

* fix(layout): write only the records a layout.apply command touched

A load-then-save rewrite also normalizes records the command never touched. The command's
effect is now the diff between the save before and after it, written onto the stored
partition record by record. A split whose main reply says a paired server holds the tab
splits as today.

* fix(layout): write a load-supplied record whole and check that patched partitions reload to the command's result

* feat(layout): close, rename and equalize panes through main behind ORCA_LAYOUT_OWNER

In a layout-owner build the window's pane close, title change and equalize go through
layout.apply and the window shows main's answer. A window pane close keeps the legacy
close's rules: the tab's last pane is refused, a pane restarted since main read the close is
left alone, every partition holding the tab closes it, and the tab's remote session id follows
the remaining pane. The rules sit behind a command field only layout.apply sets.

* fix(layout): close the tab when a racing pane close leaves the window one pane

* fix(layout): leave an unmounted tab alone when main refuses its last pane

* feat(layout): move panes and save divider ratios through main behind ORCA_LAYOUT_OWNER

Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125

* test(layout): a taken pane drop whose pane closed does nothing

Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125

* test(layout): pin the window's pane move to main's saved tree, and the drops main cannot take

Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125

* fix(layout): close a user's pane even if its terminal restarted, as today

Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125

* test(layout): pin the restarted-pane close directly, not through a made-up profile state

Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125

* fix(layout): leave a split to today's path only when the workspace's row names a paired server

The split switch point asked which host to route to with a helper that falls back to the focused
server, so a focused server could claim a workspace whose row names no owner. Use the same owner
test the tab mirror uses.

* test(layout): type the split owner mock without a cast

* test(layout): type the layout-owner command mocks with the real signature

* test(layout): type the gesture command mock with the real signature

* fix(layout): close the dark path's gaps: unmounted split panes, refused or failed splits and moves, ratios during a move, release guard

- A pane main saved but the window could not mount (source pane or manager gone during the await)
  is closed again in main, so it does not come back on restart.
- A split main refuses because its copy lacks the workspace, tab or pane, or a failed call, splits
  as today; a refused or failed move moves as today.
- Divider ratios committed while a move is in flight wait for the window's move, then go to main.
- The orcad bundle gets the ORCA_LAYOUT_OWNER define when the switch is on.
- Packaging and the orcad template refuse ORCA_LAYOUT_OWNER=main and any output a dark build marked.
- workspace-layout-record-patch.ts: no non-null assertions; plain comment for the map depth.

* test(layout): count a split pane as mounted from the split mock's own results

* fix(layout): act as today whenever main lacks the target or the call throws, not just for splits

- sendPaneCommandToLayoutOwner runs asToday for workspace/tab/pane_not_found and a thrown call, so
  close, rename and equalize fall back like split and move; a handler that throws no longer runs the
  fallback too.
- A close main refuses as its last pane, while this window still has others, closes as today.
- A move whose local step throws still releases held divider ratios.
- Drop the orcad output marker: nothing read it; the template build refuses the switch itself.

* test(layout): plain names for the last-pane fallback test and the marker comment

* docs(layout): say plainly what an indeterminate write can leave behind

* fix(layout): finish the main merge with this branch's versions of the layout-owner files

* test(build): copy the layout-owner build guard into the compiler-cache checkout fixture

* feat(layout): send tab rename, color and pin through main behind the layout-owner build switch

In an ORCA_LAYOUT_OWNER=main build, the tab bar's rename, color and pin ask main's layout.apply
first; the window then runs today's action. When main lacks the tab or the call fails the
window acts as today; a paired server's workspace keeps today's path. Pinning a tab now also
ends its preview in main's copy, as the tab bar's pin does. Other builds compile the switch out.

* fix(layout): leave a pinned tab's preview mark to the window until main opens files

Changing the shared pin command would change what a paired client's pin does in every build.

* fix(layout): write a folded legacy row in its loaded form when a layout.apply command touches its claim

A legacy terminal row the load folds into a tab-bar tab stays stored as is. Closing the tab it
repeats, or giving it a tab-bar entry by moving it, let the next load resolve the claim the other
way: the row came back or took the other tab's terminal. Such a command now writes the row as
the load had it; every other record still stays as stored.

* feat(layout): accept tab moves, group splits and group sizes on layout.apply

Group sizes have no tab, so they go to the workspace's routed partition.

* refactor(layout): move the window's layout.apply sender out of the terminal pane folder

Tab groups send through it too; it now also acts as today when main lacks the group.

* feat(layout): reorder, move and split tab groups, and save group sizes, through main behind ORCA_LAYOUT_OWNER

A tab drop and Move Tab to Split wait for main's answer and then show main's placement, with main's
new group id; group divider sizes are drawn while dragging and saved by main when the drag ends.
Closing an empty group needs no command: main never holds an empty group.

* docs(layout): wrap the layout-owner sender's doc comment

* fix(layout): review fixes for tab moves through main

- Read a folded row's terminals with the loader's own claim rule, so rows sharing only an SSH
  session are covered too, and drop the row's remote session entry with it.
- The record-patch test allows a folded row only in its loaded form.
- A tab drag ends at once; main's answer shows the move after.
- A lone group main moved whole is placed so only when this window's group is lone too.

* refactor(layout): adopt only a folded row's pane layout beside its row

A row's remote session entry is carried through load and save unchanged, so adopting it from the
load changed nothing (the earlier commit's message overstated it).

* feat(layout): record a window's terminal tab close through layout.apply

closeTabs can now record each terminal tab it closes, or does not find, as closed for the given
reason (pruned as a partition's records are), so a start that commits later is refused, as today's
close records it. layout.apply takes one tab's close with the window's reason: main forces it in
every holder partition, marks a user close's launches, stops no terminal (the window already did,
sparing any another tab shares), and leaves a workspace it lacks to today's close. A sibling the
load supplied that the close only renumbered is no longer written.

* feat(layout): send the window's terminal tab close to main behind ORCA_LAYOUT_OWNER

The window still closes the tab and stops its terminals itself; main records the close through
layout.apply instead of the close intent, which stays for paired servers and when main lacks the
workspace.

* fix(layout): review fixes for the tab close through main

- The window's close sends through a store-free sender, so the store no longer imports itself.
- Main marks a user close's launches by the terminal's own id.
- A recorded close prunes the whole partition's close records, as today, not one workspace's.

* feat(layout): move a window's dragged-out pane into a new tab through layout.apply behind ORCA_LAYOUT_OWNER

* refactor(layout): keep the topology commit under its line limit

* fix(layout): review fixes for the window's pane drag-out through main

* refactor(layout): re-key a moved pane from the move alone
2026-10-16 01:52:11 -07:00
Neil 2529df8d5d fix(ssh): a disconnect during the legacy relay bridge wait no longer republishes connected (#29544)
Refs STA-10395
2026-10-16 01:31:58 -07:00