Repository navigation
Fix missing Terminals tab while Cloud machine connects - #17326
Conversation
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
All contributors have signed the CLA ✍️ ✅ |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (3)No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review. 📝 WalkthroughWalkthroughConnecting cloud machines with available machine info now show a Terminals group. A regression test checks that a non-desktop machine’s group contains one “No terminals yet” placeholder. ChangesCloud terminals visibility
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~8 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to Connecting cloud machines can show the Terminals tab before terminals arrive, with a regression test for the empty state. No actionable merge-blocking risk is evident. 🚥 Pre-merge checks | ✅ 24 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (24 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Merge receipt for |
Dogfood tours of
|
7997c55 fix(cloud): update machine rename optimistically (manaflow-ai#17324) c9bdbd6 Fix missing Terminals tab while Cloud machine connects (manaflow-ai#17326) b047fa3 Fix Agent Hibernation never selecting live Claude Code sessions (manaflow-ai#17306) 9aefea4 cloud sidebar polish: header refresh, tab switch, empty states, errors and upgrade (manaflow-ai#17074) # Conflicts: # .github/workflows/ci-guards.yml # .github/workflows/ci.yml
* test(cloud): display health checks must not black-list websockify viewers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): stop Xvnc black-listing every viewer of additional displays Xvnc black-lists a peer after five unauthenticated connections, for a timeout that doubles each time. Every viewer of an additional display is websockify on 127.0.0.1, and the helper's 30s health check read the RFB greeting and hung up, so displays soon answered every connection with "Too many security failures". Restored panes and quiet retries then failed for minutes. Start additional displays with -UseBlacklist=0 (SecurityTypes None behind the private network gives it nothing to protect; Xvnc refuses runtime changes), complete the None handshake in the health check so it clears marks instead of adding them, and replace recovery's pgrep patterns, which pgrep's regex dialect rejected, with exact argv matching. Each helper request also runs in a plain shell now: the login shell cost about 0.7s per call and only the long-lived service needs its environment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): New Display hands over a running standby display Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * perf(cloud): keep one standby display running per desktop VM Each New Display started Xvnc, a desktop session and websockify on the guest (about 0.7s) while the user waited. The guest helper now keeps one display running outside the catalog, hands it over on create (about 0.1s) and starts the next in the background. The standby is invisible to list, does not count against capacity, and a restarted helper adopts it instead of leaking it. Opening a machine's Displays tab, or restoring it selected, runs guest discovery once so the standby is warm before the first click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): failed or launching standby displays are never misassigned Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): serialize standby handover; retire failed standbys; rediscover after wake Concurrent creates could record a launching standby's number as a normal display; take the standby under one lock and reserve running numbers. A standby whose start failed is stopped and replaced instead of handed over or retried forever. Displays-tab discovery runs once per open and retries when a sleeping machine wakes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): align two sidebar tests with merged behavior A connecting machine keeps its Terminals tab (#17326), and every visible machine row requests a cached port scan once (#17074). Both tests still asserted the earlier behavior and failed on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): standby never takes a recorded number; failed discovery retries Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): address review: standby race and Displays discovery retry ensure_standby's locked check now also rejects a number a concurrent create recorded after the unlocked probe, so a display can never be both a catalog display and the standby. Displays-tab discovery reports completion; a failed discovery clears the request and retries, bounded to three attempts per shown machine, instead of treating task launch as done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): connecting machines keep only the Resources tab (#17139) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a stale Displays discovery cannot retry after the tab reopens Drive discovery completions explicitly instead of yielding a fixed number of times. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): bind each Displays discovery completion to its request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#17327) * test(cloud): display health checks must not black-list websockify viewers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): stop Xvnc black-listing every viewer of additional displays Xvnc black-lists a peer after five unauthenticated connections, for a timeout that doubles each time. Every viewer of an additional display is websockify on 127.0.0.1, and the helper's 30s health check read the RFB greeting and hung up, so displays soon answered every connection with "Too many security failures". Restored panes and quiet retries then failed for minutes. Start additional displays with -UseBlacklist=0 (SecurityTypes None behind the private network gives it nothing to protect; Xvnc refuses runtime changes), complete the None handshake in the health check so it clears marks instead of adding them, and replace recovery's pgrep patterns, which pgrep's regex dialect rejected, with exact argv matching. Each helper request also runs in a plain shell now: the login shell cost about 0.7s per call and only the long-lived service needs its environment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): New Display hands over a running standby display Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * perf(cloud): keep one standby display running per desktop VM Each New Display started Xvnc, a desktop session and websockify on the guest (about 0.7s) while the user waited. The guest helper now keeps one display running outside the catalog, hands it over on create (about 0.1s) and starts the next in the background. The standby is invisible to list, does not count against capacity, and a restarted helper adopts it instead of leaking it. Opening a machine's Displays tab, or restoring it selected, runs guest discovery once so the standby is warm before the first click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): failed or launching standby displays are never misassigned Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): serialize standby handover; retire failed standbys; rediscover after wake Concurrent creates could record a launching standby's number as a normal display; take the standby under one lock and reserve running numbers. A standby whose start failed is stopped and replaced instead of handed over or retried forever. Displays-tab discovery runs once per open and retries when a sleeping machine wakes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a closed display view is not rebuilt from a stale graph Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): load every workspace display and keep closed displays closed Displays beyond the first in a Cloud workspace layout appeared late: the catalog only learns display:N from guest discovery and drops memberships for displays it does not know, and nothing on open or restore ran discovery. Publishing a graph whose memberships name unknown displays now runs discovery once per lifecycle generation. Closed display panes came back: the membership removal is queued while reconciliation still reads the graph holding the token, so it rebuilt the pane under a new panel id and left an orphaned token that resurrected it after every close. Closing now fences the view until a fetched graph drops its token, retries a removal that has not landed, and a pane rebuilt from an orphaned token removes that token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): discover member displays on deltas; bound and scope token cleanup Membership rows arrive as projection deltas, so discovery also runs from publishDelta. Orphan cleanup skips other Macs' tokens (a no-op write that still cost a guest snapshot), removal retries stop after three attempts, and the client id is read once per close. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): prune this Mac's orphaned display memberships in open workspaces A membership token whose pane is gone (an old close whose removal never landed, a crash, a pane rebuilt under a new id) showed as a duplicate display row and resurrected the display after it was closed; the reconciler treats one live pane as satisfying every token for that display, so nothing removed it. After reconciling an open Cloud workspace, remove this Mac's tokens with no live display pane, once the machine's restore has settled. Tokens of workspaces not open here, and of other Macs, are kept as their layout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): keep display discovery results across machine-list polls refreshDisplays dropped its result whenever refreshGeneration changed, and every machine-list poll bumps it, so a ~2s guest discovery that overlapped a poll was discarded: workspace displays loaded only after a later lucky discovery. Check the lifecycle generation only; the coordinator already invalidates on identity or image changes. Member-display discovery also re-checks after each attempt (bounded to three per lifecycle) because a launch-time refresh can cancel one, verified live: the first attempt's exec was cancelled after 1ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): member display listed once; silent desktop probe is not unreachable Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): list a workspace display once; stop repairing healthy desktops The sidebar listed a workspace's display twice: cloudWorkspaceResources appends a copy of a member display carrying its membership view, and localWorkspaceMembers deduped against the first copy (the pool resource, without the view), so the local pane added the display again. Display 1 sat on "Loading Cloud page" for 20s+: the desktop probe's 2s deadline never cancelled its connection, so a busy carrier held it to the proxy's 10s header timeout, and the timeout read as unreachable and ran the control plane's desktop repair (a guest exec, ~12s) on a healthy desktop. The deadline now cancels the connection, and repair runs only when the proxy or service answered with an error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a New Display pane and its membership are one sidebar row Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): build workspace rows and local-pane rows from one resource list The sidebar built workspace rows from cloudWorkspaceResources (which holds the membership copy of a member display) but deduped local panes against the pool resources alone, so a New Display pane listed its display twice. Both passes now read the same list. Adds debug.cloudtree.rows (DEBUG only), returning the Cloud sidebar's rows from the same builder, so dogfood can assert listed rows; duplicate rows were invisible to cloud tree --json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): display names parse from the daemon graph Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cloud): named displays, display tab titles, remove a display from a workspace Display panes showed noVNC's page title, and renaming a workspace display sent a synthetic view id to the daemon's tab rename, which cannot work. Displays now have one shared name per display, stored as a frontend projection beside the workspace memberships so every client follows a rename live. Rows and pane tabs show it ("Display N" until renamed); renaming the tab or the row renames the display; clearing restores the number. Workspace display rows get a hover X and a "Remove from Workspace" menu item, which close the display's pane on this Mac (the fenced membership removal) or remove this Mac's membership when no pane is open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ci): list debug.cloudtree.rows as a debug method; fold display names into the membership type The socket capability guard requires debug methods to be listed as intentionally unadvertised, and the package conventions lint rejects an all-static enum, so the display-name constants move onto CloudVMDisplayMembership. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a display row's Rename names the display The menu now routes display renames to renameDisplay (one name per display, shared by every row and pane) instead of a view's tab rename. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): align two sidebar tests with merged behavior A connecting machine keeps its Terminals tab (#17326), and every visible machine row requests a cached port scan once (#17074). Both tests still asserted the earlier behavior and failed on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): the desktop placeholder is titled Display 1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): title display panes from the click, never Desktop first The display 1 placeholder (shown before guest discovery) was titled "Desktop" and renamed "Display 1" seconds later; it now uses the same numbered title as discovery. A new display's pane is titled "Starting display…" from the click instead of "New tab", then takes the display's name when it materializes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): standby never takes a recorded number; failed discovery retries Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): address review: standby race and Displays discovery retry ensure_standby's locked check now also rejects a number a concurrent create recorded after the unlocked probe, so a display can never be both a catalog display and the standby. Displays-tab discovery reports completion; a failed discovery clears the request and retries, bounded to three attempts per shown machine, instead of treating task launch as done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): connecting machines keep only the Resources tab (#17139) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a stale Displays discovery cannot retry after the tab reopens Drive discovery completions explicitly instead of yielding a fixed number of times. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): bind each Displays discovery completion to its request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): closing a display pane removes it for every client Drives the real pane-close path. Another client's token in the same workspace must not rebuild the pane, including when the close lands before this pane's own token reaches the graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): closed displays stay closed across clients and instances - Closing a display pane or clicking X removes the display from that Cloud workspace for every client. The fence is keyed by machine, workspace and display, set at close from the pane's own workspace, and lifted when this Mac opens the display there again. - Pruning only touches view IDs this process recorded: stable and DEV builds on one Mac share a client ID. - A sleeping machine or an undiscovered display does not spend a removal attempt. - Tab renames run in order, and afterwards every pane shows the display's real name, so a cleared or failed rename reverts the tab. - A failed reserved pane drops its "Starting display…" title. - A reset or refused connection after the tunnel opens reads as unreachable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a desktop that resets the opened tunnel is unreachable Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): read a reset after the desktop tunnel opens as unreachable The probe's errors arrive as NWConnection.StreamError, so the previous NWError cast never matched. Only the HEAD stage maps a reset or refusal; before the tunnel opens the same error belongs to the local proxy and stays unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a queued close cannot undo a reopen; another client's re-add shows again Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): order display removals against reopens; release on another client's re-add - A reopen bumps the display's generation, so a close or removal retry that started before it leaves the reopened display alone. - Removal retries run on the machine's lane, ordered with the reopen's attach; the lane's enqueue is split into a resource-keyed core. - A removal records the tokens it deleted. A later graph showing any other token means another client put the display back, so the fence lifts. - Attempts are counted per closed display and only while it is fenced. - A tab rename re-applies the display's name only when it changed nothing or failed, so a successful rename no longer flashes the old name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): type the lane failure handler explicitly The ternary of closures crashed the type checker (failed to produce diagnostic). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud): a no-op display removal still fences older graphs; proxy reset is unknown Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): release a closed display by graph revision, not token sets A removal now reports the cursor of the graph it was computed from. A graph no newer than that predates the removal and stays fenced, including when the removal found nothing to delete. A newer graph that still shows the display means another client put it back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): fence a closed display up to its removal write's own cursor A graph published between the removal's snapshot read and its write could be newer than the snapshot yet still hold the removed tokens, releasing the fence early. The removal now reports the write receipt's cursor (the snapshot's only for a no-op), and a reply without one keeps the fence until the display is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>





Changelog
Fixed: keep the Terminals tab visible while a new Cloud machine is connecting.
Problem
A connecting machine with no terminal snapshot omitted its Terminals group, leaving the sidebar with Ports, Displays, and Resources only.
Change
The tree builder now includes the Terminals group during
.connecting, so the tab remains available and showsNo terminals yetuntil the machine reports its terminals.Validation
c060419efb5(test: keep cloud terminals tab visible while connecting)8909eeb9c6f(fix: show cloud terminals tab while connecting)git diff --checkpassed.Callsign registration timed out, so this PR is signed
unregistered.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Fixes the Cloud sidebar so the Terminals tab stays visible while a machine is connecting, instead of disappearing until the machine reports its first terminal snapshot.
.connectingstate, showing "No terminals yet" as a placeholder.Written for commit 8909eeb. Summary will update on new commits.
Summary by CodeRabbit