Skip to content

cmux-next composer: attach location controls in a tray - #18224

Merged
teamleaderleo merged 24 commits into
feat-cmux-nextfrom
fix/composer-location-tray
Oct 7, 2026
Merged

teamleaderleo merged 24 commits into
feat-cmux-nextfrom
fix/composer-location-tray

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Showcase

Changelog

Changed: refine the cmux-next composer footer around a capped draft, left-side controls, and a recessed location shelf.

The draft stops growing after eight lines and scrolls inside the field with comfortable padding. The permission mode is a quiet icon menu, the footer controls keep a stable rhythm, and folder, computer, and branch controls stay in a compact shelf under the composer shadow. Footer menus continue to use the shared Base UI wrappers and existing press and keyboard behavior.

Proof

Live gallery preview:

The gallery entry enforces zero anchor movement, zero layout shift, and a 33ms long-frame limit around menu play steps.

Validation

  • git diff --check
  • Targeted composer and location tests passed before the bundle regeneration.
  • Bundle regeneration completed through the remote cmux-next workflow at the exact pushed head.
  • Web only. No fleet build requested.

🤖 Generated with Claude Code


Note

Low Risk
CSS and layout-only composer footer changes with gallery checks for zero layout shift; no auth, data, or backend logic.

Overview
Refines the cmux-next agent composer footer so long drafts and location controls stay visually anchored without shifting the transcript.

The prompt and shell fields no longer grow with 40vh; they cap at eight lines (calc(22px * 8 + 23px)) and scroll inside the field so the composer height stays predictable.

Folder, computer, and branch controls move into a recessed location tray attached under the composer box: rounded bottom edge, tray background/border, negative margin so it reads as a shelf behind the composer shadow, and left-aligned flex so folder/computer pickers share the leading width (branch stays on the right).

Footer chrome is tightened: composer bar padding/height, permission mode as icon-only, and 32px send and context-ring targets. The bundled agent-pane/index.html CSS is updated to match the webview styles (composerLocation.css, markdownField.css, composerStates.css).

Reviewed by Cursor Bugbot for commit f25fb19. Bugbot is set up for automated code reviews on this repo. Configure here.

Showcase

before long draft dark

gallery 50d2222960b agent pane.composer long draft en Apple System Colors w760 chromium

before long draft light

gallery 50d2222960b agent pane.composer long draft en Apple System Colors Light w760 chromium

Open the live gallery

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 722bd5b0-8ba6-44fa-b303-84ff5fa291d0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Unclear: web / react-apps-check failed: no known signature; failed step: Check diff viewer eager JS budget.

CI failed on f25fb194c3 (run 37602951604 attempt 1): 1 unknown.
macOS jobs did not run: compile and app tests were skipped: Fast static checks skipped.

Job Verdict Why
web / react-apps-check unknown no known signature; failed step: Check diff viewer eager JS budget

Not re-run automatically: web / react-apps-check is not a machine failure.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread webviews/src/agent-session/acpmux/ComposerContext.tsx
Comment thread webviews/src/agent-session/acpmux/ComposerContext.tsx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Gallery

107 states changed: agent-pane.composer/slash-menu, agent-pane.composer/long-draft, agent-pane.transcript/conversation, agent-pane.composer/draft, agent-pane.composer/codex-model, ... · 4 new states

Diff page and renders (the run's gallery-pr artifact)

State Before · after
agent-pane.composer/slash-menu (Apple System Colors Light, chromium)
agent-pane.composer/slash-menu (Apple System Colors Light, webkit)
agent-pane.composer/long-draft (Apple System Colors, chromium)
agent-pane.composer/long-draft (Apple System Colors Light, webkit)
agent-pane.composer/long-draft (Apple System Colors Light, chromium)
agent-pane.composer/long-draft (Apple System Colors, webkit)

101 more on the diff page.

1 nondeterministic state differed from a second render of the same head (a clock or fixture leak) and is not counted as changes.

52 unchanged · base 5bd8bc2 · head 50d2222

teamleaderleo and others added 3 commits October 6, 2026 21:31
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

This PR is too large for Bugbot to review. It changes 2,368 lines and 4,127,676 characters. Split the change into smaller pull requests to get a review.

teamleaderleo and others added 6 commits October 7, 2026 01:16
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r-location-tray

# Conflicts:
#	webviews/src/agent-session/acpmux/styles.css
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 7, 2026
…es (#18301)

* test: gallery thumbnail links must name the file pr-media.py stores

The gallery PR comment links <prefix><key> (agent-pane.docked-chat--working--...),
but pr-media.py's sanitize() collapses each run of dashes, so the stored file is
agent-pane.docked-chat-working-... and every inline thumbnail 404s (#18152, #18224).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(gallery): link PR comment thumbnails by the name pr-media.py stores

thumbUrl collapses dash runs in the key the way pr-media.py's sanitize() does,
so the comment's inline thumbnails point at the uploaded files. SAFE_KEY also
requires a leading letter or digit, so prefix plus key cannot form a new run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

}
.acpmux-composer-context > .acpmux-location-leading { display: flex; align-items: center; gap: 2px; min-width: 0; margin-right: auto; flex: 1 1 0; }
.acpmux-composer-context > .acpmux-location-leading > .acpmux-location-picker,
.acpmux-composer-context > .acpmux-location-picker { flex: 1 1 0; min-width: 0; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Location controls stretch with empty gaps

Medium Severity

Folder, computer, and branch pickers all use flex: 1 1 0, so they split the shelf evenly, while each control is capped at max-width: 220px. At the 760px composer width the buttons stop growing and leave empty gaps between compact labels. margin-right: auto on .acpmux-location-leading cannot pack the branch to the end because the branch picker also grows.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3487577. Configure here.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

}
.acpmux-composer-context > .acpmux-location-leading { display: flex; align-items: center; gap: 2px; min-width: 0; margin-right: auto; flex: 1 1 0; }
.acpmux-composer-context > .acpmux-location-leading > .acpmux-location-picker,
.acpmux-composer-context > .acpmux-location-picker { flex: 1 1 0; min-width: 0; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branch picker steals tray space

Medium Severity

The shelf gives both the leading cluster and the branch picker flex: 1 1 0, so margin-right: auto cannot keep the branch compact on the right. With width: 100% on the control, the branch button grows toward 220px and sits in the middle of the tray instead of hugging the end.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a81f568. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fa166ac. Configure here.

box-sizing: border-box;
border: 1px solid var(--acpmux-composer-edge);
border-top: 0;
border-radius: 0 0 20px 20px;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate selector creates dead CSS property values

Low Severity

The .acpmux-composer-context selector is declared twice at the same cascade level with no conditional wrapper. The second block (around line 2445) unconditionally overrides height, margin, padding, and border-radius set in the first block (around line 2361). Those four properties in the first block are dead — they never take visual effect, but a future developer editing them would reasonably expect them to control the layout. The values from the two blocks could be consolidated into a single rule to avoid this confusion.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fa166ac. Configure here.

@teamleaderleo
teamleaderleo merged commit daf0d36 into feat-cmux-next Oct 7, 2026
52 of 55 checks passed
@teamleaderleo
teamleaderleo deleted the fix/composer-location-tray branch October 7, 2026 09:53
teamleaderleo added a commit that referenced this pull request Oct 7, 2026
#18224 (daf0d36) left one expect() unformatted, so react-apps-check's
`vp check` fails on feat-cmux-next with "Formatting issues found".
This is `vp fmt` output only.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Backfilled matching base shots for the long-draft proof at the same gallery entry, theme, width, and Chromium renderer:

State Before After
long draft, dark, 760px before after
long draft, light, 760px before after

teamleaderleo added a commit that referenced this pull request Oct 7, 2026
* test(cmux-next): require no lone space dot at rest

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cmux-next): draw no lone space dot at rest

With one space the sidebar drew a single dot above the footer. The bar
stays mounted, but a lone dot now draws only with the + on hover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cmux-next): Cmd-K under the open palette must not clear the terminal (red, cx-6so.46)

AppKit offers a key equivalent the key panel did not handle to the main
window too. The palette keeps the terminal's context bits, so the shell
window hook resolves Cmd-K to terminal.clear and runs it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(cmux-next): a shell completion past its deadline answers a timeout (red, cx-6so.47)

respondToShellComplete maps timedOut to spawnFailed(0) ("Could not
start"). The completion gets an injectable timeout and the model holds
its completion, so a fake bash that sleeps proves the mapping.

The candidate tests use the shared 30 s test timeout: on a loaded fleet
Mac (aws-m4pro-3, load 56) a login bash passed the 4 s app deadline and
bashCompletesCommandsAndFiles failed with .timedOut on base 880b1a3.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(cmux-next): Cmd-Shift-G in a focused terminal is Ghostty's previous match

BrowserChromeKeysTests.shiftCommandGIsFindPreviousInABrowser was red on
the trunk since f28642f (bisect: green on 89e0a3e, red on
9bcce34). That commit made groupSelectedWorkspaces yield to a
focused terminal on purpose (decision K1 follow-up); the test still
expected the cmux action there. The test follows the decision.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cmux-next): a key the open palette does not handle stays the palette's (cx-6so.46)

AppKit offers a key equivalent the key panel did not handle to the main
window behind it too. The palette keeps its terminal's context bits (its
commands act on that terminal), so the shell window hook ran Cmd-K as
terminal.clear, and the terminal, still its window's first responder,
could run its Ghostty cmd+k keybind.

KeyRouter.overlayHasKeys(focus): while any overlay (palette, sheet,
rename prompt, group editor) is open, the window hook runs no content
action, and ShellWindow passes on key equivalents while it is not the
key window, so nothing below the overlay takes the key. Menu items keep
their tier gate (system and navigation actions still work).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cmux-next): a shell completion past its deadline answers shell.timed_out (cx-6so.47)

respondToShellComplete answered every failure but a missing folder as
spawnFailed(0), "Could not start", also when the shell started and only
passed the 4 s deadline. A timeout now answers code shell.timed_out with
"Completion timed out" (21 languages); folder and spawn failures keep
shell.failed with their own messages.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Home harness: the oracle builds the catalyst files upstream's appkit-native/project.yml lists (new upstream files no longer break the oracle)

* MessagesLab pin d5d6a18: Markdown rendering, selection model and custom rows (their catalyst files vendored), container-motion and tail-only updates; TranscriptAccess stays at bd65bbf (its rewrite needs unvendored drivers); new strings in all 21 app languages (needs_review); the oracle builds upstream's project.yml file list; the flight recorder test waits for the off-main frames file

* cmux-rd: red tests for the viewer's upstream media sender (C4b)

Core: UpstreamSender sends UpMedia frames the host reassembles, drops a
dependent frame without a keyframe, resends NACKed shards until the ack,
refuses other streams' feedback, lowers its target on a growing queue,
adds parity on loss, paces at the target and breaks the chain on a drop,
falls to the floor when the host is silent; audio packets are independent
and a lone shard is not padded. Engine: the sender recovers a lost shard
through the host's NACK. rd-ffi: the CmuxRdUpstream C ABI (ABI 3) on both
carriers.

* cmux-rd: the viewer's upstream media sender with congestion control (C4b)

cmux-rd-core::upstream::UpstreamSender sends microphone, camera and
screen share frames as UpMedia shards; the host's upstream feedback
drives the delay-gradient CongestionController (arrival times), loss
measurement (LossMeter moves from cmux-rd-engine to cmux-rd-core so both
directions share it) and adaptive parity, NACK resends from a bounded
history (32 frames, 2 MiB, 64 resends per feedback), acks that trim the
history, and keyframe requests on host recovery. A pacing budget at the
target bitrate (100 ms burst) drops frames instead of queueing; a drop
breaks the reference chain, so dependent frames wait for an independent
one. A host silent for 500 ms with a frame unacked drops the target to
the floor. Block FEC is optional (off for Opus audio).

The packetizer no longer pads a lone shard without parity (wire
compatible: receivers accept any length for a frame's only shard), so a
120-byte Opus packet costs 152 bytes instead of a full datagram.

cmux-rd-ffi ABI 3: CmuxRdUpstream (cmux_rd_upstream_new, free,
send_frame, on_datagram, pop_datagram, target_bps, set_path, stats),
CMUX_RD_PATH_*, CMUX_RD_UPSTREAM_MAX_QUEUED (4 MiB of untaken datagrams,
then new frames are dropped). Host feedback reaches Swift as a session's
datagram message and is offered to each sender.

* cmux-rd-ffi: red tests for per-kind upstream consent (C4b privacy condition)

A sender is created for one media kind (mic, camera, screen) and sends
nothing until the app grants that kind's consent: send_frame and
on_datagram return CMUX_RD_ERR_CONSENT and emit nothing; consent for
another kind is refused; revoking drops untaken datagrams; a new sender
starts without consent.

* cmux-rd-ffi: per-kind upstream consent; doc the unpadded lone-shard wire rule (C4b)

cmux_rd_upstream_new takes a media kind (CMUX_RD_MEDIA_MIC, CAMERA,
SCREEN) and starts without consent. cmux_rd_upstream_set_consent(kind,
granted) is the app's switch after an explicit user action; another
kind is CMUX_RD_ERR_INVALID. Without consent send_frame and on_datagram
return CMUX_RD_ERR_CONSENT (-8) and queue nothing (feedback still
updates the controller); revoking drops untaken datagrams; consent dies
with the handle. CmuxRdUpstreamStats gains consent (still 32 bytes).

plans/cmux-next/remote-desktop.md: a frame of one data shard and no
parity is sent unpadded; receivers accept it. Lane note: the C4b line
with the Swift slice's consent contract (user action per kind and
session, macOS permission prompt, visible indicator with stop, revoke at
session end, up_media cap only).

* images/cmux-vm: development boots agenttools5 (agent tools, cua-video refused); credential audit

Dev Worker CLOUD_FREESTYLE_SNAPSHOT auto8 -> cmuxnp-dev-vmimg-agenttools5
(sh-e64294bf57394cd397ba37951eeb6a52), Worker version 41e53360, dev-e2e
19/19 including the booted snapshot. Rollback to auto8 recorded in
channels/dev.json, cloud-automation.md 33 and the backend lane file.
Section 33 also records the credential audit and the cua-video check.

* test(acpmux): a chats_watch sent before the chat index starts gets served once it starts (red)

The app connects at launch; the daemon answered ready:false and never subscribed that connection, so the sidebar Chats list stayed empty.

* fix(acpmux): serve a chats_watch that arrives before the chat index starts

chats_watch without a running index registers a ready waiter (Hub::when_chats_ready). start_chats runs the waiters right after the index is set: each subscribes its connection and sends _acpmux/chats_lagged, so the client lists again. Found by the all-chats GUI proof: the app's feed connected at launch and stayed empty.

* ci: install web dependencies before the Cloud VM image lock tests (#18311)

The lock test imports smoke.ts, which reaches guest.ts and its freestyle
import, so every feat-cmux-next push run since db3743e failed with
"Cannot find package 'freestyle'". The job assumed no web dependency.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(gallery): link PR comment thumbnails by the name pr-media.py stores (#18301)

* test: gallery thumbnail links must name the file pr-media.py stores

The gallery PR comment links <prefix><key> (agent-pane.docked-chat--working--...),
but pr-media.py's sanitize() collapses each run of dashes, so the stored file is
agent-pane.docked-chat-working-... and every inline thumbnail 404s (#18152, #18224).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(gallery): link PR comment thumbnails by the name pr-media.py stores

thumbUrl collapses dash runs in the key the way pr-media.py's sanitize() does,
so the comment's inline thumbnails point at the uploaded files. SAFE_KEY also
requires a leading letter or digit, so prefix plus key cannot form a new run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* test(webviews): keep base green on the ui-rules ratchet growth from 7f67cf1 and eb59615 (#18317)

7f67cf1 added task checkbox roles in conversation/Markdown.tsx and
pages/markdown/editor.ts, and eb59615 added a keydown handler in
changes/treeMotionDom.ts, so "migrated page code has no raw roles..." fails
on feat-cmux-next. The two acpmux files go on the pending list for their
owners to clear. pages/markdown may not be pending (a migrated page), so the
editor's read-only ProseMirror task mark gets a ui-allow reason instead.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant