Repository navigation
webviews: fix chat-header-changes test after tooltip shortcut hints - #19805
Conversation
…p hint #19770 moved header shortcuts from the title into data-tooltip-shortcut; the Changes test still expected "Changes (⌃⇧⌘G)" in the title. 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. |
|
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 |
|
Unclear: CI failed on
Not re-run automatically: Written by |
* test(cmux-next): New Tab omnibar suggests reddit.com in a popover
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cmux-next): New Tab suggestions are an omnibar popover
Typing in the New Tab field showed its rows inline, pushing the page down,
and "reddit" showed nothing. The rows now float in a popover anchored under
the composer on a solid theme surface. They complete addresses from visited
pages and top sites, match open tabs and workspaces, and end with "Search the
web for …" and "Ask <agent>". The top row is highlighted and taken by
Return. Blank browser tabs ("about:blank workspace-N") are never offered.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cmux-next): keep blank tabs movable; complete addresses from 3 letters
The blank-page filter ran on the host context, which also feeds a split
page's Open Tabs list, so a fresh browser tab could not be moved into the
pane. Filter only the popover's rows. Two-letter words ("go", "no") stay
prompts instead of completing to google.com or notion.so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* cmux-next: Opacity in Ghostty mode repaints live and leaves Material Ghostty (#19758)
* test: Opacity in Ghostty mode repaints live and leaves Ghostty
Red: with Material "Ghostty" (unset), moving Settings > Window Background >
Opacity through the page's preview does not repaint the window, and a write
leaves Material on Ghostty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: Opacity leaves Material Ghostty and repaints the window live
With Material "Ghostty" (unset), the Opacity slider's preview never reached
the window: TerminalThemeSetting followed only the loaded settings for the
window background. It now follows the applied (previewed) background, so every
slider step repaints the window.
Writing Opacity while Material is unset now also names the material Ghostty's
background-blur gives (none, frosted, glass or clear glass), and removing either
key removes the other, back to Ghostty. The rule lives in
WindowBackgroundSetting.linkedEdits and runs in SettingsController.setSetting
and preview, so the page, the palette and the socket's settings.set agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: add the Ghostty blur hook to SettingsController
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Opacity reset keeps a chosen Material; slider reloads coalesce
Red: resetting Opacity drops a Material the user chose, the flip reads the
window's resolved blur rather than Ghostty's own, and every slider step
reloads the Ghostty config. GhosttyRuntime now records the config files' raw
background-opacity and background-blur (configBackgroundOpacity/Blur), which
nothing reads yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: Opacity reset keeps a chosen Material; coalesce slider reloads
Resetting Opacity now removes Material only when it is the one the flip
wrote (the material the config files' own background-blur gives); a material
the user chose stays. The flip and this check read Ghostty's raw blur, which
GhosttyConfigBackground records on every load of the user's config, instead
of the window's resolved blur.
A window background step that keeps the window translucent (or opaque) and
its material repaints the chrome from the theme at once
(ThemeBridge.repaintBackground) and reloads the Ghostty config 60 ms after
the last step (DemandTimer). Crossing opaque/translucent or changing the
material reloads at once, so the terminals follow.
The raw values move from GhosttyRuntime statics to GhosttyConfigBackground
(GhosttyRuntime's type was over the god-type budget), so the tests set that.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: build the app services before the stand-in Ghostty values
AppServices may load the machine's Ghostty config, which records its own raw
background values over the test's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Agent pane: Show more lines in the changes view (cx-ncc.85, 3/3) (#19780)
* test: Show more lines reads a git scope's file whole and expands between hunks (cx-ncc.85, red)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Agent pane: Show more lines in the changes view's git scopes (cx-ncc.85)
A git scope's file is read again as it comes into view, with every unchanged line
(git.diff paths + context_lines). With both versions known, Pierre's hunk separators
expand. A read whose changes differ from the shown diff (the file changed since) is not
used, nor is one for a rename.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Show more lines ignores a read that does not start at the first line (cx-ncc.85, red)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Agent pane: Show more lines uses only a read from the file's first line (cx-ncc.85)
Review fix: a host that ignores or caps context_lines answers with the hunk's own context;
rebuilt from that, the file was too short and Pierre indexed past it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* cmux-next: a terminal whose shell the daemon cannot reach says so, not a silent cursor (#19773)
* test: a terminal whose host link the daemon gave up on is never a silent cursor
The daemon pushes no tab change when a terminal's host link is lost,
given up or back, and the app ignores terminal_state, so such a terminal
keeps a connected view with no label: the last screen, often a lone
block cursor, and keys that go nowhere. Red until the fix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: a terminal whose shell the daemon cannot reach says so
The daemon now pushes a terminal's tabs when its host link is lost,
given up or back, and the app labels a live terminal whose shell it
cannot reach (reconnecting, link lost, owned by another build) instead
of leaving a silent last screen. It re-attaches once the shell is
reachable again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: push a resync reconnect's loss; the organization banner wins
Review follow-ups: a reconnect started by a resync that then fails moves
the terminal to reconnecting, which clients now hear about at once, and
a link an administrator turned off keeps its own label over a stall.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cmux-next): keep shortcut search keyboard parity (#19778)
* cmux-tui: a registry: tab's landed check builds on Windows (no bead) (#19775)
#19725 calls Mux::landed_agent_session from conversation_tabs_wire,
which builds everywhere, but agent_transfer (where it lives) is
#[cfg(unix)], so feat-cmux-next's cargo check (x86_64-pc-windows-gnu)
fails with E0599. Off unix no chat lands through agent-transfer, so the
check is false there.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Agent pane: hideable chrome; Hide from the control, Show from its row (cx-wab7m) (#19783)
* test: right-click hides the mic, right-click its row shows it, across a relaunch (cx-wab7m, red)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Agent pane: hideable chrome; right-click a composer control to Hide it, its row to Show it (cx-wab7m)
ui/HideableChrome: a piece of optional chrome (id, Hide/Show labels, icon, persisted
shown/setShown) hides from its own right-click and comes back from its area's right-click.
ContextMenu items take an icon, and a menu inside another wins the right-click.
The composer's dictation mic and context ring use it in the agent composer and the New Tab
page: Hide Dictation Button / Hide Context Usage on the control, Show ... on the button row.
The choice stays the agentPane.showDictation / showContextUsage setting, written by the host.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: a popup's right-click keeps its own menu; New Tab offers Show only for what it draws (cx-wab7m, red)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Agent pane: the button row's Show keeps out of popups and offers only what it draws (cx-wab7m)
ContextMenu targets="own" opens only for right-clicks on the host's own DOM, so the
project chooser's search field (a popup React events pass up from) keeps its own menu.
The New Tab row offers Show for the mic only; that page draws no context ring.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Chrome tab keys move between sidebar items from every focus (Leo 2026-10-12) (#19788)
* test(next): Chrome tab keys select sidebar items from any focus (Leo 2026-10-12)
Every Chrome-standard tab key (Ctrl-Tab, Cmd-Shift-] / [, Cmd-Opt-arrows,
Ctrl-PageDown / Up, Cmd-1…9) from a terminal, the New Tab field and an
agent composer, in one-tab and two-tab panes, compared with the sidebar
action from the same start. Leo's two Karabiner paths also go in
transition by transition with their timing through the new DEBUG
`debug.key` `sequence`, which posts CGEvent-built key events to the app's
event queue.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(next): debug.key sequence schedules its steps with DemandTimer
check-concurrency bans asyncAfter; each step's timer posts its queued event.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(next): Chrome tab keys select sidebar items from every focus (Leo 2026-10-12)
Leo's Karabiner sends Cmd-Shift-] / [ and Ctrl-Tab, as Chrome, ChatGPT and
Claude use them. Here they ran Previous / Next, which steps the focused
pane's tabs when it has two or more, and in a terminal Ctrl-Tab and
Ctrl-PageDown / Up went to Ghostty's next_tab (the pane's tabs). Cmd-Opt
arrows focused panes.
Now Ctrl-Tab / Ctrl-Shift-Tab, Cmd-Shift-] / [, Cmd-Opt-Right / Left,
Ctrl-PageDown / Up (and Ctrl-Cmd-] / [) select the next / previous sidebar
item, and Cmd-1…8 / Cmd-9 the nth / last item. These Chrome tab keys sit
after the Ghostty config's keybinds and claims in the binding table, so a
terminal, a Ghostty keybind (super+[ included), a page and the agent
composer never take them; only cmux.json entries change them.
- Next / Previous Sidebar Item show Cmd-Shift-] / [ as their keys.
- Next / Previous Tab or Workspace keep no default key (palette only).
- Focus Pane Left / Right move to Ctrl-Cmd-H / L.
- Home's Cmd-Shift-[ / ] conversation keys go: Home is a sidebar item.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): regenerate action exports for the Chrome tab keys
scripts/measure/export-action-surfaces.sh on the fleet at the fix commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(next): chrome-tab-keys e2e reads older builds' sidebar selection and focus
Builds before the selection and focus readouts (Leo's DEV d0364e0) mark the
selected row and name no focus; the script falls back to those.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): regenerate action exports after the base merge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* New Tab: a calm default with a real Send button; no caret restart; no ring around open menus (#19749)
* test: the New Tab field keeps its caret across updates and a click into it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: the New Tab field takes the keyboard once, not on every update
The page's focus effect depended on the input-ready callback, which the
App makes anew on each render, so every update and a click into the
focused field focused and selected it again: the caret blink restarted
and the text under the caret was selected. It runs once per input token
now (and on Cmd-L).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: the default New Tab is the composer and five recent chats, with a real send button
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: an open menu draws no focus ring around itself
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: a calm default New Tab with a real Send button, and no focus ring around open menus
The default New Tab is the composer and the five newest chats as quiet rows, with All Chats for
the rest; the action row, Recently Closed and the All chats table leave the default (the other
templates keep theirs). Send is the composer's arrow-up disc, off while the field is empty.
An open menu, list or popover takes focus so its keys work; the global keyboard rings no longer
draw a square around it, and the focus-ring lint refuses a universal ring that would. Monaco's
find fields draw no ring of their own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: lists that take Tab focus keep their ring; only open menus and popovers drop it
Review: the Cloud machine list and the History list are themselves the focus target, so leaving
[role=listbox] out of the ring hid their keyboard focus. Drops the classic page's unused tools
and onRunAction props.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: the New Tab's recent chats are one-line rows
The list variant set height 30px, but the card's 84px min-height won, so every row drew three
lines tall (fleet capture of the calm default; Threads and Console had it too). The calm-default
gallery play now refuses a row taller than one line: 84px before, 30px after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: the New Tab page has no tools row, so no Integrate a harness button in it
The base's #19755 test rendered the tools row the calm default removes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* cx-ncc.85: pass git diff paths and context_lines through the App (#19730)
* test: the pane's git diff reads pass paths and context_lines to the session host (cx-ncc.85, red)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: the pane's git diff reads pass paths and context_lines to the session host (cx-ncc.85)
Show more lines asks for one file's patch with enough unchanged lines to hold
the whole file. The App decodes paths (relative, inside the repository) and
context_lines (0 to 1,000,000) and refuses anything else rather than dropping
it, which would be another read.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: import the pane module testably for its request decoder (cx-ncc.85)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Recently Closed: leave out untouched New Tab pages and about:blank rows (#19774)
* test: closed.list marks a tab that reopens as nothing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: closed.list marks a tab that reopens as nothing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Recently Closed leaves out New Tab pages and names the rest
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: leave New Tab pages out of Recently Closed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: History and untitled chats keep about:blank out of Recently Closed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: keep about:blank and New Tab pages out of History and Tab Search
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: closed chat fixtures carry no folder, as the daemon records them
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: name the closed-tabs helper's lifetime
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): PR autofix at 5b12bae
- regenerated cmux-tui/crates/cmux-app-host/generated/cmux-app.d.ts
Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38219624487
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
* cmux-next menus: highlight rows in the theme accent (#19784)
* test: themed menu rows draw the theme accent and run once
The workspace, tab and pane menus (#19754) highlight rows in the
system accent. Adds the failing behavior test for cmux-drawn rows: a
highlighted row draws the theme accent in a non-default theme scope,
and Return or a click runs the item's action exactly once. The API it
calls is a no-op stub here; the Palette accentFill/onAccent tokens it
reads are real.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* cmux-next: workspace, tab and pane menus highlight in the theme accent
NSMenu draws its highlight in the system accent whatever the theme.
NSMenu.themeRows(in:) swaps a menu's rows (and its submenus') for
ThemedMenuRowView, which draws the highlight in Palette.accentFill with
Palette.onAccent ink, in the scope of the view that was right-clicked.
Items keep titles, key equivalents, states and submenus; their action
goes through ThemedMenuDispatch, which validates via the original
target and runs once per opening whether it arrives from AppKit's
Return, a click on the row, or Return delivered to the row.
Applied to the three menus #19754 trimmed: the sidebar workspace and
tab menus and the strip's tab and pane menus.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Return on a themed submenu row reaches AppKit
Review of #19784 (cx-3pcgz): the row took Return whenever it was
highlighted, so Return on More or Move to Group was swallowed instead
of opening the submenu.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* cmux-next: themed menu rows run after tracking and redraw on arrows
Review of #19784 (cx-3pcgz):
- A click or Return on a row closes the menu and runs the action once
the tracking loop has ended (RunLoop default mode), as a native row
does. The selector form of RunLoop.perform keeps it Swift 6.0 safe.
- Each themed menu gets a delegate relay that redraws the rows losing
and taking the highlight on menu(_:willHighlight:) and forwards to
the menu's previous delegate (a choices submenu's coordinator).
- The row takes Return only for an enabled item with an action and no
submenu; otherwise AppKit gets it.
- The row view is no accessibility element, so VoiceOver uses the
native menu item.
- A release with no press on the row also runs it once the pointer has
moved since the menu opened (right-drag-release).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* cmux-next: iconic public-domain paintings as backdrop art (cx-t2x.7) (#19776)
* test: backdrop art is iconic paintings in four collections (cx-t2x.7)
The picker groups bundled art into Dark Art, Museum Icons, Calm and Doré,
labels each "Title — Artist", ships every image at 1600x1000, and keeps
every id an earlier cmux.json saved choosing art. Fails on the current
set: two collections, title-only labels, mixed image sizes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: thumbnails for every work, a bundled dark starter set, verified downloads (cx-t2x.7)
Leo's list grew to about 170 works, so the full images no longer all fit
the app-size budget: every work ships a 480 px thumbnail, a starter set of
dark works ships its full 1600x1000 image, and the rest download once into
the backgrounds folder, kept only when the bytes match the manifest hash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: iconic public-domain paintings as backdrop art (cx-t2x.7)
Replaces the figure-drawing sketches and Met paintings with 169 well-known
public-domain works from Leo's list (cmuxterm-hq#1906): Goya, Doré,
Friedrich, Van Gogh, Bosch, Klimt, Munch and more, in four picker
collections (Dark Art, Museum Icons, Calm, Doré), labelled "Title — Artist".
- art/manifest.json is the source of truth: Commons source and license,
copyright dates, framing, tone, measured range and SHA-256 per work.
Gate: artist dead 70+ years and first published before 1931.
- Every image is 1600x1000 AVIF framed for a terminal backdrop (subject to
one side, dark side for text) at <=150 KB. The app ships 480 px
thumbnails of all works plus a 16-work dark starter set (~2 MB, down
from 4.4 MB); the rest download once from files.cmux.com by hash
(cmux-art-publish.yml) and are kept only when the bytes match.
- Each work sets its own default tint, and the legibility floor uses its
measured darkest and lightest colors instead of assuming black-to-white.
- Ids saved by earlier builds map to a stand-in work.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: starter-set test reads metadata on the main actor; format the gallery fixture (cx-t2x.7)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: regenerate settings schema and MDM exports for the new art set (cx-t2x.7)
Generated by scripts/measure/export-settings-artifacts.sh on the fleet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: keep non-art backdrop strings, all locales and true brightness extremes (cx-t2x.7)
Red on the current generator: it deletes backdrop.desktop/system strings,
writes art strings in 9 of the catalog's 21 locales, and measures the
brightest pixel from a 160x100 downscale, which loses a small moon.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: keep wallpaper strings, ship art strings in all 21 locales, measure true brightness extremes (cx-t2x.7)
- The generator no longer deletes backdrop.desktop/system strings; restored
them from base with their 21 translations.
- Art titles, collections, label and "Public domain" now carry every locale
the catalog does (bs, da, it, km, nb, pl, pt-BR, ru, th, tr, uk, vi added).
- darkest/lightest are the full-size extremes, so the legibility floor holds
over moons and flames a 160x100 downscale averaged away.
- Merged the stacked JSDoc on the settings backdrops type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: regenerate settings page strings after the base merge (cx-t2x.7)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: regenerate settings schema and MDM exports after the base merge (cx-t2x.7)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: regenerate settings page strings from the refreshed schema (cx-t2x.7)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* CmuxNext: the chat header's Terminal honors split-inherit-working-directory (cx-zld.1) (#19799)
* test: the header's Terminal inherits the chat's folder only when splits inherit (cx-zld.1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CmuxNext: the header's Terminal honors split-inherit-working-directory (cx-zld.1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: a chat of another machine keeps its folder for the header's Terminal (cx-zld.1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CmuxNext: a chat of another machine keeps its folder for the header's Terminal (cx-zld.1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CmuxNext: keep AgentTabStore's length while wiring the header's local check (cx-zld.1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* webviews: New Worktree shows the host's folder question instead of ending silently (cx-lyqio.7) (#19800)
* test: New Worktree hands back the host's folder question (cx-lyqio.7)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: type New Worktree's folder question, no behavior yet (cx-lyqio.7)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* webviews: New Worktree shows the host's folder question instead of ending silently (cx-lyqio.7)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* cmux-next: rapid workspace create/close runs in press order (cx-7cit9) (#19757)
* test(next): rapid workspace create/close stress e2e (cx-7cit9)
30 Cmd-N at key-repeat speed with interleaved Cmd-Shift-W, some landing
on a workspace still being created; then the sidebar must match the
daemon, the new names must be consecutive, New Tab must suggest only
live tabs and workspaces, and no refusal HUD or toast may appear.
DEBUG readouts for it: debug.toast reports the refusal HUD's history and
debug.new_tab state the New Tab page's suggestions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(next): rapid workspace e2e skips workspaces the sidebar never shows (cx-7cit9)
Home is in the daemon's list-workspaces but has no sidebar row; the
count and order checks compare only the workspaces shown at the start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(next): queue workspace creates and closes per window (cx-7cit9)
Cmd-N at key-repeat speed started every create at once, so the daemon
numbered workspaces in arrival order with gaps, and a Cmd-Shift-W pressed
before a new workspace was mirrored closed the one the window still
showed. Each window's creates and closes now run one at a time, in the
order they were pressed (WorkspaceLanes). The workspace key is fixed at
the press, so a close pressed while a create waits or is in flight takes
exactly that workspace: one not started never runs, one in flight closes
once the daemon made it.
The create body moves from WindowManager to WorkspaceSpawner (the god-type
budget). Not-found refusals are quiet for keyboard and menu runs, so a
gone target is a no-op instead of a "no workspace <uuid>" notice; the
socket still answers not_found. The New Tab omnibar lists only terminal
and browser tabs, not every New Tab page as "about:blank".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(next): rapid workspace e2e checks press order under any placement (cx-7cit9)
New workspaces go to the top by default, so the sidebar is not in the
daemon's order; the new rows must instead be in press order. Home stays a
live workspace for the New Tab check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(next): capture the spawn command, not the shadowed spawn (cx-7cit9)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: 20 Cmd-N with closes in between keep every workspace in press order (cx-7cit9)
Real daemon and launch window: 20 named presses inside a second with
Close Workspace pressed after presses 5, 6, 12 and 18. Every workspace
not closed must be in the window's sidebar in press order, each close
must take exactly one, and no press may fail or show a notice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci: publish art thumbnails and a public manifest to files.cmux.com (cx-t2x.8) (#19802)
* ci: publish art thumbnails and a public manifest to files.cmux.com (cx-t2x.8)
cmux.com/art and the in-app Browse page read the collection from
cmux-art/manifest.json: art/manifest.json plus each work's image and
thumbnail URL. Thumbnails upload write-once by their own SHA-256.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: check ids before reading thumbnails; verify a served thumbnail (cx-t2x.8)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* test: keys typed right after Cmd-N all land in the New Tab field (cx-kql5h) (#19797)
Real Chromium, both New Tab screens rendered the way the agent pane renders
them: a host update hands the screen new callbacks. Types "hello world 123"
a key at a time with a page render before each, as the bead's keys came.
Red on #19749's parent (both screens keep only "3"), green on base.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* cmux link sync pull: bring a Cloud folder back by a three-way merge (cx-rppd.4) (#19722)
* test: bring a VM's edits, commit and chat back to the Mac
Two boundary tests of cmux link sync pull against the fake fs-v1 socket
link_sync.rs already uses: an edit, a delete, a new file and a commit
made on the machine come back (the branch fast-forwards, git status
matches the machine's) while its hooks, config, ignored output and new
.env files stay there; and a file changed on both sides is a conflict
that changes nothing here, as is a branch both sides moved.
A Linux journey, the reverse of cloud_move_journey.rs, with real
processes: a Cloud-VM-shaped daemon whose chat runs in ~/work/app with
history, a running turn and a queued prompt, and a local daemon. An
edit and a commit made on the VM come back with link sync pull, then
link agent move takes the chat back under the Mac's web guard, where
its queued prompt runs once. A chat that approves everything is refused
with transfer.policy and stays open on the VM. The journeys share their
machine helpers in tests/journey_support.
cmux link sync pull does not exist yet, so these fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* cmux link sync pull: bring a pushed folder back by a three-way merge
cmux link sync pull --socket LINK_SOCKET LOCAL REMOTE merges what a
push left on a Cloud machine back into the local folder, against the
push manifest as the base. Per file: the machine's still as pushed keeps
the local one, the local still as pushed takes the machine's (written,
or deleted), both changed alike settles, both changed differently is a
conflict. New machine files come back unless the working copy ignores
them, they are untracked .env files, or they are not regular files.
Any conflict changes nothing and answers
{"ok":false,"error_code":"sync_conflict","conflicts":[paths]}. Otherwise
the machine's files are first staged in a folder of the pull, the local
files are checked again, and each moves into place by rename, through no
symlink, with 0644, 0755, 0600 or 0700 permissions.
The git leg takes the same three-way rule for HEAD and for what is
staged. The push now records the branch, HEAD and a digest of
git ls-files --stage in its manifest. When the local branch is still at
the pushed commit, it fast-forwards to the machine's; a switched branch,
a rewritten history or both sides moving is a conflict. The machine's
objects (loose objects and pack data, never its pack indexes) go into a
quarantine repository whose object store borrows the local one; git
fetches only what the new commit and staged tree need from it with
transfer.fsckObjects, and the branch moves by update-ref compare and
swap. The machine's hooks, config, info and refs files never come back.
The manifest then records the merged state, so a second pull finds
nothing new. Unix only, like the rest of the link module.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: make the machine's hooks folder before writing a hook there
The push sends no .git/hooks folder, so the pull test made none to
write its machine hook into and stopped before the pull ran.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* cmux link sync pull: clippy fixes; journeys bind install-host tabs (cx-k21v)
A registry: tab of a store takes its session only from
agent-session-start since cx-k21v, so the journeys' stand-in for a
client's chat tab records an install host.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: the bring back journey starts its approve-all chat under an approving profile
Only the person's app may switch a chat to approve-all (cx-1l61), so the
journey starts that chat under a fake-approve harness profile instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: a malicious machine can't plant a hook, climb out, half-apply or lie about the base
The fake fs-v1 machine can now plant hostile listing entries. A pull must
not bring back .GIT, git~1 or a nested repository, must refuse listed
names that climb (x/../.git/hooks/..., ../escaped.txt), must leave the
files, branch and index unchanged when it fails partway, and must use the
copy of the push record this Mac kept, refusing a missing or different
one. The names helpers are stubs with today's rules; their unit tests
cover git's HFS and NTFS .git spellings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): PR autofix at f93b4f7
- cargo fmt in cmux-tui
Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38208995763
* test: compare names, not paths, for a repository folder under another spelling
On a Mac's case-insensitive disk .GIT exists wherever .git does, so the
test looks for the planted names in the folder's listing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* cmux link sync pull: treat the machine as hostile
- A listed name must be one plain component, or the listing is refused
(sync_unsafe_name). No path that reads as .git under git's HFS and NTFS
rules (.GIT, git~1, .git., ignorable code points) comes back, nor any
folder below the top holding one (a nested repository).
- The base is this Mac's own copy of the push record, kept in its state
folder by local folder and machine folder; a missing copy is
sync_no_base and a machine record that differs is sync_base_mismatch.
- All or nothing: files are staged and the machine's commits fetched
first; then files move into place through folder handles (openat,
renameat, unlinkat, mkdirat with O_NOFOLLOW), each replaced or deleted
file moved aside, and the branch (compare-and-swap) and index move last
after this Mac's branch and index are checked again. Any failure puts
back the files, and the branch if the index can't follow.
- A file's revision is read before and after its content, which streams
to disk; pack and object files stream with a 4 GiB cap.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): PR autofix at 47ca161
- cargo fmt in cmux-tui
Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38209935609
* cmux link sync pull: fmt and clippy
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: a hostile machine's repository shapes, hooks, fd load, races and endless answers
Red first for the re-review of the pull: a planted bare-repository shape
(HEAD, objects, refs, config), the working copy's hooksPath folder, 300
new folders under ulimit -n 128, a file edited after the plan, and answer
lines, ids and listings that never end.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): PR autofix at 98b2197
- cargo fmt in cmux-tui
Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38215666535
* fix: a pull never brings back a planted repository, hook folder or endless answer
- A folder that is a repository on either side (a .git, HEAD or
commondir) is fenced off: nothing in it comes back or is deleted. A top
with a repository's shape keeps out its repository names.
- The folder core.hooksPath names (and .husky above .husky/_) is fenced.
- The transaction keeps folders by path, so it holds no handle per file.
- A file is moved aside, then checked against the plan; one edited after
the plan goes back and the pull answers sync_conflict. Files are placed
and put back with a hard link, never over a file made meanwhile.
- Roll back reports what it could not put back and keeps the staging
folder (also on panic).
- Answer lines, answers for other requests and listing pages are capped.
- The staged tree is rebuilt from the machine's entries in a new index,
not taken from its cached trees. The .cmux-sync filter ignores case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): PR autofix at c40e787
- cargo fmt in cmux-tui
Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38216347988
* test: the hooks fence ignores case, and the git leg refuses hooks and repositories
Red first for the second re-review: core.hooksPath spelled .GitHooks,
and a machine commit or staged change that adds a hook or a bare
repository's shape.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: case-blind hook fence, and the git leg refuses hooks and repositories
- The hooks and fenced-folder checks compare names as a Mac's disk does
(case and HFS-ignorable code points ignored).
- A machine commit or staged tree that adds or changes a path in a hooks
folder, a .git under any spelling, or a HEAD or commondir in a
subfolder is a conflict (.git/HEAD or .git/index).
- A repository here in a folder the push sent is fenced even when the
machine no longer lists it.
- Roll back removes a placed file only if it is still the one placed.
- The staging folder has a name of its own and is never reused.
- All listings together are capped at 2,000,000 entries.
- core.hooksPath with ~/ or through a symlinked prefix is resolved.
- ENOTSUP and EOPNOTSUPP are one value on Linux (clippy there).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(next): PR autofix at 19e2f4c
- cargo fmt in cmux-tui
Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38220021551
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
* webviews: chat-header-changes test expects the shortcut as the tooltip hint (#19805)
#19770 moved header shortcuts from the title into data-tooltip-shortcut; the
Changes test still expected "Changes (⌃⇧⌘G)" in the title.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* New Tab: one scroller, soft edges (#19791)
* test: the New Tab field keeps its caret across updates and a click into it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: the New Tab field takes the keyboard once, not on every update
The page's focus effect depended on the input-ready callback, which the
App makes anew on each render, so every update and a click into the
focused field focused and selected it again: the caret blink restarted
and the text under the caret was selected. It runs once per input token
now (and on Cmd-L).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: the default New Tab is the composer and five recent chats, with a real send button
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: an open menu draws no focus ring around itself
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: a calm default New Tab with a real Send button, and no focus ring around open menus
The default New Tab is the composer and the five newest chats as quiet rows, with All Chats for
the rest; the action row, Recently Closed and the All chats table leave the default (the other
templates keep theirs). Send is the composer's arrow-up disc, off while the field is empty.
An open menu, list or popover takes focus so its keys work; the global keyboard rings no longer
draw a square around it, and the focus-ring lint refuses a universal ring that would. Monaco's
find fields draw no ring of their own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: lists that take Tab focus keep their ring; only open menus and popovers drop it
Review: the Cloud machine list and the History list are themselves the focus target, so leaving
[role=listbox] out of the ring hid their keyboard focus. Drops the classic page's unused tools
and onRunAction props.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: the New Tab's recent chats are one-line rows
The list variant set height 30px, but the card's 84px min-height won, so every row drew three
lines tall (fleet capture of the calm default; Threads and Console had it too). The calm-default
gallery play now refuses a row taller than one line: 84px before, 30px after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: the New Tab page has no tools row, so no Integrate a harness button in it
The base's #19755 test rendered the tools row the calm default removes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: New Tab scrolls in one place and fades at its edges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: New Tab scrolls in one place and fades at its edges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: a short New Tab keeps two rows of list, and the page never fades
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: keep two rows of New Tab list, fade only the list
Review: in a short pane the list collapsed to nothing behind the hidden page overflow, the
page's fade dimmed the composer's model menu (it opens inside the page), and the list's fades
covered its first and last rows. The list now keeps two rows and the page scrolls below that;
only the list fades, over end padding.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* test(gallery): typed-reddit allows the popover's own rows to reorder
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
Fixes the base red in
webviews/test/chat-header-changes.test.tsxfrom #19770.#19770 moved the header buttons' shortcut out of the
titleintodata-tooltip-shortcut, which the themed tooltip draws as a hint in the secondary ink. The button's title and accessible name are now the plain "Changes". The test still expected "Changes (⌃⇧⌘G)" in the title. It now expects the plain title and the shortcut indata-tooltip-shortcut.Testing
bun test test/chat-header-changes.test.tsx: red on base (title "Changes" vs expected "Changes (⌃⇧⌘G)"), 1 pass after this change.test/chat-header-tooltips.test.tsxandtest/chat-menu-copy.test.tsx, the other tests that assert shortcut text: both pass.Changelog
none
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Updates the chat header "Changes" test so it passes after #19770 moved header button shortcuts out of
titleintodata-tooltip-shortcut.data-tooltip-shortcutinstead.Written for commit f6a7d95. Summary will update on new commits.