Repository navigation
fix(remote-runtime): wait for the desktop's terminal list before opening a terminal - #28154
Conversation
… a terminal A paired client opening a workspace whose terminals it had not heard about yet read "no answer from the host" as "zero terminals" and asked the host for one. When the host's list then arrived with terminals, the workspace gained an extra terminal; when it arrived empty, the first-frame bootstrap created a second one. The client now treats an unknown host count as unknown. Activation without explicit startup work waits, and the active subscription's first real answer seeds the workspace if it is empty. An "ask me later" frame from a host that has not published yet no longer records a count of zero, and the host's later answer (sent as an update) is accepted as the first answer for seeding.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
… later Hosts before #25736 answer an empty workspace with "ask me later" and never follow it with a real answer, so waiting for that answer left a blank workspace with no terminal against them. Wait only on hosts that advertise session-tabs.empty-worktree-answer.v1; older hosts keep main's behaviour. Workspaces this client just created are known empty and open their first terminal without waiting. Co-Authored-By: Claude <noreply@anthropic.com>
…t flag Co-Authored-By: Claude <noreply@anthropic.com>
ELI5
When a browser, or another desktop, paired with a desktop opened a workspace, it sometimes asked the desktop for a new terminal before the desktop had told it which terminals already existed. "I haven't heard yet" was read as "there are none", so the workspace could get an extra terminal, or two. Now the client waits for the desktop's list and decides from that.
What Changed
Before: opening (or switching to) a workspace that the desktop owns, right after the client connected or reconnected, could add a terminal the user did not ask for. If the desktop already had terminals, the workspace gained one more. If it had none, two were created: one by the "open workspace" step and one by the step that seeds an empty workspace when the desktop's first list arrives.
After: the workspace shows exactly the desktop's terminals. If the desktop answers that the workspace is empty, exactly one terminal is opened, as before.
Mechanism:
tracking-lifecycle.ts).active-session-subscription.ts) creates the terminal if the workspace really is empty. Opens that carry a startup command keep creating directly, because the seeding step can only open a plain terminal and would drop the command.session-tabs.empty-worktree-answer.v1(new modulesession-tabs-runtime-capabilities.ts, through the existing runtime capability list) to say it does send that answer. The client waits only for desktops that advertise it. For any other desktop, or if the check fails, an unknown count is treated as 0, exactly as on main. Desktops from 1.4.223 up to this release do not advertise it, so they also keep main's behaviour. Delete the check once every supported desktop advertises the capability.unknownHostCountIsEmptyand opens its first terminal right away, as on main. That includes a blank workspace created in the background. Waiting there would leave the desktop window and the phone with no terminal, which is a visible change.tracking.ts), and the desktop's later real answer, which arrives as an update rather than a first snapshot, is accepted as the first answer for seeding (tracking-decisions.ts). Without this, a workspace opened while the desktop was still starting would end up with no terminal.Why
This rule was added in #4825 (fix for a workspace-switching loop), and #21630 narrowed the field-reported "a terminal every time, sometimes two" duplicate, but left the gap between connecting and the desktop's first list. The client was guessing from a partial copy; the desktop owns the answer. Two alternatives were set aside:
The existing first-list seeding step already makes this decision from the desktop's real answer, so this change routes the unknown case to it. The only wire addition is one capability string a desktop advertises, which older clients ignore. Desktops without it keep main's behaviour.
Linked Issue
N/A (internal legacy-rules audit, rule 10).
Visual Proof
N/A: the change removes a duplicate terminal that only appears in a race between connecting and the desktop's first tab list. The unit tests below drive that exact ordering.
Testing
New tests in
src/renderer/src/runtime/web-session-tabs-sync-initial-terminal-relaunch.test.tsxdrive the real tab-sync subscription with the "open workspace" step called before the desktop's first list:worktree-creation-agent-seeding.test.tschecks that the background blank create passes the flag.Existing activation tests that model "the desktop already said the workspace is empty" now record that answer explicitly.
pnpm tc, oxlint,pnpm run check:code-quality:changed, and the full renderer unit suite pass (one unrelated terminal-snapshot file failed under load and passes alone).e2e: full suite and the workspace-layout oracle specs dispatched on this head.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Review
Agent skill upstream boundary
Notes
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)