* Layout groundwork (switched off): main derives agent tab titles from its own hook status
With the layout-owner switch on, main gives agent tabs their generated titles from
the hook-server status it owns, on the desktop, headless serve and orcad: one
renameTabs per status batch, so one write and one frame. It keeps the window's
rules (setting, custom and quick-command titles, first title wins, dispatch labels).
The window stops sending generated titles for tabs main holds; a paired server's
tab, or one main has no tab-bar entry for, is still titled by the window as today.
The title rules move to src/shared (agent-row-primary-text, and the new
agent-generated-tab-title-rules) so both sides share them; switch-off behaviour
is unchanged.
* feat(layout): main applies a phone's or paired client's tab move itself, and a tab move names the tab it follows so a stale index can't misplace it (layout-owner build, L193)
* fix(layout): a move in a group showing a tab main lacks goes the window's way, a twin's agent tab keeps its window title, and orcad subscribes titles through the store attach (layout-owner build)
* chore(layout): main's tab move reaches the old-client translation through its compat entry
* chore(layout): mark the window-only-row move fallback as bridge code (ledger L280)
* test(layout): attaching the hook store follows its rows for main's tab titles once
* chore(layout): the old-client move translation is a compat entry of its own, with no cyclic re-export
* test(config): the boundary message test names the old-client folder's configured entries
* fix(wsl-host): pair again from the distro when a WSL host refuses the enrolled token
A WSL host that lost its device registry, or revoked this desktop, refused the
enrolled token forever, and an update over it read as deferred. The connect now
re-pairs through the managed repair gate SSH uses (one repair at a time, a
capped number per window, only an offer under the pinned host key), reading the
host's published offer from the distro. The incumbent's terminal count uses the
same enrolled-or-live pairing the connect does.
* fix(wsl-host): retire a bridge whose pairing was refused, and let a user's Connect retry a repair
A refused or repaired-then-refused pairing on a reused bridge left its stale
token cached, and the failure status then saved it over the repair. That bridge
now closes first. A user-initiated Connect clears a standing repair failure or a
spent cap, as an explicit SSH connect does.
* fix(wsl-host): retire a refused bridge without cancelling a queued Update or Force
* fix(wsl-host): repair only a stored pairing, dispose the repair's transport directly, and log refusals neutrally
A host still being added has no stored record for the gate to re-pair, so its
live bridge is reused as before. The WSL repair deps are typed with the WSL
transport, and the shared refusal log no longer says SSH for WSL.
* fix(ssh): point unclearable move conflicts at plain SSH, and polish the plain SSH window
Conflicts retrying can't clear now say how to keep working on the host. The
plain SSH terminal paints its theme background past the grid, and a failed
open shows only its error, not an empty terminal.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): say what plain SSH is for beside its button, not in main's refusal text
Main's refusal text also reaches clients without a plain SSH terminal, so the
next step is shown next to the button wherever it renders. Also: a translucent
theme isn't painted twice, and a failed open shrinks to its error.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): treat only opacity below 1 as a translucent plain SSH background
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Preserve deliberate terminal taps after scrolling and keep them ordered with Live input. Retain fresh keyless edits, cap coalesced sends at the existing UTF-8 request limit, and settle cancelled flush barriers without waiting for retired acknowledgements.
Adapted from @innocarpe's community PR #30514, with additional ordering, lifecycle and bounded-send regressions.
Fixes#30510
Co-authored-by: Wooseong Kim <innocarpe@gmail.com>
* Polish explorer search layout and filter disclosure
* Use compact search details disclosure and lowercase filter labels
* fix: preserve query focus when switching explorer modes
* fix: announce active explorer search filter counts
* fix(mobile): retire dismissed branch diff requests
A pending branch diff reopens a dismissed drawer and blocks replacement previews. Retire requests on dismissal and host/workspace changes, and keep spinner ownership with the current request.
* fix(mobile): retain branch preview through suspended transitions
* test(mobile): retain confirmed branch previews across connection cutover
* fix(mobile): retain quick command editor ownership during saves
A deferred Save discards newer edits or closes a replacement editor, including after host/repository changes. Bind each save to its editor and scope; preserve newer text and the persisted command id.
* fix(mobile): preserve quick command saves through suspended renders
* test(mobile): preserve quick-command edits during connection migration
Reconnect refreshes only the root and retains deleted nested entries; interrupted children can remain loading. Invalidate child reads and refresh expanded folders. Bound deep indentation to keep filenames reachable.
Fresh repository objects reset explicit setup choices, while host changes can retain stale scripts and trust. Use logical repository and runtime ownership.
Delayed hydration and out-of-order storage writes can reverse a browser destination selection. Order durable writes and preserve the confirmed value when saving fails.
With the layout-owner switch on, session.tabs takes main's markdown edit row and copies the
window's view facts onto it, but not the untitled flag, which the saved session never records.
The phone then offered to save an untitled document as an ordinary file. Carry the flag too.
The route tests now use a realistic store: it lists its host partitions and saves each open
editor's unified tab and group, as the window does.
* fix(session-tabs): a confirmed close of a pinned server tab closes it instead of snapping back
A paired desktop sent its confirmed close of a pinned terminal tab in a
server workspace over session.tabs.close, which had no force, so the
server refused it (terminal_tab_pinned) and the tab came back.
- session.tabs.close takes an optional `force: true`, honoured only with
an explicit `reason: 'user'` and passed to the server's existing forced
close (the same path worktree stop uses), in both builds.
- The server advertises `session-tabs.close-force.v1` in both builds. The
desktop sends force only after the pinned-tab confirmation and only to
a server advertising it; an older server keeps today's refusal.
- A forced close the server never received keeps its force in the held
replay record, so the replay is still the confirmed close.
- Moves the undelivered-close hold helpers into
web-session-undelivered-close.ts unchanged, to keep the lifecycle
module under the line limit.
* fix(session-tabs): a pinned server tab closes when the pin confirmation is turned off
A local pinned tab closes at once when confirmClosePinnedTab is off, so the
close itself is the user's consent. A server workspace's pinned tab now
sends that consent as force too (still only to a server advertising
session-tabs.close-force.v1). Lifecycle closes (pty-exit), rejectPinned
callers and bulk closes are unchanged.
* test(session-tabs): load the forced-close server test once; cover held and probe-failed forced closes
- session-tab-close-force.test.ts imports the runtime once and flips the
layout-owner switch per case through the mock's getter, instead of
resetting modules and re-importing the runtime for every case; drops
the 120 s timeouts.
- A forced close held while the session is inactive, and one whose
capability probe failed, keep their force for the replay.
- A pinned lifecycle (pty-exit) close never forces, even with the pin
confirmation turned off.
wsl.exe imports only the variables WSLENV names. ORCA_WORKTREE_ID crossed but ORCA_WORKSPACE_ID
did not, so a WSL shell never saw it, whether the window or main started the terminal.
* fix(ci): recover verified pnpm setup from registry metadata outages
* fix(ci): prepare native pnpm shims after fallback verification
* fix(ci): provide Node for pnpm fallback in bare containers
* chore(cloud): update relay runtimes and security scanning
* docs(cloud): record Go binary advisory reachability
* chore(cloud): rerun security checks after resolving main conflict