Repository navigation
cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions - #21951
Conversation
… motion exceptions c5a1f90 built the update card's entrance, exit and crossfade from raw CABasicAnimation, CASpringAnimation, CATransition and CAMediaTimingFunction, so check-motion is red on feat-cmux-next (9 hits). Every duration and spring already comes from the injected MotionPolicy's tokens; Motion.set would write the model value and read the global policy instead. The 9 lines carry a motion-allow and the type doc says why. Comments only. 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 |
|
Receipt for
|
|
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by |
The curves and the spring's settle tolerance are literal, not tokens; say so, so the allow does not overclaim (coord-2's review of #21951). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Bead |
|
Landing under the base-red rule. In this PR's "cmux-next checks" run, the only failures are "No literal state roots" and "Main-thread concurrency". Both also fail at feat-cmux-next f143ac4 with no change applied (ErrorJournalService.swift:44 literal |
|
cmux-next tour of Path-selected interactions
Core UI (before): PASS — 12 ok
Screenshots (11)1. Launch
Screenshots (11)1. Launch Tours are data in |
The ErrorJournal (1597dc9) and browser popup (fa8b3fc) commits left five checks red on feat-cmux-next, so every PR into it fails "cmux-next checks" and its web lane skips its tests. Comments and baselines only, no behavior change: - Main-thread concurrency: the harvest loop runs in a detached utility task and the flush delay in the ErrorJournal actor's task, so neither is on main; reviewed concurrency-allow and wakeup-allow comments. - No literal state roots: the app's ~/.acpmux/daemon.log is only read; a keep row in the baseline. - Package conventions: lint:allow on BrowserPopupWindowGeometry (pure geometry). - Type scale: BrowserPopupPanel.swift has no raw font sizes left; drop its row. - Text focus: the popup address field sets focusRingType = .none (was #21963). Motion tokens (SidebarCardTransition) stays with #21951 for its owner. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…t frame of a click (#21976) * test(ui): a picker trigger is marked pressed from press to release (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(agent pane): a composer picker keeps its pressed tone on the first frame of a click Opening a picker moves focus into its popup before the held frame paints, which clears :active. The trigger carries data-press-active from press to release, and the composer's picker buttons draw the open-chip tone under it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * guards: drop the pull_request_target publish case removed with publish-pr-tree 17bb49c deleted the dead publish-pr-tree job, so release-notary's 'pull_request_target refs/heads/feat-cmux-next publishes once' cases failed 5 times (run 39205353024). * ci(cmux-next media): rebuild a warm tour's prebuilt modules after a binary pin change (#21971) * test(ci): a warm tour must rebuild after a GhosttyNextKit pin change The cmux-next tour keeps each tag's DerivedData warm, and Xcode reused the explicit module it had precompiled from the old pin's ghostty.h: "ghostty.h has been modified since the module file ... was built" (job 117892119256). This regression runs the tour's build step twice with a stand-in reload.sh that fails the same way; it fails until the fix lands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ci): drop a warm tour's prebuilt modules when a binary pin changes A Mac that last built a pull request's tag with GhosttyNextKit e6a27a1fb failed the next tour, which pinned ced99dcde: Xcode copied the new ghostty.h into Build/Products/Debug/include but kept the explicit module it had precompiled from the old one (job 117892119256). scripts/ci/media_module_cache_stamp.py keys a tag's build on every sha256 in the tracked Package.swift files and every Package.resolved. Before reload.sh it removes SwiftExplicitPrecompiledModules, ExplicitPrecompiledModules and ModuleCache.noindex when that key differs from the stamp of the tag's last good build; after the build it writes the stamp. The rest of DerivedData stays warm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * gallery advisory: sample the states a PR adds first (#21850) * gallery advisory: sample the states a PR adds first A PR that touches a shared file (strings, App.tsx) touches every gallery entry, so the first 16 states in order came from unrelated entries and the receipt never showed what the PR added. The manifests now list every touched state and the sample puts the new ones (no base case with that id) first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * gallery advisory: the base keeps every sampled state before removed ones The base filter cut at 16 in base order, so removed states early in that order could push out sampled states that exist in base, which were then compared as new. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 0283a51) * gallery advisory: each stage renders its own manifest Both stages rendered the joined case list, so the base reported the states a PR adds as not ready (it has no such variant) and the capture stopped before the head ran. Now that new states come first, every PR that adds a variant hit this (#21851's first run). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 5b6d825) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback (#21958) * docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback The guarded fallback for when gh-merge-green couldn't read the coordinator's WINDOW no longer applies: freezes are merge-freeze issues that every host reads through the GitHub API (#21957). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(merge-freeze): gh-merge-green enforces the freeze check Same line as #21957 on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * apps: preserve provider mutation context for owner handlers (#21406) Replays #21406's change onto current feat-cmux-next as one commit. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * test(sidebar): a dragged group drops between every group Regression test for scrawl-1792382497882-1673e-10: on the sidebar document path a dragged group found a drop only on the thin bands of each group header. Fails without the fix. * fix(sidebar): fluid group drag, a drop at every gap between groups - SidebarDragGeometry: a drop that cannot go into a group (a dragged group, groups do not nest) goes before or after the whole group, by the half of its block the probe is in, over its header or any member row. Before, every member row refused and the gap closed. - A dragged group's header, not the tall card's centre, decides the drop. - A refused place keeps the last open gap instead of springing it shut and dimming the card, so rows stop jumping during the drag. * test(layout): a divider drag keeps one daemon command in flight Adds GestureCommandCoalescer and its tests: 125 live values while one command is in flight send the first and the newest only; the ended value goes last; a failed live value with a newer one waiting is superseded. * fix(layout): stop flooding the daemon during divider and column drags NIGHTLY sent one set-viewport-pane-width per mouse move (~125/s); each timed out at 2 s and every other command (pane and tab moves, saves, attaches) timed out behind them. Divider and column gestures now go through GestureCommandCoalescer: one command in flight per gesture, only the newest value waits, the ended value always goes last. A failed live value with a newer one waiting no longer rolls the divider back. * scripts(cmux-next): drag-lag-live.py, column/tab/sidebar drag timing on a fleet app * scripts(cmux-next): drag-lag-live probes the daemon during drags, bigger scene * ci(nightly-next): one-command rollback of the cmux NEXT feed (#21887) * ci(nightly-next): one-command rollback of the cmux NEXT feed nightly-next-rollback.yml takes a bad build, and every newer one, off appcast-arm64.xml so the feed serves the previous signed build again. It runs in release-next on branch nightly-next, guards the appcast and R2 key like publish-nightly, checks the fallback DMG exists, refuses to empty the feed, and stops when the feed changed while it planned. docs/ci/nightly-next-canary.md maps the nightly pipeline and its holds and says what a pull can and cannot do: Sparkle never offers a lower build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(nightly): the delta lane never puts a pulled build back on the feed republish-nightly-deltas skipped its rewrite only when the live NEXT feed served a newer build. After nightly-next-rollback.yml pulls build N, the feed serves N-1 and the lane's two-item appcast would restore N. It now skips whenever the feed serves any other build. The regression cases in test_nightly_republish_delta_guard.py fail on the old guard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(nightly-next): rollback runs-on keeps a fork branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(nightly-next): the rollback writes the feed only with If-Match upload-r2-object.py --replace-sha256 HEX reads the object, requires the bytes the caller planned from, and writes with If-Match on its ETag; a changed object is not written (--conflict-exit-code). The rollback uses it instead of a public re-read, so a publication that lands between the plan and the write is never overwritten. Its summary no longer says "nothing to pull" when the plan itself failed. (CodeRabbit on #21900.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions (#21951) * cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions c5a1f90 built the update card's entrance, exit and crossfade from raw CABasicAnimation, CASpringAnimation, CATransition and CAMediaTimingFunction, so check-motion is red on feat-cmux-next (9 hits). Every duration and spring already comes from the injected MotionPolicy's tokens; Motion.set would write the model value and read the global policy instead. The 9 lines carry a motion-allow and the type doc says why. Comments only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the sidebar card's motion-allow note names what stays literal The curves and the spring's settle tolerance are literal, not tokens; say so, so the allow does not overclaim (coord-2's review of #21951). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * optchat-chief: auto-resume subagents that stop on a model or network error A subagent run that ends on an API/harness error is classified (auto_resume.rs): transient errors (overloaded, 429, 5xx, did not start) are told to continue after a 30/60/120 s backoff, at most 3 times in a row; network errors (connection lost, fetch failed, DNS) are not retried blind: a thread waits until a TCP probe of the model endpoint (the subrouter from ANTHROPIC_BASE_URL or ~/.claude/settings.json) answers, then continues. The Chief's chat gets a quiet '[id] stopped: <reason>' note; the subagent's chat shows each '[auto-resume N]' continue. A stop auto-resume gives up on is reported as usual. OPTCHAT_AUTO_RESUME=off turns it off. * optchat-chief: auto-resume agent CLIs in cmux terminals; fix clone_on_copy terminal_watch.rs: every 30 s the Chief host lists cmux terminals; a Claude Code or Codex terminal that reports 'error', or sits idle at an empty prompt with an API error as its last output, is classified as in auto_resume.rs. Transient errors get '[auto-resume N] ... continue' typed at the prompt after a backoff; network errors wait until the model endpoint answers. Working, blocked (a question) or half-typed prompts are never touched. Each event reaches the Chief chat as '[term_...] stopped: <reason>' (a notice while a continue is planned, a Chief note when it gives up). OPTCHAT_TERMINAL_RESUME=off turns it off. Also: a short reply that only mentions an error is not a stop, and the clippy clone_on_copy in workspaces.rs (a75b0c3) is fixed. * optchat-chief: module order in lib.rs (rustfmt) * fix(acpmux): clear stop timer on client close (#21615) * Markdown: cmux:// workspace, pane, tab and chat links open in the app A cmux:// link in rendered Markdown did nothing or left the app: the Markdown file page classified every non-web scheme as unsafe, Home only linked a Chief subagent's chat, and the agent pane drew only http(s). - One opener, CmuxAppLinks (was ChiefSubagentLinks): a workspace, pane, tab or session link in the `cmux` scheme or this build's scheme, or this Chief's subagent link, runs link.open. Terminals and pages reach it via LinkRouter.appLink. - Markdown file page: `cmux://...` is link kind "app" (hover: "Opens in cmux", 21 locales); cmux.markdown.openLink kind "app" opens it in the app or refuses, never the system. - Home: URL.isCmuxAppLink draws and routes the same links to onAppLink. - Agent chat: replies draw cmux app links; a click after a real gesture goes to the app opener, never NSWorkspace. - javascript:, file:, data:, vbscript:, ssh: and malformed ids stay text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next palette: Go to Workspace (Cmd-P) searches groups, panes, tabs and agent sessions Cmd-P now lists sidebar groups, panes and every tab (terminal, browser, markdown, file, agent chat) next to the workspaces once you type, each row with its kind and its parent workspace and group. Titles, cwd, URL, group names and session ids are searchable; whole-title and prefix matches rank first, then the recently used. - Picking a group shows its first workspace, expanding the group when collapsed (WorkspaceGroupFocus, shared with Next/Previous Workspace Group). - Picking a pane or tab shows its workspace and focuses it (pane.focus, revealTab as Search Tabs). - Cmd-K in the palette shows the row's Actions menu; agent rows offer Copy Session ID: acp:<session id> for acpmux chats (what cmux agent message takes), the harness session UUID for Claude Code / Codex terminals. Handle format documented in skills/cmux-acpmux/SKILL.md. * acpmux: require version evidence for already-current updates (#21398) Replays #21398's change onto current feat-cmux-next as one commit. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cx-dgsp follow-ups: scope-bound wire tickets, hold a refused feed token (#21725) * test(api): the forwarded wire upgrade carries no credential A native header upgrade with stray bearer.x and ticket.y subprotocols reaches UserDO with no Authorization header and only cmux.wire.v1. Green on the current strip; red when wireCredential keeps bearer. or forwardHeaders keeps Authorization. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(api): a wire ticket opens only the scope it was minted for (red) POST /v1/wire/ticket takes {scope}; a feed ticket must not open the user socket, a refused try spends it, an unscoped ticket is a user ticket and an unknown scope mints nothing. Fails now: the feed ticket opens /v1/wire/user (101). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud-client): openWire mints its ticket for the scope it opens (red) Fails now: POST /v1/wire/ticket goes out with no body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(api): bind a wire ticket to the socket scope it was minted for POST /v1/wire/ticket takes {scope} (user|team|feed|cloud|conv|mux; no body or no scope means user, which the dashboard panel and any client minted before this send). The ticket record keeps the scope; the router entry still spends a ticket on any path, and wire() refuses one of another scope with the usual 401. openWire and the dashboard's wireCredential name their scope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a 401 on the feed wire holds the refused token (red) CloudFeedSource takes an internal Connect seam and reconnect Backoff so the loop runs against a fake; the socket session throws Unauthorized when the upgrade's response is 401. The test fails now: the loop opens a socket for every repeat of the refused token (a, a, a, b), not a then b. Compile-only on this Linux host; it runs in CmuxNextAppTests on macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): stop reconnecting the feed wire with a token the server refused A 401 on the upgrade fed the outer reconnect loop, which opened a socket with the same token every 500 ms..30 s. The loop now remembers the refused token, reports a disconnected reason once, and opens no socket with it again: it asks the token provider on the Backoff schedule (no request reaches the server) until it returns another token. start and reset still restart the loop on a sign-in or account change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(api): the expired-ticket test mints a feed ticket for the feed socket With scope binding, an unscoped (user) ticket on /v1/wire/feed is refused for its scope, so the test no longer reached the expiry check. Red when WireTicketDO.spend ignores expires_at. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the Desktop Wallpaper tile shows the desktop, never a broken image macOS can report a desktop picture that is gone (a deleted file in /tmp), a folder it rotates through, or a .madesktop description. The Settings thumbnail and the window backdrop loaded that URL as is, so the tile drew the webview's broken-image mark and choosing it showed nothing. DesktopPicture resolves the reported URL to a picture that decodes: the file, a picture in the folder, the still a description names, or else a picture of the desktop fill color. The picker swaps a thumbnail that fails to load for an empty framed box. * Home dock: pinned column kind (pinned-dock-v1) Lawrence 2026-10-18: "I should not be able to close Home inside the Home thing ... I should not be able to create more tabs in the Home thing unless I explicitly enable it." Daemon (cmux-tui): a dock column may be pinned. Its first tab stays (no close, move out or reorder away from the first place) and it takes no other tab unless its allow_tabs is on (column.update {allow_tabs}). The column is never removed, undocked or unpinned. Enforced on every path (resource ops, JSON-lines, layout undo, terminal tab creation before the spawn) with reason_code dock-column-pinned. set-column-dock takes pinned; column.update takes pinned and allow_tabs. Spec, docs, bindings updated. App: Home pins its left chat dock on connect (page tab first). Home's tab shows no close button, the strip no new-tab button while the column takes no tabs, Cmd-W keeps Home's tab, new agent chats open beside a pinned dock, and a refused close says "Home stays open in its column." * cmux NEXT: compact attachment strip in the composer (#21739) * test(acpmux): the attachment strip is compact Leo 2026-10-18: pasted screenshots took ~100 px off the composer. One row of 64 px tiles 6 px apart, 8 px under the composer's top, the text 6 px under it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): compact attachment strip, like the Claude desktop composer 64 px tiles (from 80), a 6 px gap, an 8 px top inset, and the prompt starts 6 px under the strip instead of 15. The strip adds about 78 px, not ~100. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): shell field follows the compact strip; tighten the gallery budget Review: in shell mode under attachments the field and glyph kept the 15 px inset, so typing ! moved the text 9 px. The attach-screenshot gallery budget still allowed the old 96 px row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acpmux): wait for the thumbnails to load instead of decode() CI: decode() rejected while a thumbnail's source was swapped for its copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the popup address field draws no focus ring (#21963) fa8b3fc made the popup URL label selectable without focusRingType = .none, which turns check:text-focus red on every webviews job. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * composer: picking another provider's model keeps the typed prompt (#21937) * test: a harness switch keeps the typed prompt (red) * composer: picking another provider's model keeps the typed prompt through the harness switch * composer: a chat's own saved draft wins over a carried prompt (review) * fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵ (#21870) * test(acpmux): a running turn's empty prompt teaches Return and ⌘Return Leo 2026-10-18: like Claude's "↵ to send, ⌘↵ to queue for later", the empty prompt mid-turn says "↵ to queue, ⌘↵ to steer" (or interrupt, for an agent that cannot steer). The Quick Composer keeps "Queue a follow-up". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵ Mid-turn the empty prompt says "↵ to queue, ⌘↵ to steer" (or "to interrupt" when the agent cannot take steering), as Claude's composer does. The Quick Composer keeps "Queue a follow-up", since its ⌘↵ opens the window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acpmux): an attachment-only prompt mid-turn names only the queue key Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): drop the ⌘↵ hint with only attachments, match the Steer button's verb ⌘Return needs typed text, so an attachment-only prompt mid-turn says only "Queue a follow-up". The es, fr, it, ja, ko and uk hints now use the Steer button's own verb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(acpmux): say when the queued placeholder still shows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: schema doc names peer masking and the lane error cut (#21924) * docs(acpmux): the schema names peer masking and the lane error cut The SessionSummary lane note still said every other field stays raw; since #21871 a peer daemon reads them masked, and since #21799 the lane error is cut to 3072 characters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(acpmux): raw for every client but a proven peer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: every markdown viewer is read-write; Cmd-=/-/0 text size and a default size setting Root cause: a markdown file opened by cmux open, an agent or a link (not the user's own Open File...) was writable only inside a files.roots folder. The roots setting is empty by default and never holds home, so viewers opened from the Home workspace (and any workspace) came up read only with an "outside the workspace" note. - Markdown pages are writable for every document they show; only a real reason keeps one read only (not UTF-8, binary, not writable, or a chat transcript the host opens read only), and the page names the reason. The code editor keeps its root rule. - The markdown page handles the zoomIn/zoomOut/zoomReset page commands the app already sent: one pixel per step (8-40) in rich and source mode, Cmd-0 back to markdown.font.size. Cmd-Shift-= is a Zoom In alias. - Settings > Appearance > Markdown Viewer > Default Font Size (markdown.font.size, 16, 8-40), localized. Co-Authored-By: Claude <noreply@anthropic.com> * fix(home): pasted pictures are small thumbnails in a row in the composer The vendored MessagesLab compose strip copies macOS 27 Messages: every attachment is a 177 x 118 pt tile stacked top to bottom above the text. Two pasted screenshots made the field ~280 pt tall and pushed the text line to the bottom. Images are now aspect-fit in 128 x 64 pt, files are 200 x 52 pt pills, and tiles flow left to right and wrap at the field's right edge. Tests: ComposeAttachmentLayoutTests (MessagesLabHome). * test(home): qualify Attachment (Swift Testing has one too) * cmux-next: page strings tables become build output (#21970) * test(webviews): strings tables must not be tracked Red on feat-cmux-next: every table gen-strings.mjs writes is committed, and none is ignored (#21946). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: page strings tables become build output (#21946) The generated strings tables (webviews/src/**/generated/strings.json, the diff page's per-locale tables and loader, the home-channels pane table) are no longer committed. bun install (postinstall, best effort), the webviews test preload (only stale pages) and every bundle build (strict) write them from the checkout's xcstrings catalogs and settings schema. Committed copies conflicted in every pull request that changed a catalog or the settings schema, and the PR autofix could rebuild one from a stale schema and drop another branch's labels (#21746). A table made from the tree it sits in can do neither. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: merge rules and atomic writes for every strings output (#21946) The diff page's locale tables and loader and the home-channels pane table are build output too: route them through cmux-generated-v1 and next_batch's WEB_GENERATED, so a branch from before the change that edited one catches up instead of stopping on a modify/delete conflict. gen-strings writes through a temporary file (parallel test preloads), and --best-effort skips a page whose catalog or schema is missing instead of failing bun install. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at f2ef8f4 - regenerated schemas/settings-export/settings-schema.sources.sha256 - vp fmt webviews/scripts/pages/gen-strings.mjs - vp fmt webviews/test/strings-build-output.test.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39205550635 --------- 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: a new terminal tab spawns at its pane's grid, so its first frame is final The Mac's new-tab request sent no size. The daemon then spawned the PTY at the grid of whichever terminal reported last, anywhere (client_sizing_state.rs creation_size), the shell printed its first prompt at that width, and the pane snapped when the view's first report resized it. newTerminalTab now sends cols/rows (NewTerminalGrid): the fitted grid of the terminal the pane shows (Ghostty's own fit of the same content host), else the content host size, backing scale, a live terminal's cell size and the configured padding through Ghostty's formula (TerminalGridEstimate; Cmd-T's New Tab page, a page or agent tab). A zoomed terminal does not count. With neither known the daemon's fallback applies as before. docs/shared-terminal-sizing.md: a Creation size section (who sizes a new terminal, and why a later attach never draws a wrong frame for others). * cmux NEXT: NewTerminalGridTests builds its padding from the public default * perf-10x daemon: request-latency bench (raw, 10 clients, CLI; 1 and 200 terminals) * cmux-next: clear five base reds in the cmux-next checks lane (#21981) The ErrorJournal (1597dc9) and browser popup (fa8b3fc) commits left five checks red on feat-cmux-next, so every PR into it fails "cmux-next checks" and its web lane skips its tests. Comments and baselines only, no behavior change: - Main-thread concurrency: the harvest loop runs in a detached utility task and the flush delay in the ErrorJournal actor's task, so neither is on main; reviewed concurrency-allow and wakeup-allow comments. - No literal state roots: the app's ~/.acpmux/daemon.log is only read; a keep row in the baseline. - Package conventions: lint:allow on BrowserPopupWindowGeometry (pure geometry). - Type scale: BrowserPopupPanel.swift has no raw font sizes left; drop its row. - Text focus: the popup address field sets focusRingType = .none (was #21963). Motion tokens (SidebarCardTransition) stays with #21951 for its owner. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cx-ncc.104: Debug toggle for the agent pane's in-session status (agent.sessionStatus) (#20953) Recut of #20953 onto the current feat-cmux-next as one commit: the In-session status Debug toggle, its sessionStatus page event, and useSessionStatus() for the plan and recap cards. The base merge kept both sides of the tunables list, the view's observations and the page host's events (the sidebar preview variant landed meanwhile). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: route/list says which routes serve the session's family (#21852) * test(acpmux): route/list names a session's family and which routes serve it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(acpmux): route/list says which routes serve the session's family With a sessionId, _acpmux/route/list now returns the session's family and a serves flag on each route (Route::serves), so the composer's Account menu can list only the routes that can run this chat without copying that logic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: tunable registries list one entry per line (#21972) * cmux-next: tunable registries list one entry per line (#21946) AgentPaneTunables.all and SidebarTunables.all were single lines, so every pull request that added a tunable conflicted with every other one there (14 open PRs on AgentPaneTunables, 4 on SidebarTunables). Each entry now has its own line in alphabetical order, so two additions insert different lines and merge cleanly; TunableCatalog.all lists one module per line. Debug Settings shows the agent-pane and sidebar tunables alphabetically; nothing else depends on the order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the TunableCatalog list as it was: CmuxNextApp may not grow The one-per-line TunableCatalog added 20 source lines to CmuxNextApp, which check-app-size.sh refuses. The conflict hotspots are the AgentPaneTunables and SidebarTunables lists, which live in their own targets and stay one per line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * test(next): cover dictation auto-send prompt routing (#21169) * test(next): cover dictation auto-send prompt routing * fix(next): satisfy dictation test formatting * chore(next): PR autofix at 60f4a49 - regenerated Packages/macOS/CmuxNext/ci-target-graph.json - vp fmt webviews/src/agent-session/acpmux/replyHref.ts - vp fmt webviews/src/pages/markdown/README.md - vp fmt webviews/src/pages/markdown/links.ts - vp fmt webviews/test/markdown-cmux-app-links.test.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39212288176 * chore: drop the autofix bot's unrelated markdown-link and target-graph edits from this PR They aren't part of this change; base carries its own version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(agent pane): a pressed pill keeps the pill's own open tone The model, effort and access pills open at --acpmux-pill-hover; under the press marker alone they drew the brighter --acpmux-pill-open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(ui): window blur, Escape and a drag-out release clear the press marker (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ui): the press marker clears on window blur, Escape and unmount A press whose pointerup never reaches the page (Cmd-Tab away, Escape) left the pill tinted. The plain footer's resting and hover rules also exclude the marker, so it can't flash there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Co-authored-by: Lucas Ribeiro <lucascamribeiro@gmail.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
…tions (#22100) check-motion (the Motion tokens step of cmux-next checks) is red on feat-cmux-next and so on every PR: TabCell+HibernationRing.swift:109 (c9df8bf), TerminalSizedForChip.swift:98 and HoverCardPanel.swift:192/195 (8c3bf17). Each takes its duration from Motion and skips when Motion says 0; only the curve or the transition object is raw. Mark them with motion-allow, as #21951 did for the sidebar card. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(agent-pane): accept new tab inline suggestions safely * fix(agent-pane): complete visited URL suggestions * test(new-tab): Tab without a highlighted row moves focus; history rows are not inline-accepted Red: Tab is prevented whenever suggestions show, and Right/End inline-accepts history rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(new-tab): Tab steps only a keyboard-highlighted row; inline completion skips history rows Tab is taken only after Down/Up/Tab moved the highlight, so keyboard users can Tab to Send. Right/End inline-accept only top-row open results (typed address or top site), matching the comment that history rows stay explicit picks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * guards: drop the pull_request_target publish case removed with publish-pr-tree 17bb49c deleted the dead publish-pr-tree job, so release-notary's 'pull_request_target refs/heads/feat-cmux-next publishes once' cases failed 5 times (run 39205353024). * ci(cmux-next media): rebuild a warm tour's prebuilt modules after a binary pin change (#21971) * test(ci): a warm tour must rebuild after a GhosttyNextKit pin change The cmux-next tour keeps each tag's DerivedData warm, and Xcode reused the explicit module it had precompiled from the old pin's ghostty.h: "ghostty.h has been modified since the module file ... was built" (job 117892119256). This regression runs the tour's build step twice with a stand-in reload.sh that fails the same way; it fails until the fix lands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ci): drop a warm tour's prebuilt modules when a binary pin changes A Mac that last built a pull request's tag with GhosttyNextKit e6a27a1fb failed the next tour, which pinned ced99dcde: Xcode copied the new ghostty.h into Build/Products/Debug/include but kept the explicit module it had precompiled from the old one (job 117892119256). scripts/ci/media_module_cache_stamp.py keys a tag's build on every sha256 in the tracked Package.swift files and every Package.resolved. Before reload.sh it removes SwiftExplicitPrecompiledModules, ExplicitPrecompiledModules and ModuleCache.noindex when that key differs from the stamp of the tag's last good build; after the build it writes the stamp. The rest of DerivedData stays warm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * gallery advisory: sample the states a PR adds first (#21850) * gallery advisory: sample the states a PR adds first A PR that touches a shared file (strings, App.tsx) touches every gallery entry, so the first 16 states in order came from unrelated entries and the receipt never showed what the PR added. The manifests now list every touched state and the sample puts the new ones (no base case with that id) first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * gallery advisory: the base keeps every sampled state before removed ones The base filter cut at 16 in base order, so removed states early in that order could push out sampled states that exist in base, which were then compared as new. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 0283a51) * gallery advisory: each stage renders its own manifest Both stages rendered the joined case list, so the base reported the states a PR adds as not ready (it has no such variant) and the capture stopped before the head ran. Now that new states come first, every PR that adds a variant hit this (#21851's first run). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 5b6d825) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback (#21958) * docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback The guarded fallback for when gh-merge-green couldn't read the coordinator's WINDOW no longer applies: freezes are merge-freeze issues that every host reads through the GitHub API (#21957). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(merge-freeze): gh-merge-green enforces the freeze check Same line as #21957 on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * apps: preserve provider mutation context for owner handlers (#21406) Replays #21406's change onto current feat-cmux-next as one commit. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * test(sidebar): a dragged group drops between every group Regression test for scrawl-1792382497882-1673e-10: on the sidebar document path a dragged group found a drop only on the thin bands of each group header. Fails without the fix. * fix(sidebar): fluid group drag, a drop at every gap between groups - SidebarDragGeometry: a drop that cannot go into a group (a dragged group, groups do not nest) goes before or after the whole group, by the half of its block the probe is in, over its header or any member row. Before, every member row refused and the gap closed. - A dragged group's header, not the tall card's centre, decides the drop. - A refused place keeps the last open gap instead of springing it shut and dimming the card, so rows stop jumping during the drag. * test(layout): a divider drag keeps one daemon command in flight Adds GestureCommandCoalescer and its tests: 125 live values while one command is in flight send the first and the newest only; the ended value goes last; a failed live value with a newer one waiting is superseded. * fix(layout): stop flooding the daemon during divider and column drags NIGHTLY sent one set-viewport-pane-width per mouse move (~125/s); each timed out at 2 s and every other command (pane and tab moves, saves, attaches) timed out behind them. Divider and column gestures now go through GestureCommandCoalescer: one command in flight per gesture, only the newest value waits, the ended value always goes last. A failed live value with a newer one waiting no longer rolls the divider back. * scripts(cmux-next): drag-lag-live.py, column/tab/sidebar drag timing on a fleet app * scripts(cmux-next): drag-lag-live probes the daemon during drags, bigger scene * ci(nightly-next): one-command rollback of the cmux NEXT feed (#21887) * ci(nightly-next): one-command rollback of the cmux NEXT feed nightly-next-rollback.yml takes a bad build, and every newer one, off appcast-arm64.xml so the feed serves the previous signed build again. It runs in release-next on branch nightly-next, guards the appcast and R2 key like publish-nightly, checks the fallback DMG exists, refuses to empty the feed, and stops when the feed changed while it planned. docs/ci/nightly-next-canary.md maps the nightly pipeline and its holds and says what a pull can and cannot do: Sparkle never offers a lower build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(nightly): the delta lane never puts a pulled build back on the feed republish-nightly-deltas skipped its rewrite only when the live NEXT feed served a newer build. After nightly-next-rollback.yml pulls build N, the feed serves N-1 and the lane's two-item appcast would restore N. It now skips whenever the feed serves any other build. The regression cases in test_nightly_republish_delta_guard.py fail on the old guard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(nightly-next): rollback runs-on keeps a fork branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(nightly-next): the rollback writes the feed only with If-Match upload-r2-object.py --replace-sha256 HEX reads the object, requires the bytes the caller planned from, and writes with If-Match on its ETag; a changed object is not written (--conflict-exit-code). The rollback uses it instead of a public re-read, so a publication that lands between the plan and the write is never overwritten. Its summary no longer says "nothing to pull" when the plan itself failed. (CodeRabbit on #21900.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions (#21951) * cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions c5a1f90 built the update card's entrance, exit and crossfade from raw CABasicAnimation, CASpringAnimation, CATransition and CAMediaTimingFunction, so check-motion is red on feat-cmux-next (9 hits). Every duration and spring already comes from the injected MotionPolicy's tokens; Motion.set would write the model value and read the global policy instead. The 9 lines carry a motion-allow and the type doc says why. Comments only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the sidebar card's motion-allow note names what stays literal The curves and the spring's settle tolerance are literal, not tokens; say so, so the allow does not overclaim (coord-2's review of #21951). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * optchat-chief: auto-resume subagents that stop on a model or network error A subagent run that ends on an API/harness error is classified (auto_resume.rs): transient errors (overloaded, 429, 5xx, did not start) are told to continue after a 30/60/120 s backoff, at most 3 times in a row; network errors (connection lost, fetch failed, DNS) are not retried blind: a thread waits until a TCP probe of the model endpoint (the subrouter from ANTHROPIC_BASE_URL or ~/.claude/settings.json) answers, then continues. The Chief's chat gets a quiet '[id] stopped: <reason>' note; the subagent's chat shows each '[auto-resume N]' continue. A stop auto-resume gives up on is reported as usual. OPTCHAT_AUTO_RESUME=off turns it off. * optchat-chief: auto-resume agent CLIs in cmux terminals; fix clone_on_copy terminal_watch.rs: every 30 s the Chief host lists cmux terminals; a Claude Code or Codex terminal that reports 'error', or sits idle at an empty prompt with an API error as its last output, is classified as in auto_resume.rs. Transient errors get '[auto-resume N] ... continue' typed at the prompt after a backoff; network errors wait until the model endpoint answers. Working, blocked (a question) or half-typed prompts are never touched. Each event reaches the Chief chat as '[term_...] stopped: <reason>' (a notice while a continue is planned, a Chief note when it gives up). OPTCHAT_TERMINAL_RESUME=off turns it off. Also: a short reply that only mentions an error is not a stop, and the clippy clone_on_copy in workspaces.rs (a75b0c3) is fixed. * optchat-chief: module order in lib.rs (rustfmt) * test(new-tab): a visited page completes inline on Right and opens nothing (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(new-tab): a visited page completes inline again The Tab fix also dropped history rows from inline completion to match an older comment, undoing 1d8f0db. Accepting a completion only fills the field on an explicit Right or End, and Enter or Send still opens it, so a visited page completes as in Chrome. The comment now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): clear stop timer on client close (#21615) * Markdown: cmux:// workspace, pane, tab and chat links open in the app A cmux:// link in rendered Markdown did nothing or left the app: the Markdown file page classified every non-web scheme as unsafe, Home only linked a Chief subagent's chat, and the agent pane drew only http(s). - One opener, CmuxAppLinks (was ChiefSubagentLinks): a workspace, pane, tab or session link in the `cmux` scheme or this build's scheme, or this Chief's subagent link, runs link.open. Terminals and pages reach it via LinkRouter.appLink. - Markdown file page: `cmux://...` is link kind "app" (hover: "Opens in cmux", 21 locales); cmux.markdown.openLink kind "app" opens it in the app or refuses, never the system. - Home: URL.isCmuxAppLink draws and routes the same links to onAppLink. - Agent chat: replies draw cmux app links; a click after a real gesture goes to the app opener, never NSWorkspace. - javascript:, file:, data:, vbscript:, ssh: and malformed ids stay text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next palette: Go to Workspace (Cmd-P) searches groups, panes, tabs and agent sessions Cmd-P now lists sidebar groups, panes and every tab (terminal, browser, markdown, file, agent chat) next to the workspaces once you type, each row with its kind and its parent workspace and group. Titles, cwd, URL, group names and session ids are searchable; whole-title and prefix matches rank first, then the recently used. - Picking a group shows its first workspace, expanding the group when collapsed (WorkspaceGroupFocus, shared with Next/Previous Workspace Group). - Picking a pane or tab shows its workspace and focuses it (pane.focus, revealTab as Search Tabs). - Cmd-K in the palette shows the row's Actions menu; agent rows offer Copy Session ID: acp:<session id> for acpmux chats (what cmux agent message takes), the harness session UUID for Claude Code / Codex terminals. Handle format documented in skills/cmux-acpmux/SKILL.md. * acpmux: require version evidence for already-current updates (#21398) Replays #21398's change onto current feat-cmux-next as one commit. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cx-dgsp follow-ups: scope-bound wire tickets, hold a refused feed token (#21725) * test(api): the forwarded wire upgrade carries no credential A native header upgrade with stray bearer.x and ticket.y subprotocols reaches UserDO with no Authorization header and only cmux.wire.v1. Green on the current strip; red when wireCredential keeps bearer. or forwardHeaders keeps Authorization. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(api): a wire ticket opens only the scope it was minted for (red) POST /v1/wire/ticket takes {scope}; a feed ticket must not open the user socket, a refused try spends it, an unscoped ticket is a user ticket and an unknown scope mints nothing. Fails now: the feed ticket opens /v1/wire/user (101). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cloud-client): openWire mints its ticket for the scope it opens (red) Fails now: POST /v1/wire/ticket goes out with no body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(api): bind a wire ticket to the socket scope it was minted for POST /v1/wire/ticket takes {scope} (user|team|feed|cloud|conv|mux; no body or no scope means user, which the dashboard panel and any client minted before this send). The ticket record keeps the scope; the router entry still spends a ticket on any path, and wire() refuses one of another scope with the usual 401. openWire and the dashboard's wireCredential name their scope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a 401 on the feed wire holds the refused token (red) CloudFeedSource takes an internal Connect seam and reconnect Backoff so the loop runs against a fake; the socket session throws Unauthorized when the upgrade's response is 401. The test fails now: the loop opens a socket for every repeat of the refused token (a, a, a, b), not a then b. Compile-only on this Linux host; it runs in CmuxNextAppTests on macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): stop reconnecting the feed wire with a token the server refused A 401 on the upgrade fed the outer reconnect loop, which opened a socket with the same token every 500 ms..30 s. The loop now remembers the refused token, reports a disconnected reason once, and opens no socket with it again: it asks the token provider on the Backoff schedule (no request reaches the server) until it returns another token. start and reset still restart the loop on a sign-in or account change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(api): the expired-ticket test mints a feed ticket for the feed socket With scope binding, an unscoped (user) ticket on /v1/wire/feed is refused for its scope, so the test no longer reached the expiry check. Red when WireTicketDO.spend ignores expires_at. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the Desktop Wallpaper tile shows the desktop, never a broken image macOS can report a desktop picture that is gone (a deleted file in /tmp), a folder it rotates through, or a .madesktop description. The Settings thumbnail and the window backdrop loaded that URL as is, so the tile drew the webview's broken-image mark and choosing it showed nothing. DesktopPicture resolves the reported URL to a picture that decodes: the file, a picture in the folder, the still a description names, or else a picture of the desktop fill color. The picker swaps a thumbnail that fails to load for an empty framed box. * Home dock: pinned column kind (pinned-dock-v1) Lawrence 2026-10-18: "I should not be able to close Home inside the Home thing ... I should not be able to create more tabs in the Home thing unless I explicitly enable it." Daemon (cmux-tui): a dock column may be pinned. Its first tab stays (no close, move out or reorder away from the first place) and it takes no other tab unless its allow_tabs is on (column.update {allow_tabs}). The column is never removed, undocked or unpinned. Enforced on every path (resource ops, JSON-lines, layout undo, terminal tab creation before the spawn) with reason_code dock-column-pinned. set-column-dock takes pinned; column.update takes pinned and allow_tabs. Spec, docs, bindings updated. App: Home pins its left chat dock on connect (page tab first). Home's tab shows no close button, the strip no new-tab button while the column takes no tabs, Cmd-W keeps Home's tab, new agent chats open beside a pinned dock, and a refused close says "Home stays open in its column." * cmux NEXT: compact attachment strip in the composer (#21739) * test(acpmux): the attachment strip is compact Leo 2026-10-18: pasted screenshots took ~100 px off the composer. One row of 64 px tiles 6 px apart, 8 px under the composer's top, the text 6 px under it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): compact attachment strip, like the Claude desktop composer 64 px tiles (from 80), a 6 px gap, an 8 px top inset, and the prompt starts 6 px under the strip instead of 15. The strip adds about 78 px, not ~100. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): shell field follows the compact strip; tighten the gallery budget Review: in shell mode under attachments the field and glyph kept the 15 px inset, so typing ! moved the text 9 px. The attach-screenshot gallery budget still allowed the old 96 px row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acpmux): wait for the thumbnails to load instead of decode() CI: decode() rejected while a thumbnail's source was swapped for its copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: the popup address field draws no focus ring (#21963) fa8b3fc made the popup URL label selectable without focusRingType = .none, which turns check:text-focus red on every webviews job. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * composer: picking another provider's model keeps the typed prompt (#21937) * test: a harness switch keeps the typed prompt (red) * composer: picking another provider's model keeps the typed prompt through the harness switch * composer: a chat's own saved draft wins over a carried prompt (review) * fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵ (#21870) * test(acpmux): a running turn's empty prompt teaches Return and ⌘Return Leo 2026-10-18: like Claude's "↵ to send, ⌘↵ to queue for later", the empty prompt mid-turn says "↵ to queue, ⌘↵ to steer" (or interrupt, for an agent that cannot steer). The Quick Composer keeps "Queue a follow-up". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵ Mid-turn the empty prompt says "↵ to queue, ⌘↵ to steer" (or "to interrupt" when the agent cannot take steering), as Claude's composer does. The Quick Composer keeps "Queue a follow-up", since its ⌘↵ opens the window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acpmux): an attachment-only prompt mid-turn names only the queue key Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(acpmux): drop the ⌘↵ hint with only attachments, match the Steer button's verb ⌘Return needs typed text, so an attachment-only prompt mid-turn says only "Queue a follow-up". The es, fr, it, ja, ko and uk hints now use the Steer button's own verb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(acpmux): say when the queued placeholder still shows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: schema doc names peer masking and the lane error cut (#21924) * docs(acpmux): the schema names peer masking and the lane error cut The SessionSummary lane note still said every other field stays raw; since #21871 a peer daemon reads them masked, and since #21799 the lane error is cut to 3072 characters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(acpmux): raw for every client but a proven peer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: every markdown viewer is read-write; Cmd-=/-/0 text size and a default size setting Root cause: a markdown file opened by cmux open, an agent or a link (not the user's own Open File...) was writable only inside a files.roots folder. The roots setting is empty by default and never holds home, so viewers opened from the Home workspace (and any workspace) came up read only with an "outside the workspace" note. - Markdown pages are writable for every document they show; only a real reason keeps one read only (not UTF-8, binary, not writable, or a chat transcript the host opens read only), and the page names the reason. The code editor keeps its root rule. - The markdown page handles the zoomIn/zoomOut/zoomReset page commands the app already sent: one pixel per step (8-40) in rich and source mode, Cmd-0 back to markdown.font.size. Cmd-Shift-= is a Zoom In alias. - Settings > Appearance > Markdown Viewer > Default Font Size (markdown.font.size, 16, 8-40), localized. Co-Authored-By: Claude <noreply@anthropic.com> * fix(home): pasted pictures are small thumbnails in a row in the composer The vendored MessagesLab compose strip copies macOS 27 Messages: every attachment is a 177 x 118 pt tile stacked top to bottom above the text. Two pasted screenshots made the field ~280 pt tall and pushed the text line to the bottom. Images are now aspect-fit in 128 x 64 pt, files are 200 x 52 pt pills, and tiles flow left to right and wrap at the field's right edge. Tests: ComposeAttachmentLayoutTests (MessagesLabHome). * test(home): qualify Attachment (Swift Testing has one too) * cmux-next: page strings tables become build output (#21970) * test(webviews): strings tables must not be tracked Red on feat-cmux-next: every table gen-strings.mjs writes is committed, and none is ignored (#21946). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: page strings tables become build output (#21946) The generated strings tables (webviews/src/**/generated/strings.json, the diff page's per-locale tables and loader, the home-channels pane table) are no longer committed. bun install (postinstall, best effort), the webviews test preload (only stale pages) and every bundle build (strict) write them from the checkout's xcstrings catalogs and settings schema. Committed copies conflicted in every pull request that changed a catalog or the settings schema, and the PR autofix could rebuild one from a stale schema and drop another branch's labels (#21746). A table made from the tree it sits in can do neither. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: merge rules and atomic writes for every strings output (#21946) The diff page's locale tables and loader and the home-channels pane table are build output too: route them through cmux-generated-v1 and next_batch's WEB_GENERATED, so a branch from before the change that edited one catches up instead of stopping on a modify/delete conflict. gen-strings writes through a temporary file (parallel test preloads), and --best-effort skips a page whose catalog or schema is missing instead of failing bun install. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at f2ef8f4 - regenerated schemas/settings-export/settings-schema.sources.sha256 - vp fmt webviews/scripts/pages/gen-strings.mjs - vp fmt webviews/test/strings-build-output.test.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39205550635 --------- 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: a new terminal tab spawns at its pane's grid, so its first frame is final The Mac's new-tab request sent no size. The daemon then spawned the PTY at the grid of whichever terminal reported last, anywhere (client_sizing_state.rs creation_size), the shell printed its first prompt at that width, and the pane snapped when the view's first report resized it. newTerminalTab now sends cols/rows (NewTerminalGrid): the fitted grid of the terminal the pane shows (Ghostty's own fit of the same content host), else the content host size, backing scale, a live terminal's cell size and the configured padding through Ghostty's formula (TerminalGridEstimate; Cmd-T's New Tab page, a page or agent tab). A zoomed terminal does not count. With neither known the daemon's fallback applies as before. docs/shared-terminal-sizing.md: a Creation size section (who sizes a new terminal, and why a later attach never draws a wrong frame for others). * cmux NEXT: NewTerminalGridTests builds its padding from the public default * perf-10x daemon: request-latency bench (raw, 10 clients, CLI; 1 and 200 terminals) * cmux-next: clear five base reds in the cmux-next checks lane (#21981) The ErrorJournal (1597dc9) and browser popup (fa8b3fc) commits left five checks red on feat-cmux-next, so every PR into it fails "cmux-next checks" and its web lane skips its tests. Comments and baselines only, no behavior change: - Main-thread concurrency: the harvest loop runs in a detached utility task and the flush delay in the ErrorJournal actor's task, so neither is on main; reviewed concurrency-allow and wakeup-allow comments. - No literal state roots: the app's ~/.acpmux/daemon.log is only read; a keep row in the baseline. - Package conventions: lint:allow on BrowserPopupWindowGeometry (pure geometry). - Type scale: BrowserPopupPanel.swift has no raw font sizes left; drop its row. - Text focus: the popup address field sets focusRingType = .none (was #21963). Motion tokens (SidebarCardTransition) stays with #21951 for its owner. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cx-ncc.104: Debug toggle for the agent pane's in-session status (agent.sessionStatus) (#20953) Recut of #20953 onto the current feat-cmux-next as one commit: the In-session status Debug toggle, its sessionStatus page event, and useSessionStatus() for the plan and recap cards. The base merge kept both sides of the tunables list, the view's observations and the page host's events (the sidebar preview variant landed meanwhile). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * acpmux: route/list says which routes serve the session's family (#21852) * test(acpmux): route/list names a session's family and which routes serve it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(acpmux): route/list says which routes serve the session's family With a sessionId, _acpmux/route/list now returns the session's family and a serves flag on each route (Route::serves), so the composer's Account menu can list only the routes that can run this chat without copying that logic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * cmux-next: tunable registries list one entry per line (#21972) * cmux-next: tunable registries list one entry per line (#21946) AgentPaneTunables.all and SidebarTunables.all were single lines, so every pull request that added a tunable conflicted with every other one there (14 open PRs on AgentPaneTunables, 4 on SidebarTunables). Each entry now has its own line in alphabetical order, so two additions insert different lines and merge cleanly; TunableCatalog.all lists one module per line. Debug Settings shows the agent-pane and sidebar tunables alphabetically; nothing else depends on the order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the TunableCatalog list as it was: CmuxNextApp may not grow The one-per-line TunableCatalog added 20 source lines to CmuxNextApp, which check-app-size.sh refuses. The conflict hotspots are the AgentPaneTunables and SidebarTunables lists, which live in their own targets and stay one per line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * test(next): cover dictation auto-send prompt routing (#21169) * test(next): cover dictation auto-send prompt routing * fix(next): satisfy dictation test formatting --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Co-authored-by: Lucas Ribeiro <lucascamribeiro@gmail.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
























c5a1f90 ("Sidebar update card: animate coming in, going out and message changes") built the card's entrance, exit and content crossfade from raw
CABasicAnimation,CASpringAnimation,CATransitionandCAMediaTimingFunction. Since thenscripts/cmux-next/check-motion.shhas failed with 9 hits inSidebarCardTransition.swift, which turns "cmux-next checks" red on feat-cmux-next and every PR into it. The chat-web lane reported it.Every duration and spring in that file already comes from the injected
MotionPolicy's tokens (.fadeIn,.fadeOut,.crossfade,.appear). The raw objects are there because the card's animations are presentation-only, andMotion.setwrites the model value and reads the globalMotion.policy. Porting the file to the Motion helpers would change those semantics and the easing curves, so that's the owner's call and needs a build to check. This PR only marks the 9 lines with the script's reviewed-exception comment,// motion-allow:, and adds the reason to the type doc. It changes comments only; the compiled code is identical.Verification
bash scripts/cmux-next/check-motion.shlists the 9 hits at the feat-cmux-next tip and printscheck-motion: okwith this change.bash scripts/cmux-next/tests/check-motion.test.sh: ok.Changelog
none
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Fixes
scripts/cmux-next/check-motion.shfailing with 9 hits by marking the sidebar card's raw Core Animation objects as reviewed motion exceptions.SidebarCardTransition.swiftnow carries a// motion-allow:comment, with the reason documented in the type doc.CABasicAnimation,CASpringAnimation,CATransition, andCAMediaTimingFunctionobjects stay, sinceMotion.setwould write the model value and read the global policy; durations and springs come from theMotionPolicytokens, while the easing curves and the spring's settle tolerance remain literal.Written for commit c551443. Summary will update on new commits.