* 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>
* 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
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.
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.
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.
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.
* 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
* 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
* 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
* 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)
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#30086Fixes#30085
* 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
* 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
* 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
* 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>
* 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
* 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
* 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>
* 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
* 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
* 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
* 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
* 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
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.
* 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>
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>
* 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
* 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
* 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
* 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
* 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.
* 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
* 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
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>
* 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
* 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>
* 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)
* 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
* 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
* 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.
* 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