Repository navigation
cmux NEXT: a pane's top-right is one hover "…" in place of its buttons - #20119
Conversation
… no split buttons (Leo 10-12) Red: today the corner shows Split Right, Split Down and the tab's actions as buttons, "…" holds only the overflow, and a zoomed pane lights a zoom button. The seams (PaneToolbar init with newTabMenu, the view's HoverReveal) keep the old behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dropping Split Right/Down was meant for the composer's ellipsis, not the pane. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…buttons (Leo 10-12) The row of buttons (Split Right, Split Down, the tab's actions) goes away. One "…" fades in while the pointer is over the pane's top-right corner (the shared HoverReveal, like the strip's plus) and while its menu is open; a zoomed pane keeps it shown and lit. Its menu is the strip plus's (a terminal, a browser, an agent chat in this pane), then Split Right, Split Down, the tab's own actions and Toggle Pane Zoom. Hide/Show button menus go with the buttons; an action in tabs.hiddenButtons is left out of the menu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The hover reaches 96 pt left of "…" over the tab bar (the pane's corner), not only "…"'s own cell; the corner's tracking area lives on the pane. - The tint follows theme changes (set in layout and appearance hooks). - tabs.hiddenButtons no longer filters "…": it hid buttons from the old row, which put them under "…", so everything stays reachable. - "…" builds the plus's rows without its Chromium warmup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
|
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by |
A synthetic enter (debug.pointer_hover) carries no tracking area, so the area check dropped it; the view owns no other area. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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. |
CaptureFleet DEV build of 8ef8b91 on a capture slot (showcase profile), right pane only.
The capture found a bug, fixed in 8ef8b91: a synthetic enter carries no tracking area, so the corner ignored it. ReceiptsAll on fleet (Xcode 26.6).
|
…0115) * test(optchat-chief): link previews on Chief replies (red, behavior) The brain runs end to end against the fake conversation owner: a reply line that is only a URL goes out as a link_preview part whose picture is uploaded once as an attachment record; a failed fetch sends the URL only; and the SSRF guard keeps every fetch off loopback, private and link-local hosts, by literal, by name (localhost), by redirect and by og:image, so none of those URLs reaches the transport. Re-applied from the orphaned feat-cmux-next-chief-link-preview (bead cx-ebm.47). The orphan's unit tests of the guard, metadata, picture and line-split functions are not carried over (no-unit-tests rule, 2026-10-10); the guard is proven through the brain instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(optchat-chief): link previews on Chief replies A reply line that is only an http(s) URL becomes a link_preview part in its place. The host fetches the page's title, site and image through an SSRF guard (src/link_preview/guard.rs): http(s) on the default port, no credentials, every resolved address public (no loopback, private, CGNAT, link-local, ULA; mapped IPv6 as IPv4), the transport connects only to the checked addresses (ureq resolver, so a rebinding answer is never used), at most 5 redirects each re-checked and never https to http, no proxy and no cookies, 512 KB of HTML (head only), 5 MB of image, 8 s per preview. The picture becomes a JPEG of at most 512000 bytes uploaded as an attachment record (conversation-attachment-upload); a preview that fails or is late leaves the URL only. OPTCHAT_CHIEF_LINK_PREVIEWS=0 turns it off. Cargo.lock (optchat-chief's own workspace): image and url, resolved on a Testbox with cargo metadata. cmux-tui-rust-check.sh gets the optchat-chief mode beside rb-testhost (short TMPDIR for its socket tests). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * CmuxHomeCore, MessagesLab: the sender attaches link previews A draft with URL-only lines waits for each card's fetch (the one MessagesLab's send started; the local message already flies with the grey card), then sends HomeStore parts in TextParts order: .text blocks and .linkPreview(url, title, site, image). The picture (LinkPreviews' file) becomes a JPEG of at most 1024 px and 512 KB uploaded as its own image record with the message (HomeStore.prepareLinkPreviewImage, send(conversation:parts:uploads:key:)); the owner checks its hash like an attachment's. A failed fetch sends the URL only. LinkPreview.sendable applies the owner's URL and label rules before the send. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * optchat-chief: rustfmt the link preview test and brain modules Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * optchat-chief: op_entry starts without a preview hold The tip's op_entry (added after the orphan branch) builds an OutboxEntry by hand; it gets previews_until: None like reply_entry. The turn-reply doc comment goes back above reply_entry. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(optchat-chief): link preview review, red behavior tests Through the brain and the fake owner: a URL only the agent wrote is never fetched (the reply goes as its text); an owner without link-preview-v1 gets the plain text; a reply whose card the owner refuses goes again as its original text under a new key; a picture wider than 4096 px is not decoded; IPv4-translated (::ffff:0:0/96), local-use NAT64 (64:ff9b:1::/48) and Teredo (2001::/32) addresses are never requested. Picture uploads move to an uploader the brain hands to the preview thread (FakeUploader in the harness). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(optchat-chief): link preview review: provenance, capability, fallback, caps - Only a URL a person wrote verbatim in one of the conversation's last 200 messages (text or own link card) becomes a card; a URL only the agent wrote stays text and is never fetched (security policy from the review; tool-result URLs are not previewed yet, the stricter subset). - Cards go only to an owner that advertises link-preview-v1; an owner that refuses them gets the reply's original text, unchanged, under the key '<key>:text' (OutboxEntry::plain_text). A reply is never dropped. - Picture uploads run on the preview thread through an ImageUploader with its own connection bound as the chief's agent, never on the brain thread. - The picture decoder takes at most 4096 px a side and 64 MB, scales from the one decoded image without copying it per try, and stops at the deadline (before the decode and before each encode try). - The guard refuses ::ffff:0:0/96, 64:ff9b:1::/48 and 2001::/32, and a name lookup takes 3 s at most. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * CmuxHomeCore, MessagesLab, CmuxNext: link sends log first and check link-preview-v1 A draft with URL-only lines is logged at the press as its plain text (HomeStore.send(...attaching:)): the row keeps its place in the send queue and a quit before the previews arrive still sends the text. The previews then replace the logged op (same key, same position) and the pictures upload with it. HomeLinkSend attaches cards only when the owner takes them (HomeSource.acceptsLinkPreviews: the local daemon advertises link-preview-v1; the cloud and older daemons get plain text). DaemonCapabilities lists link-preview-v1 as optional (plans/cmux-next/daemon-capabilities.json updated by hand in the encoder's format). No unit tests (no-unit-tests rule); the real check is a tagged app against an older daemon and a quit during a preview fetch. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * optchat-chief: keep the reply key for the preview thread's fallback Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(optchat-chief): only an exact URL token a person wrote gets a card (red) A shortened query or a shortened host of a person's URL gets no card and no fetch; the exact URL inside a longer sentence (with trailing punctuation or brackets) gets one; a URL in a person's link preview title does not count. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(optchat-chief): previews need an exact URL token a person wrote; the read moves off the brain thread - A card's URL must equal a URL token of a person's text parts (split on whitespace, leading brackets and trailing punctuation stripped, the same ends as split.rs sole_url) or the URL of a person's own link card; a prefix of a person's URL (a shorter query or host) and a URL in a card's title do not count. - The conversation read, the split, the fetches and the uploads run on the preview thread's own connection (PreviewPort: snapshot and upload_image); the reply waits in the outbox as its text and gets its cards when the thread answers, or goes as its text when the hold ends. The text fallback after a refusal applies only to an op with cards. - At most two picture decodes at once (a slot waits only until the deadline); a DNS lookup is clamped to the request's deadline. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: Update Ready card: See all changes, stacked untruncated buttons; Updated card button on one line; DEV changelog reads cmux-next nightly notes (cx-7rone) - Ready card: up to 3 lines, Restart to Update full width, a quiet full-width See all changes under it (opens What's New for the staged span through the new openUpdateChanges intent); the side-by-side Release Notes button truncated both labels below a 260 pt sidebar. - Updated card: its button carries its own styles (the surface document does not load styles.css) and keeps one line; Share moves under it when narrow. - Changelog page: a DEV build with no SUFeedURL listed the stable fallback's notes (none: 'No release notes yet'); it now lists the cmux-next nightly notes (files-next.cmux.com/nightly-next/notes), built from the same branch. - Update harness: --notes also signs notes/index.json (the page lists only the index); --changelog-shots captures the cards at the 160 pt sidebar and the What's New page each button opens; debug.update_surfaces gains sidebar-width, open-changes and open-whats-new. * cmux-next: cx-7rone review fixes: See all changes falls back to the web release notes without signed notes, DEV page selects the newest nightly, harness restores the sidebar width, long card labels end in an ellipsis, 3 changelog lines everywhere (cx-7rone) * cmux-next: update harness: dev_changelog.py captures a plain DEV build's What's New page; changelog shots list the windows (cx-7rone) * cmux-next: a restored What's New tab keeps its title and page: the changelog provider registers at launch (cx-warpr) The provider registered only on the first open, so a What's New tab that the session restored after a relaunch (or that Reopen Closed brought back in a new process) had no provider: the strip showed the store tab's title (Home) and the pane showed no page, and the next open selected that empty tab. reopen_page_title.py: open, close, Cmd-Shift-T action, relaunch, captures. * cmux-next: update-harness proof scripts: socket runs ask for focus, check each reply, refuse a live tag socket, stop when the first instance does not quit (cx-warpr review) * cmux-next: closing a non-last window closes it like a browser window: it keeps its workspaces as one closed group that Cmd-Shift-T reopens whole (cx-gzh.9.3) Chief decision 2026-10-12. Before, a non-last window moved its workspaces into the most recent other window and its record went away, so the close made no closed group and could not be undone. Now every normal window closes the way the last one did: kept closed with its workspaces (their terminals and agents keep running), so the window record goes open:false and the daemon stores one `window` closed group (cx-gzh.9.1); Cmd-Shift-T or History reopens the window with its workspaces. WindowRecord.closed (projection key `closed`) keeps a closed window closed across a relaunch; when every saved window is closed, the front one opens, as before. The launch window never adopts a closed window. Incognito windows still close for good. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(cmux-tui): a personal workspace keeps its own remote-localhost choice Red for cx-d0d.41: set-personal-workspace takes remote_localhost (null clears), list-personal carries it, identify advertises personal-remote-localhost-v1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: restored closed windows through WindowRegistry.setRestored (windows has a private setter) (cx-gzh.9.3) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: DEV changelog notes: a DEV bundle names the stable feed URL, so key on the channel, not on a missing SUFeedURL (cx-7rone) * cmux-tui: socket behavior test, a closed workspace's agent-home folder follows its reopen and goes to trash-pending on delete (cx-gzh.9.2, red) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui + cmux-next: a reopened workspace keeps its agent-home folder; a deleted closed workspace's folder goes to the Trash (cx-gzh.9.2) AgentHomeHistory left with the Swift closed trackers (cx-gzh.9); since then a reopened folderless workspace lost its chat files (the folder is named by the workspace key, and a reopen gets a new key) and deleted entries left their folders behind. The daemon owns closed history and the agent-home base (agent_start), so it moves the folders now (state/agent_home_moves.rs): - closed.reopen: after the commit, `<base>/<closed key>` becomes `<base>/<reopened key>` (before the reply, so before the first chat). - closed.delete: the folders of the deleted workspace members that no live workspace uses move to `<base>/.trash-pending/`. - Never a symlink, never over an existing target, only safe keys; a failure is logged and the folder stays. - The app sends `.trash-pending` to the macOS Trash (AgentHome .emptyTrashPending) after its own deletes and at launch (CLI deletes), never a hard delete. No workspace key crosses the v2 resource API (private identity). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui-core: module order (rustfmt) (cx-gzh.9.2) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: a personal workspace keeps its own remote-localhost choice cx-d0d.41 (call 2026-10-12: the per-workspace override is personal state). personal_workspaces gains remote_localhost (0/1, NULL follows browser.remoteLocalhost), added in place to older registries. set-personal-workspace takes remote_localhost (null clears); the row, list-personal and personal.workspace.updated carry it; identify advertises personal-remote-localhost-v1. Spec (commands.md, sdk-schema.json) and the generated SDK layers follow. set-personal-workspace now hands its command to cmd_profiles, and the per-column updates are one loop, so server.rs and personal_mutations.rs stay within the god-file budget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui + cmux-next: closed windows and agent-home folders, review fixes (cx-gzh.9.3, cx-gzh.9.2) - A deleted window group (History Remove, Clear History) releases its closed window: the workspaces move to the most recent open window, or the window opens again; no running workspace stays hidden. - On a daemon without window records a non-last window merges into the heir window as before (no closed group would record it). - At launch, when every window left after reconciling is closed, the most recent one opens (the app never starts with no window). - A closed window becomes the most recent one (a Dock click or a relaunch brings back the last window closed). - Reopen: when the reopened workspace already has its own agent-home folder, the old one goes to trash-pending instead of staying orphaned; the daemon moves nothing under a non-canonical base. Docs updated. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * optchat-chief: Cargo.lock for image and url on the current tip Resolved on a Testbox with cargo metadata after merging the tip (the merge took the tip's lockfile, which lacks the link preview crates). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: crash ratchet: weak services in ClosedHistoryRetention, checked age math in ClosedRetention, link-filter cwd pushed instead of assumeIsolated (cx-zknal) - CmuxNextApp unowned (0f2bf3e): services is weak; a gone AppServices stops the checks. - CmuxNextDaemon int_conversion (0f2bf3e): UInt64(clamping:) and an overflow-checked multiply; an age too large for milliseconds keeps everything. - CmuxNextTerminal assume_isolated (6780396): the surface view pushes the shell's folder to its link filter on each pwd report and surface swap, so Ghostty's callback no longer hops onto the main actor. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: namespace enums become extensions on their owning types (cx-zknal) lint-ios-package-conventions flagged three all-static enums: - CommandRetentionSetting (2d66749) -> CmuxConfigSnapshot.commandRetention* and parseCommandRetention, beside parseTerminalCommandHistory. - AgentPageMoveCover (8698d64, #20017) -> AgentPaneView.hideMovedPage(until:) and revealMovedPage(). - AgentPaneCrashNoticeDebug (4069030, #20062) -> AgentPaneView.debugCrashNoticeTexts and debugPressCrashNoticeReload() (DEBUG only). Callers updated; behavior unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: ClosedHistoryRetention check reads weak services inline (no line growth in CmuxNextApp) (cx-zknal) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: the window record mirror, the reopen wait and the agent-home trash sweep move out of CmuxNextApp (CmuxNextDaemon, CmuxNextAgentPane) so the App target does not grow (cx-gzh.9.3, cx-gzh.9.2) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-next: Show Agent History on the palette and the Window menu (cx-qno.24) Lawrence 2026-10-11 (via the chief): the agent History page (cx-zlnl: every coding agent chat on this device, with select and Bring into Active Sessions) opens from a palette and Window-menu action, agentHistory.show, not from the sidebar's space bar (its dot went in cx-qno.23). The page opens beside the targeted or focused pane, as the dot did. CLI: GUI-only for now (reachable as cmux action run agentHistory.show); a named verb needs the Rust grammar check, follow-up filed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cx-urd.26: cmux-tui artifacts runs check their key's owner once instead of waiting (#20109) * test: a cmux-tui artifacts run checks its key's owner once instead of waiting (cx-urd.26) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: cmux-tui artifacts runs check their key's owner once instead of waiting (cx-urd.26) tree-owner-wait polled a live owner every minute for up to 55 minutes: 21,801 runner minutes on 2026-10-12, and 221 of 765 waits built the key anyway after a chain of failed owners. A run now looks once: a published tree or a live owner means it builds nothing, an owner that ended is taken over by winning the key's claim, and an unpublished key is built by the next push of it or cmux-tui-tree-request.yml. The job's timeout drops from 60 to 5 minutes. Since a feat-cmux-next push no longer waits for a branch run that owns its key, a publishing run on any branch asks for the nightly-next promotion of the feat-cmux-next head that shares its key, from that head's checkout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: a failed owner hands its key on, and a pin push skips a published tree (cx-urd.26) Review of #20109: a run that defers to a live owner must be re-run when that owner ends unpublished, an unreadable owner status or a stale claim must not strand the key, and a cmux-tui-pin-* push of a tree whose macOS and Windows daemons are published builds nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: hand a failed owner's key to a deferred run, skip duplicate pin builds (cx-urd.26) A run that defers to its key's live owner leaves a one-day cmux-tui-tree-deferred-<key> artifact. An owner that ends without publishing re-runs one deferring run (a feat-cmux-next push first), which wins the claim and builds; each marker is used once. The claim now decides whenever the tree is unpublished, so an unreadable owner status or a claim that still names the ended owner no longer leaves the key unbuilt. The owner check's timeout is 10 minutes. A publishing run on another branch asks nightly-next to promote the newest of the last 40 feat-cmux-next commits with its key, not only the head. A cmux-tui-pin-* push whose tree is published with its Windows daemon builds nothing (222 pin builds, 25,215 minutes on 2026-10-12). A pin with a missing Windows daemon, and any dispatch, still builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: a pin push of a new commit with a published tree still publishes its binaries (cx-urd.26) test_pin_push_keeps_commit_artifacts_enabled went red on c1402b0: a pin push also publishes its commit's binaries for cmux-tui.pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: a pin push skips only when its commit's binaries are published too (cx-urd.26) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: a live owner is not claimed past, and a failed re-run keeps its marker (cx-urd.26) Second review of #20109. Red on 29319a5: 4 checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: hand off after the owner's last job, never claim past a live owner (cx-urd.26) notify-unpublished-tree now needs the macOS cross jobs, so the run it re-runs finds the owner ended. A live owner means defer without asking the claim, which could grant a second builder beside an owner the run-list fallback elected. A claim that still names an ended owner is asked again once before taking over, and a marker is deleted only after its run was re-run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run the cmux-tui owner and pin guards in the group that runs for this workflow (cx-urd.26) The release-tooling group did not run for a cmux-tui-artifacts.yml change, so both steps were skipped on #20109. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: shorter docs for the closed-window paths (CmuxNextApp size cap) (cx-gzh.9.3) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * CmuxNext: plain text fields draw the theme's placeholder, text and caret (theme sweep 3, batch G) (#20108) * test: plain SwiftUI fields and first-frame fallbacks draw the theme Theme sweep 3, batch G, failing first: the new-task field, the app store search, the feed inbox filter, the feed reply field and an app scene's text field show their placeholder in macOS's gray and their text in the appearance's ink under a purple room. The cookie card's link starts as secondaryLabelColor and an unreadable session color is systemGray. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: plain SwiftUI fields draw the theme's text, caret and placeholder The new-task field, the app store search, the feed inbox filter, the feed reply field and app scene text fields were stock SwiftUI .plain fields: macOS's gray placeholder and the appearance's text and caret in every theme. They are now ThemedField without its box (boxed: false), which keeps the caller's own row, capsule or fill. ThemedField gains an isFocused binding (New Task focus, Escape lets go) and onCancel (Escape). The cookie card's link and an unreadable session color start in the app theme's tertiary ink instead of secondaryLabelColor and systemGray. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: a page's first-frame separator follows the border switch History's and Bookmarks' colors start with the theme's separator even under appearance.borders none, where Palette.separator is clear. Also drops the badge's always-true NSVisualEffectView check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: History and Bookmarks first-frame separator follows the border switch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: a themed field with text keeps its placeholder as its label The stock SwiftUI field exposed its title as the accessibility label; ThemedField only draws a themed placeholder, so once text is typed VoiceOver has no name for the field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: a themed field's placeholder is its accessibility label Kept in sync when the placeholder changes, so VoiceOver names the field after text is typed, as the stock SwiftUI field's title did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Name an older Cloud machine before Move to Cloud or Bring Back Local (#20110) * cx-rppd.13: red tests for naming an older Cloud machine before a move A Linux journey (machine_update_journey.rs) stands one cmux-tui binary in for an older Cloud machine daemon through two debug-only seams (another build id, newer capabilities left out of identify) and expects the link CLIs that Move to Cloud, Bring Back Local and local access run to answer machine_outdated before anything moves, with the chat still live on the Mac. A same-build machine without a verb keeps its own refusal. The Swift suites expect the app to name an older machine in plain words (new catalog strings in every locale) and keep the chat where it was, with Retry on that machine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cx-rppd.13: name an older Cloud machine before a move instead of failing The link CLIs ask the machine daemon's identify first. A daemon of another build that lacks the capability the verb needs (fs-v1 for sync and folder grants, agent-transfer-v1 on either side of a move, access-request-v1 for file request triage and answers) answers machine_outdated before anything is copied or the chat freezes. A same-build daemon, or one whose identify does not answer, keeps the verb's own refusal: the gate only names a cause and never decides access. The app maps machine_outdated to "<machine> runs an older cmux that can't take this chat. Update the machine, then Retry." on Move to Cloud and the matching Bring Back Local text, with Retry pinned to that machine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cx-rppd.13: word the older-machine toasts for an update, not a retry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cx-rppd.13: test that a revoke and this Mac's own daemon are never the machine's fault A revoke on an older machine must still end the grants on this Mac, and a chat move whose source daemon is the outdated one must say which side it is, so the app never asks to update the machine for this Mac's own daemon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cx-rppd.13: never gate a revoke, name the outdated side and bound identify `link access revoke` is no longer gated: it always ends the grants on this Mac, as before the gate. `link agent move` answers which daemon is outdated (`side`), and the app names the machine only when it is the machine. The gate's `identify` now has one 5 second budget for the whole answer, however a daemon trickles it. The French and Chinese strings use the catalog's usual word for a chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cx-rppd.13: word an outdated move side without blaming the machine When the outdated daemon of a chat move is this Mac's own, the CLI's error no longer says "update the machine": it names the side and the build, and the app shows it as a plain move failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * test(next): name why a PinnedPage pin never lands (#20123) The pin wait's timeout now says whether Pin Tab refused, started no daemon work, or the daemon failed it. The fleet report so far shows the store tab still unpinned with a pane controller present. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: release terminals when their workspace closes (#20124) * bench: pick the launched app's socket by identify pid; end the app before its daemons lsof reports the app's bind path, not the socket name it is reached by, so launch mode never found a socket. A live app respawns daemons ended before it, which left two behind after a failed launch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * bench: end the run through its cleanup on SIGTERM Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * bench: --config passes cmux.json settings to a launched app Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * bench: --mix none churns bare workspaces Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: a closed workspace's terminal and preview go (cx-x15rz) Red: closing a workspace only hides its terminals; the surface stays in the warm set and the preview in the cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: release terminals whose workspace closed (cx-x15rz) A terminal goes once its daemon tree, connected and loaded, has listed its tab and no longer does, as agent pages already do. Before, a closed workspace's terminals stayed in the warm set until the LRU took them and their previews stayed in the 32 MB preview cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * bench: --fake-agent runs the chats on an ACP test agent whose turns end Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * bench: clean up the launched app when the fake agent can't be added Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Agent: New Agent Chat and Add Harness from Home open a new workspace (cx-bun) (#20118) * test: New Agent Chat and Add Harness from Home open a new workspace (cx-bun) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Agent: New Agent Chat and Add Harness from Home open a new workspace with the chat (cx-bun) Over a top page the window's workspace is parked and its panes never mount, so withAgentPane waited 10 s and refused. It now opens a workspace whose only tab is the chat (the Harnesses page for Add Harness), as Cmd-I does from a workspace. withAgentPane moves to AgentHandlers+Pane.swift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Agent: refuse at once over a top page when no chat can open; fix the missing import; Home shown as the app shows it in the test (cx-bun) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: storm bench runs again; three main-thread lookups stop stalling under a CLI storm (cx-6so.21) (#20130) * cmux-next: storm bench finds its stream pane from the split's reply (cx-6so.21) An automation split-right no longer moves focus, so the bench waited for a focused stream pane that never came and exited before any storm. It now takes the split's created tab, and focuses left only when focus moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: a daemon capability check is one native-string set lookup (cx-6so.21) ThemeCoordinator asks supports() per tab per snapshot and DaemonCompatibility asks it per known capability; each scanned the decoded capability strings, which held the main thread in CoreFoundation and allocator locks during a CLI storm (2.3k of 6.6k lock samples on main). Keep a Set of native strings built when the capabilities are set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: isChat reads the tab it is given (cx-6so.21) isAgentTab(tab.id) found the same tab again by walking every workspace, once per tab whenever a pane's tab bar kind was computed: quadratic in tabs during a CLI storm (618 main-thread lock samples under locateTab). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: focus topology looks tabs up by id once per pane (cx-6so.21) focusPane and tabsInLayoutOrder searched the pane's tabs linearly for each strip tab, an observation-tracked read per step: quadratic in a pane's tabs, the top main-thread lock site left in the CLI storm profile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux NEXT: a pane's top-right is one hover "…" in place of its buttons (#20119) * test(cmux-next): a pane's top-right is one hover "…" that opens tabs, no split buttons (Leo 10-12) Red: today the corner shows Split Right, Split Down and the tab's actions as buttons, "…" holds only the overflow, and a zoomed pane lights a zoom button. The seams (PaneToolbar init with newTabMenu, the view's HoverReveal) keep the old behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): splits stay in the pane's "…" menu (Leo's correction) Dropping Split Right/Down was meant for the composer's ellipsis, not the pane. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): a pane's top-right is one hover "…" in place of its buttons (Leo 10-12) The row of buttons (Split Right, Split Down, the tab's actions) goes away. One "…" fades in while the pointer is over the pane's top-right corner (the shared HoverReveal, like the strip's plus) and while its menu is open; a zoomed pane keeps it shown and lit. Its menu is the strip plus's (a terminal, a browser, an agent chat in this pane), then Split Right, Split Down, the tab's own actions and Toggle Pane Zoom. Hide/Show button menus go with the buttons; an action in tabs.hiddenButtons is left out of the menu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): pane corner "…" review fixes - The hover reaches 96 pt left of "…" over the tab bar (the pane's corner), not only "…"'s own cell; the corner's tracking area lives on the pane. - The tint follows theme changes (set in layout and appearance hooks). - tabs.hiddenButtons no longer filters "…": it hid buttons from the old row, which put them under "…", so everything stays reachable. - "…" builds the plus's rows without its Chromium warmup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): the corner reveals "…" for any enter/exit it owns A synthetic enter (debug.pointer_hover) carries no tracking area, so the area check dropped it; the view owns no other area. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: bookmark icon doc avoids an HTML tag in rustdoc (#20129) The bookmark-icon-v1 description's image:sha256-<hex> became an unclosed <hex> HTML tag in the generated Rust SDK docs, which fails `rust package` (rustdoc -D warnings) on every PR since #20083. The placeholder is {hex}; the SDK layers are regenerated. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: Claude's model choices come from the bundled catalog (cx-miuo) (#20091) * test: a Claude Code session offers every catalog Claude model (cx-miuo) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: Claude's model choices come from the bundled catalog (cx-miuo) claude_stdio's hand list (no Opus 5.5 or Sonnet 5.5) fed the session's configOptions model select, the pane's stand-in list before Claude Code's own probe answers, and model-id hints. Claude Code's aliases stay static (only Claude Code says what they run); every concrete release now comes from catalog/models-v1.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: keep the catalog model-choices test with the catalog RPC tests (god-file budget) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: safe-push <safe-push@cmux.local>
Nothing has read it since the hover "…" replaced the pane's buttons (#20119). An old file loads without a diagnostic and settings.set says it was removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on (#20144) * test(settings): tabs.hiddenButtons is a retired key; an old list loads without a diagnostic Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * settings: retire tabs.hiddenButtons; the pane's "…" lists every action Nothing has read it since the hover "…" replaced the pane's buttons (#20119). An old file loads without a diagnostic and settings.set says it was removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(pane toolbar): the New Tab page's "…" leaves the splits out (#20128) #20128 dropped Split Right/Down from a New Tab page pane's "…" and left this expectation red on base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * settings: regenerate the exports without tabs.hiddenButtons Fleet export-settings-artifacts.sh at 324afbe, then strings:settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * settings: regenerate the exports on the merged head Fleet export-settings-artifacts.sh at 0635e3f, then strings:settings. Also drops base's stale tabs.newTabKind rows (retired in Swift by #20127). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(pane toolbar): follow base again; #20143 kept the splits in the New Tab page's "…" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

Summary
Leo, 10-12: the pane's top-right buttons go away. Hovering the corner shows one "…", whose menu opens a browser, terminal, agent chat and so on.
HoverRevealthat the strip's "+" uses, and stays up while its menu is open.tabs.hiddenButtonsno longer applies: hiding a button used to move it into "…", and every action is in "…" now. A follow-up PR removes the setting and its generated docs.Visible change: panes show no buttons at the top right until you hover the corner, then one "…".
Verification
Tests:
PaneToolbarTests. All runs are fleetrun-swift-testing-suites.sh --arg Packages/macOS/CmuxNext(Xcode 26.6).newTabMenu, andreveal) that keep the old behavior. All 5 tests failed on assertions. For example:bar.controls → ["More", "Split Right", "Split Down", "Open Diff Viewer", "Open File"],bar.more → ["Toggle Pane Zoom"], andreveal.isRevealed → falsefor a zoomed pane.hidden:dropped from the calls), so the red is re-recorded on a scratch commit (the final tests on the old code) and green on the head. Both receipts are in a comment.Changelog
Changed: A pane's top-right shows one "…" on hover, instead of a row of buttons. Its menu opens a new terminal, browser or agent chat in the pane, splits it, and runs the tab's actions.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Replaces the pane's top-right row of buttons with a single "…" that fades in as the pointer crosses the pane's top-right corner.
HoverRevealas the strip's "+".tabs.hiddenButtonsno longer applies; a follow-up removes the setting and its generated docs.debug.pointer_hoverthat carry no tracking area.Written for commit 8ef8b91. Summary will update on new commits.