Skip to content

base red: warm the dev server in three agent pane browser tests - #20873

Merged
teamleaderleo merged 1 commit into
feat-cmux-nextfrom
op-next-cursors/warm-vite-base-red
Oct 15, 2026
Merged

teamleaderleo merged 1 commit into
feat-cmux-nextfrom
op-next-cursors/warm-vite-base-red

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes a base red. check:browser-lanes (#20733) requires every browser test that starts a Vite dev server to call warmViteServer(vite, page) once it listens. Three agent pane tests landed after #20733 without that call, so web / react-apps-check is red on feat-cmux-next for every PR:

This adds the call to all three.

Testing

On sbx:

  • bun run check:browser-lanes:
    • red on base, which lists these files;
    • green with this change: "Browser test lane imports checked."
  • CMUX_BROWSER_TESTS=1 bun test on the three files: 8 + 8 tests pass, 0 fail.
  • bunx vp check is clean.

Changelog

none

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Fixes the failed check:browser-lanes by warming the Vite dev server in three agent pane browser tests that didn't call it.

Written for commit 73388c1. Summary will update on new commits.

View guided diff Turn on auto-fix

check:browser-lanes (#20733) requires warmViteServer after listen; #20752,
#20780 and #20785 landed tests without it, so react-apps-check is red on base.

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

coderabbitai Bot commented Oct 15, 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: 31906ef9-90c3-4c3c-91b3-35aec6c9e0dd

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
  • Autofix · 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-fhoq0 created for this PR by the cmux coordinator.

@teamleaderleo
teamleaderleo merged commit 201ad73 into feat-cmux-next Oct 15, 2026
95 checks passed
@teamleaderleo
teamleaderleo deleted the op-next-cursors/warm-vite-base-red branch October 15, 2026 04:06
teamleaderleo added a commit that referenced this pull request Oct 15, 2026
#20884)

#20592 landed after #20873 without warmViteServer, so check:browser-lanes is
red on base again.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 15, 2026
#20880)

* cx-tgf4h red: cmux chief -p under ACPMUX_AGENT_LAUNCH=deny fails at once with a typed refusal

* cx-tgf4h: the Chief says at once that agents are disabled in this build session

With ACPMUX_AGENT_LAUNCH=deny (the nx-remote gui/input default since HQ
#2130) or CMUX_AGENTS_DISABLED=1, no Chief turn can start an agent.
`cmux chief -p` started a daemon and a brain and waited 240 s for a reply
that could not come.

- cmux-tui-core agent_launch: one test of the kill switch (acpmux
  launch_policy.rs), the reason agent_launch_disabled.
- `cmux chief` (pipe and chat) refuses before it starts or sends anything:
  operation.failed, details.reason agent_launch_disabled, exit 1.
- The daemon's supervisor starts no Chief brain; chief.engine.* and
  chief.stop answer the typed refusal at once.
- optchat-chief host does not start (logs why, exit 0).
- Home: the local Chief conversation's notice says agents are disabled;
  the engine panel maps the typed refusal (localized, all Home languages).
- Every Chief proof script refuses at once under deny and names
  `nx-remote --allow-agents`.

* test: code pages follow the terminal font; font variables resolve

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

* cx-tgf4h review: forward chief control to a running brain first; daemon-side deny test; engine/stop CLI text; guard before side effects; fmt

* acpmux tests: every acpmux process a test starts gets a hermetic environment (cx-s8wux)

One helper, tests/support/daemon_env.rs, starts the acpmux binary for every
integration test: env_clear, a bare PATH (python3 plus named host tools,
then the system directories), a scratch HOME, and ACPMUX_AGENT_LAUNCH=deny
unless the test drives a stand-in agent (Agents::StandIn keeps the bare
PATH). The 26 test files that started the binary with the host environment
use it; tests/hermetic_daemon_guard.rs refuses a test file that names
CARGO_BIN_EXE_acpmux anywhere else.

Root cause of cx-w014j: a fleet host's PATH holds real codex/claude, which a
test daemon discovered and ran (probes, sign-in checks, auto-updates).

* cx-tgf4h: fmt and clippy

* acpmux tests: the hermetic HOME is <scratch>/home, never a chat's folder

* acpmux tests: review fixes for the hermetic environment (cx-s8wux)

python3 links the interpreter itself (sys.executable), not a version
manager's shim; stale tool links from an earlier run are replaced; the guard
also flags daemon_env::bin() outside a listed use; the live codex test probes
only codex; codex_bridge_config's discovery test runs with launches denied.

* acpmux tests: router_install_secret starts the router through daemon_env (cx-s8wux)

* fix: code pages draw in the terminal's font; agent pane defines --font-mono

The diff, markdown and code editor pages were written to follow the terminal font
(appearance.ts, editorFont), but no cmux NEXT host ever sent it, so code always drew
in Menlo. Every page theme now carries the terminal's family (cmux.json
terminal.fontFamily, else the Ghostty config's font-family), resent when it changes.

The agent pane's mono text read --font-mono, which only Tailwind's theme layer
emitted because a source file happened to name it; conversation.css defines it.

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

* cmux-next: fix two Chief profile relay base reds (concurrency check, Release compile crash) (no bead) (#20876)

* cmux-next: mark the Chief profile relay retry loop as bounded (no bead)

check-concurrency flags its while true as a loop that can spin. It retries
once, only after a lost connection, and every other error throws.

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

* cmux-next: nonisolated deinit for PageCallDeadline.Once (no bead)

The Release compile crashes swift-frontend 6.3.3 in EarlyPerfInliner on
the isolated deinit of this main-actor generic class (exit 65, no error
line), the same crash #20408 fixed elsewhere.

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

---------

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

* fix(cmux-next): the Chief profile relay's retry is a two-attempt for loop, not while true with a wakeup-allow (cx-ebm.59.5)

* cmux-next sidebar perf round 3: Release-build hitch bench with real wheel input; O(1) hover-card hit

- scripts/cmux-next/sidebar-rows-perf-release.py: runs in a Release tagged app (no debug.* methods) inside
  nx-remote --needs input: CLI workspaces (50 with a terminal, 950 empty), HID-tap wheel events, Animation
  Hitches per gesture, A/B of two apps in one job (side by side, interleaved), traces and the recorder's ktrace
  files removed after each export, PTY count logged.
- SidebarListView+HoverCard: the hover-card hit reads the list's row dictionary instead of
  SidebarModel.isPlaceholder, an O(workspaces) section walk on every scroll frame (7-12% of main-thread samples
  while scrolling 1,000 rows in Release).

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

* Channels: a primary or danger button keeps its fill under the pointer (a soft ring shows the hover); gallery play primary-hover

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

* Channels gallery: primary-hover asserts the hover ring and the unchanged fill; a budget with a reason for the Create frame

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

* cmux-motion: Chrome tab strip tween (200 ms easeOutQuad, restart from value), tabStrip geometry tokens, damping <= 0 takes the fallback (hq-1d, no bead)

Additive: MotionTween {TabOpen, TabClose, TabMove}, TweenCurve::EaseOutQuad,
ease_out_quad, TweenParameters, TweenValue (f64 core: retarget restarts the
duration from the current value with no velocity; the same target does not
restart), Tween (f32, token-driven), MotionPolicy::tween (0 under speed off,
Reduce Motion, or tabOpen/tabClose with ui.animations.newTab off),
TabStripGeometry (design-tokens.json motion.tabStrip: max 200, open/close
18, min 56 active / 32 inactive / 64 pinned, reorder 16 x width / 200,
closing mode +40 below / +60 trailing / 0.3 s). cmux-app-ffi ABI 2 exports
cmux_motion_tween_{base,seconds,retarget,step}, cmux_motion_ease and
cmux_motion_tab_strip_geometry. SpringParameters::finite_or now treats a
damping fraction <= 0 like NaN (hq-4e nit). The parity corpus example
prints tween paths (60 Hz: 12 frames for 200 ms).

* fix: read the font from the files the Ghostty config loaded, includes too

Review: a font-family in a config-file include won in the terminal but not on pages.
Read the runtime's loaded files (with includes, in load order) instead of guessing
paths, repaint after the last override is set, and fix a stale doc comment.

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

* acpmux: record a session's git branch and HEAD at start (hq#1920) (#20840)

* test(acpmux): record a session's git branch and head at start

A session should keep its folder's branch and HEAD commit as they were at
session/new, and a fork its own folder's state at fork time (hq#1920), so
agent spend can be joined to the pull request a session produced. These
fail today: neither the saved meta nor _acpmux/info carries gitBranch or
gitHead.

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

* feat(acpmux): record a session's git branch and head at start

session/new and session/fork now store the cwd's checked-out branch and
full HEAD commit in the session meta (gitBranch, gitHead), so a session
can later be joined to the pull request it produced (hq#1920). The values
are read once, as the session starts, from the repository's own files
(HEAD, loose refs, packed-refs, a linked worktree's gitdir and commondir),
never a git process, and off the async runtime. A detached HEAD records
only the head; a folder outside a repository records neither; a lookup
that fails never fails the session. A fork reads its own folder at fork
time instead of copying the parent's. _acpmux/info carries both fields.
Old session.json files load unchanged.

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

* test(acpmux): git state skips non-files, bad branch names and missing folders; follows symlinks

Review of #20840: a FIFO HEAD hung session/new, a symlinked folder was walked
lexically, a missing fork folder took its parent repository's state, and an
invalid ref name was stored as the branch. The test git also runs without the
machine's global or system config.

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

* fix(acpmux): git state reads only small regular files, the physical folder and valid ref names

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

---------

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

* cx-tgf4h: keep CmuxNextApp line count (App size cap)

* acpmux: a pooled agent host no longer spins on Linux reading its own record (cx-7z8yx)

The record watch used notify's inotify backend, whose watch mask always
includes open, close-write and modify, and ran its callback on every event.
The callback reads the host record; on Linux that read queued an open and a
close in the watched directory, which ran the callback again. Every pooled
host spun at 100% CPU (about 200,000 read calls a second).

Linux now has its own inotify watch, like the macOS kqueue watch: a mask of
entry changes only (create, delete, moved from/to) and the directory's own
delete or move, one thread in poll with no timeout, an eventfd to stop it.
A read of the record never queues an event. The notify fallback (other
platforms) ignores access events. macOS is unchanged.

Behavior test (tests/host_lifetime.rs, Linux): a real daemon pools a host;
idle for 3 s it makes fewer than 100 read calls and 30 CPU ticks (before:
599,042 reads, 298 ticks), a rename rewrite of its record keeps it, and the
record removed ends it.

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

* cmux-tui smoke: sidebar drag checks the drawn sidebar document order

Since sidebar-v2 S6 the TUI draws the daemon's sidebar document, where a new
workspace goes to the top (workspaces.newPlacement default), and a workspace
drop is one sidebar.move that changes the document only. The smoke still
assumed the list-workspaces order: it dragged the drawn top row (the new
workspace) below the original, which the product did, and then read
list-workspaces, which a sidebar.move never changes.

The smoke now reads the order from sidebar.get, checks that the rail draws
it, drags the top row below the second (a real reorder), and drags again when
needed so the original workspace ends below the new one.

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

* PR dock chips; tooltips only where nothing else names the control (#20375)

* test: no tooltip on an element whose text shows

Red on base: 105 elements with visible text carry title/data-tooltip.
Command: bun test test/tooltip-rules.test.ts

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

* fix: PR dock chips; tooltips only where nothing else names the control

The pull request dock's bars become content-sized chips (icon, #N, repo, title cut off at
360 px) with the dismiss button inside and no tooltip. Across the pages, a row, chip, link,
path or thought whose text shows carries no title tooltip any more; tooltips stay on
icon-only controls, shortcuts and text shown nowhere else (why a control is disabled or
failed, who reacted, policy detail), each marked tooltip-allow. Tooltips wait the native
hover delay (about a second) and show at once when moving straight on to the next one.

Green: bun test test/tooltip-rules.test.ts

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

* fix: review of tooltip audit

Keep the PR dock's state colours, drop four more tooltips the lint now finds inside
components (a setting's summary, the branch and folder pickers, a video), let a click or
scroll end the quick next-tooltip window, and move two tests to the no-tooltip rule.

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

* test: Backdrop Art's line has no tooltip

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

* chore(next): PR autofix at 047c247

- vp fmt webviews/src/pages/history/HistoryPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38502564051

* test(mock): the worked chat opens its pull request, so mock mode shows the PR dock

Captures of the agent pane in a real window (--showcase runs the in-page
mock) now show the pull request dock.

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

* test: the PR dock takes its own space; the transcript ends above it

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

* chore(next): PR autofix at 39f3ca9

- vp fmt webviews/test/ime-composition-keys.test.ts
- vp fmt webviews/test/new-tab-omnibar-pointer.test.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38567629461

* chore(next): PR autofix at c7cb261

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38592980576

* fix: a channel image keeps its name tooltip (the name shows only when it fails)

Base added title={part.name} on channel image attachments (AttachmentViews.tsx).
A loaded image shows no name, so the tooltip is its only label; mark it with
tooltip-allow. tooltip-rules.test.ts: red before, green after.

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

* chore(next): PR autofix at f221864

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38633116142

* fix: keep the tool card scope hint and Steer shortcut tooltips

Both explain something shown nowhere else, so they stay under tooltip-allow.

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

* chore(next): PR autofix at 022cc8e

- vp fmt webviews/src/pages/home-channels/cloudHome.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38647981824

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* ci: nightly-next recovery initializes the notices submodule before continuing accepted submissions

The recovery job's checkout had no ghostty-next submodule, so the bundle
notice check that notarize-nightly-dmg.sh runs after Apple accepts failed,
and run 38669958906 skipped five accepted builds as 'Apple did not accept'.
Initialize the submodule like the signing job does, and make the skip notice
say that a post-acceptance check can also be the cause.

* ci: the cmux NIGHTLY-identity job also initializes the notices submodule

Run 38669958906's publish-nightly-identity-legacy job saw Apple accept,
then failed the bundle notice check for lack of ghostty-next and retired
the accepted submission of run 38609024986.

* agent pane: progress and stop for a running Claude subagent or workflow (cx-liswe) (#20718)

* test: a running subagent or workflow shows what it does and what it has spent

Red on base: both rows read only "Running" (bun test
test/subagent-progress.test.tsx).

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

* webviews: a running subagent or workflow shows what it does and what it has spent

The subagent fold keeps acpmux's subagent_progress fields (action, tokens,
tool uses, a workflow's agents done of started), and the transcript's
subagent row adds them to its status line through one shared helper
(subagentProgress.ts) the summary list and the Background tasks pane can use.
Three plural strings, translated for every pane locale.

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

* test: a running subagent row has a stop button

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

* feat: stop a running Claude subagent or workflow from its row

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

* chore: restore the catalog's base order after the merge

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

* test: stopping a subagent leaves its row closed, and a refused stop says so

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

* fix: a subagent's stop button waits for Claude and says when the stop failed

The button is off while Claude has the request and until the subagent
ends; a refused or unanswered stop (10 s) turns it into "Couldn't stop
<name>" and it can be tried again. The pane no longer drops the error.
Also moves the stop wiring above showSubagent's doc comment and corrects
two comments.

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

* style: format the subagent progress test

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

* fix: stop rejects without English the pane would never show

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

* chore: restore the catalog's base order after the merge

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

* chore(next): PR autofix at 2fe6cc4

- vp fmt webviews/src/pages/home-channels/HomeChannelsPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38637059713

* test: the agent pane relays a subagent stop for its chat (cx-liswe)

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

* fix: the agent pane may stop a subagent of its chat (cx-liswe)

Adds _acpmux/subagent_stop to the pane's method allowlist: session-scoped,
params sessionId and subagentSessionId, no gesture (it stops work, like
_acpmux/kill). Without it the host refused every stop click.

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

* fix: mirror the subagent stop into the shared pane policy (cx-liswe)

The Swift allowlist took _acpmux/subagent_stop; policy.json, its parity
source for Rust hosts, gets the same request, session scope and params,
with cases for an in-scope stop, another chat and an unknown param.

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

* gallery: a light window with no theme named renders light (#20794)

* test(gallery): a light window with no theme named should show the light default

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

* fix(gallery): a light window with no theme named shows Apple System Colors Light

The gallery defaulted the theme to the dark side of the app's default pair
whatever the window appearance, so colorScheme=light (or Appearance: Light)
rendered every stage in dark colors under a light media query. The default
now follows the appearance, as the app's does with no theme set.

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>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* Channels view: gallery plays for a message link with no link read (red)

A Cloud conversation has no link resolver (G4), so the Messages view's switch hand-off
#/conversation/<id>/message/<id> showed an error. Two plays: a thread reply and a timeline
message, opened through the store's openLink with an owner that has no resolver. cx-hnmbt

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

* Channels view: open a known conversation's message link without the owner's link read

When conversation-link-resolve fails (a Cloud conversation, an older daemon) and the page knows
the conversation, it opens it, pages the timeline until the message shows, opens its thread when
it is a reply, and marks it. The Messages view's switch hands off Cloud selections this way.
cx-hnmbt

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

* Channels view: format parseConversationLink (vp fmt)

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

* Channels view: link fallback review follow-ups

Ids in a known conversation's link may hold '-' (the gallery's sample ids); the scheme check
follows the daemon (cmux[-<tag>], any case); the fallback runs only for a Cloud conversation or
an owner without a link read, so a refused local link (a deleted message) still shows its error.
cx-hnmbt

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

* acpmux: host_lifetime idle test cleans up from the start and never signals a reused pid (cx-7z8yx review)

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

* cmux-tui: move the build identity into a leaf crate so an edit no longer recompiles cmux-remote

cmux-remote's build script hashed the dirty source tree into
CMUX_TUI_BUILD_IDENTITY, so every edit in the workspace reran it and
recompiled cmux-remote and every crate above it (about 8 s of a 12.6 s
one-line edit loop on rbx). The same build script now lives in
cmux-build-identity, which only cmux-tui reads; cmux-remote takes the
identity as an argument (SshBootstrapConfig::defaults,
pinned_linux_payload). The identity value, its inputs and format, and
every skew and SSH re-bootstrap comparison are unchanged.

* test: warm the dev server in the Claude reasoning default browser test (#20884)

#20592 landed after #20873 without warmViteServer, so check:browser-lanes is
red on base again.

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

* cmux-next: frame-strip report as an NSWindow method, not a namespace enum (no bead) (#20887)

The package conventions lint fails every PR on the new all-static public
enum WindowFrameStrip (cx-me3xd). The report reads its window, so it is an
extension on NSWindow; same body, same report.

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

* Home channels: the run card is an inline disclosure (no frame, steps on an indented rail)

The live and done run cards under a Chief's reply lose their box: "Working
for" / "Worked for", the step count, cost and Open sit inline under the
message, and the opened steps hang on a thin rail under the status mark. The
narrow rules stay: the first line never wraps, and below 480 px of card width
the step count and cost move under it with no leading separator.

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

* Home channels: the run rail and columns follow the author's picture

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

* Home channels: the run sheet keeps its error line; run card columns in logical properties

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

* Revert "cmux-motion: Chrome tab strip tween ..." (8a3ee62) until the app-ffi release App 403 is fixed (run 38682698310) (hq-1d, chief go 2026-10-15, no bead)

The release App could not publish cmux-app-ffi-854febb26527 (HTTP 403 on
POST /releases), so the app FFI pin check stays red on the tip. The tween
re-lands with the publish and repin after the App is fixed.

* test(ci): nightly jobs that run the license check must init ghostty-next (#20893)

* test(ci): nightly jobs that run the license check must init ghostty-next

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

* fix(ci): nightly recovery initializes ghostty-next before the license check

Apple accepted, stapled and launch-tested each recovered nightly-next build,
then verify-app-bundle-licenses.sh failed on the missing
ghostty-next/build.zig.zon and the build was skipped as not accepted.

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

---------

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

* cmux-next: terminal-face repaint lives in DesignSettings, not the App target

Keeps CmuxNextApp under its size cap: setting either terminal family
repaints pages when the face the terminal draws in changed.

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

---------

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
Co-authored-by: safe-push <safe-push@cmux.local>
teamleaderleo added a commit that referenced this pull request Oct 15, 2026
#20759)

* test: the strip scrollbar's thumb stays above a browser page

A Chromium page at the bottom of the column strip is a child window above
the scrollbar band, so it hid the thumb and took its clicks (cx-6so.44,
dock-column.md Known gaps).

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

* fix: the strip scrollbar's thumb stays above a browser page

While shown, the thumb's band is an occluder of the window's overlay
host, so a Chromium page under it leaves the thumb showing and its clicks
to the bar. Updates dock-column.md's known gaps: reveal under an overlay
and the strip clip were already fixed.

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

* test: a hidden screen's strip scrollbar leaves no hole in a browser page

Review of #20759: a screen switch hides the screen's view, not the bar,
so the old screen's thumb stayed an occluder and the new one's never came
back.

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

* fix: a hidden or sliding screen's strip scrollbar keeps its occluder current

The thumb's occluder now follows an ancestor's hide and unhide
(viewDidHide/viewDidUnhide), and each screen's origin as the screen switch
moves it (applyScreenFrames).

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

* cx-tgf4h red: cmux chief -p under ACPMUX_AGENT_LAUNCH=deny fails at once with a typed refusal

* cx-tgf4h: the Chief says at once that agents are disabled in this build session

With ACPMUX_AGENT_LAUNCH=deny (the nx-remote gui/input default since HQ
#2130) or CMUX_AGENTS_DISABLED=1, no Chief turn can start an agent.
`cmux chief -p` started a daemon and a brain and waited 240 s for a reply
that could not come.

- cmux-tui-core agent_launch: one test of the kill switch (acpmux
  launch_policy.rs), the reason agent_launch_disabled.
- `cmux chief` (pipe and chat) refuses before it starts or sends anything:
  operation.failed, details.reason agent_launch_disabled, exit 1.
- The daemon's supervisor starts no Chief brain; chief.engine.* and
  chief.stop answer the typed refusal at once.
- optchat-chief host does not start (logs why, exit 0).
- Home: the local Chief conversation's notice says agents are disabled;
  the engine panel maps the typed refusal (localized, all Home languages).
- Every Chief proof script refuses at once under deny and names
  `nx-remote --allow-agents`.

* cx-tgf4h review: forward chief control to a running brain first; daemon-side deny test; engine/stop CLI text; guard before side effects; fmt

* cx-tgf4h: fmt and clippy

* cx-tgf4h: keep CmuxNextApp line count (App size cap)

* acpmux: a pooled agent host no longer spins on Linux reading its own record (cx-7z8yx)

The record watch used notify's inotify backend, whose watch mask always
includes open, close-write and modify, and ran its callback on every event.
The callback reads the host record; on Linux that read queued an open and a
close in the watched directory, which ran the callback again. Every pooled
host spun at 100% CPU (about 200,000 read calls a second).

Linux now has its own inotify watch, like the macOS kqueue watch: a mask of
entry changes only (create, delete, moved from/to) and the directory's own
delete or move, one thread in poll with no timeout, an eventfd to stop it.
A read of the record never queues an event. The notify fallback (other
platforms) ignores access events. macOS is unchanged.

Behavior test (tests/host_lifetime.rs, Linux): a real daemon pools a host;
idle for 3 s it makes fewer than 100 read calls and 30 CPU ticks (before:
599,042 reads, 298 ticks), a rename rewrite of its record keeps it, and the
record removed ends it.

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

* cmux-tui smoke: sidebar drag checks the drawn sidebar document order

Since sidebar-v2 S6 the TUI draws the daemon's sidebar document, where a new
workspace goes to the top (workspaces.newPlacement default), and a workspace
drop is one sidebar.move that changes the document only. The smoke still
assumed the list-workspaces order: it dragged the drawn top row (the new
workspace) below the original, which the product did, and then read
list-workspaces, which a sidebar.move never changes.

The smoke now reads the order from sidebar.get, checks that the rail draws
it, drags the top row below the second (a real reorder), and drags again when
needed so the original workspace ends below the new one.

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

* ci: nightly-next recovery initializes the notices submodule before continuing accepted submissions

The recovery job's checkout had no ghostty-next submodule, so the bundle
notice check that notarize-nightly-dmg.sh runs after Apple accepts failed,
and run 38669958906 skipped five accepted builds as 'Apple did not accept'.
Initialize the submodule like the signing job does, and make the skip notice
say that a post-acceptance check can also be the cause.

* ci: the cmux NIGHTLY-identity job also initializes the notices submodule

Run 38669958906's publish-nightly-identity-legacy job saw Apple accept,
then failed the bundle notice check for lack of ghostty-next and retired
the accepted submission of run 38609024986.

* agent pane: progress and stop for a running Claude subagent or workflow (cx-liswe) (#20718)

* test: a running subagent or workflow shows what it does and what it has spent

Red on base: both rows read only "Running" (bun test
test/subagent-progress.test.tsx).

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

* webviews: a running subagent or workflow shows what it does and what it has spent

The subagent fold keeps acpmux's subagent_progress fields (action, tokens,
tool uses, a workflow's agents done of started), and the transcript's
subagent row adds them to its status line through one shared helper
(subagentProgress.ts) the summary list and the Background tasks pane can use.
Three plural strings, translated for every pane locale.

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

* test: a running subagent row has a stop button

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

* feat: stop a running Claude subagent or workflow from its row

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

* chore: restore the catalog's base order after the merge

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

* test: stopping a subagent leaves its row closed, and a refused stop says so

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

* fix: a subagent's stop button waits for Claude and says when the stop failed

The button is off while Claude has the request and until the subagent
ends; a refused or unanswered stop (10 s) turns it into "Couldn't stop
<name>" and it can be tried again. The pane no longer drops the error.
Also moves the stop wiring above showSubagent's doc comment and corrects
two comments.

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

* style: format the subagent progress test

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

* fix: stop rejects without English the pane would never show

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

* chore: restore the catalog's base order after the merge

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

* chore(next): PR autofix at 2fe6cc4

- vp fmt webviews/src/pages/home-channels/HomeChannelsPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38637059713

* test: the agent pane relays a subagent stop for its chat (cx-liswe)

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

* fix: the agent pane may stop a subagent of its chat (cx-liswe)

Adds _acpmux/subagent_stop to the pane's method allowlist: session-scoped,
params sessionId and subagentSessionId, no gesture (it stops work, like
_acpmux/kill). Without it the host refused every stop click.

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

* fix: mirror the subagent stop into the shared pane policy (cx-liswe)

The Swift allowlist took _acpmux/subagent_stop; policy.json, its parity
source for Rust hosts, gets the same request, session scope and params,
with cases for an in-scope stop, another chat and an unknown param.

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

* gallery: a light window with no theme named renders light (#20794)

* test(gallery): a light window with no theme named should show the light default

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

* fix(gallery): a light window with no theme named shows Apple System Colors Light

The gallery defaulted the theme to the dark side of the app's default pair
whatever the window appearance, so colorScheme=light (or Appearance: Light)
rendered every stage in dark colors under a light media query. The default
now follows the appearance, as the app's does with no theme set.

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>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* Channels view: gallery plays for a message link with no link read (red)

A Cloud conversation has no link resolver (G4), so the Messages view's switch hand-off
#/conversation/<id>/message/<id> showed an error. Two plays: a thread reply and a timeline
message, opened through the store's openLink with an owner that has no resolver. cx-hnmbt

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

* Channels view: open a known conversation's message link without the owner's link read

When conversation-link-resolve fails (a Cloud conversation, an older daemon) and the page knows
the conversation, it opens it, pages the timeline until the message shows, opens its thread when
it is a reply, and marks it. The Messages view's switch hands off Cloud selections this way.
cx-hnmbt

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

* Channels view: format parseConversationLink (vp fmt)

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

* Channels view: link fallback review follow-ups

Ids in a known conversation's link may hold '-' (the gallery's sample ids); the scheme check
follows the daemon (cmux[-<tag>], any case); the fallback runs only for a Cloud conversation or
an owner without a link read, so a refused local link (a deleted message) still shows its error.
cx-hnmbt

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

* acpmux: host_lifetime idle test cleans up from the start and never signals a reused pid (cx-7z8yx review)

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

* cmux-tui: move the build identity into a leaf crate so an edit no longer recompiles cmux-remote

cmux-remote's build script hashed the dirty source tree into
CMUX_TUI_BUILD_IDENTITY, so every edit in the workspace reran it and
recompiled cmux-remote and every crate above it (about 8 s of a 12.6 s
one-line edit loop on rbx). The same build script now lives in
cmux-build-identity, which only cmux-tui reads; cmux-remote takes the
identity as an argument (SshBootstrapConfig::defaults,
pinned_linux_payload). The identity value, its inputs and format, and
every skew and SSH re-bootstrap comparison are unchanged.

* test: warm the dev server in the Claude reasoning default browser test (#20884)

#20592 landed after #20873 without warmViteServer, so check:browser-lanes is
red on base again.

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

* cmux-next: frame-strip report as an NSWindow method, not a namespace enum (no bead) (#20887)

The package conventions lint fails every PR on the new all-static public
enum WindowFrameStrip (cx-me3xd). The report reads its window, so it is an
extension on NSWindow; same body, same report.

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

* Home channels: the run card is an inline disclosure (no frame, steps on an indented rail)

The live and done run cards under a Chief's reply lose their box: "Working
for" / "Worked for", the step count, cost and Open sit inline under the
message, and the opened steps hang on a thin rail under the status mark. The
narrow rules stay: the first line never wraps, and below 480 px of card width
the step count and cost move under it with no leading separator.

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

* Home channels: the run rail and columns follow the author's picture

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

* Home channels: the run sheet keeps its error line; run card columns in logical properties

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

* Revert "cmux-motion: Chrome tab strip tween ..." (8a3ee62) until the app-ffi release App 403 is fixed (run 38682698310) (hq-1d, chief go 2026-10-15, no bead)

The release App could not publish cmux-app-ffi-854febb26527 (HTTP 403 on
POST /releases), so the app FFI pin check stays red on the tip. The tween
re-lands with the publish and repin after the App is fixed.

* test(ci): nightly jobs that run the license check must init ghostty-next (#20893)

* test(ci): nightly jobs that run the license check must init ghostty-next

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

* fix(ci): nightly recovery initializes ghostty-next before the license check

Apple accepted, stapled and launch-tested each recovered nightly-next build,
then verify-app-bundle-licenses.sh failed on the missing
ghostty-next/build.zig.zon and the build was skipped as not accepted.

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>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
Co-authored-by: safe-push <safe-push@cmux.local>
teamleaderleo added a commit that referenced this pull request Oct 15, 2026
* feat(cx-gakp): unify slash commands, skills and prompts

Keep the existing Milkdown editor and its URL, mention and attachment behavior. Label ACP command sources so skills and prompts share the same searchable picker.

* chore(next): PR autofix at cade19a

- vp fmt webviews/src/agent-session/acpmux/composer.gallery.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38535762014

* fix(cx-gakp): localize slash picker labels and cmux command descriptions

The Skill/Prompt labels and the four cmux command descriptions were
hard-coded English, which pane-english rejects. They now come from the
pane's table in all 21 languages; cmux commands carry a descriptionKey.

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

* fix(cx-gakp): keep Codex skills' $ prefix in the slash picker

codex-acp names each skill `$name` and passes `/$name` through to
Codex as a skill mention. Stripping the $ inserted `/name`, which ran a
same-named builtin or nothing, and deduped the skill behind cmux's own
commands. Keep the name and use the $ as the skill signal.

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

* chore(next): PR autofix at f4ed982

- regenerated schemas/defaults/cmux-next.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38541336447

* fix(cx-gakp): read the skill tag from ACP _meta in the slash picker

acpmux will tag Claude skills as _meta.kind (ACP keeps extensions in
_meta); read it alongside codex-acp's $ prefix.

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

* fix(cx-gakp): slash picker play finds its rows by name; harness stays harness

- The gallery play waited for exactly 3 rows, but cmux's /import shares
  the menu; it now finds the fixture rows by name, asserts Skill and
  Prompt on their own rows and no label on a harness command, and clears
  the "/" before typing the draft.
- The comment no longer claims acpmux tags Claude skills.
- /continue's description keeps "harness" as the catalog does elsewhere
  (17 locales said "tool").

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

* chore: regenerate pane strings after the base merge

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

* webviews: regenerate pane strings after the base merge

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

* Chief registry: chief.profile.adopt makes an existing agent participant a Chief record under its own id

The owner (a trusted local Unix caller acting as the person) adopts an agent that is already in a
conversation: the record keeps the participant's id and display name, so its DMs, history and
credential stay its own, and gets chief.profile.create's defaults and only the fields given.
A page (WebSocket or the host's page relay, even with a gesture), a paired or remote device and a
bound agent get origin.forbidden; there is no page route. agent_mux is default_chief, a live record
already_chief, a deleted Chief deleted_chief (an adopt never revives its tombstone or kept memory),
and a person or an unknown id not_an_agent_participant. The write goes through the daemon's
registry ledger (idempotent per key) and the same chief_written hook as a create.
Capability chief-profile-adopt-v1; CLI cmux chief adopt AGENT [PROFILE], refused for an agent
caller. Real-daemon tests for each refusal and for an adopt that keeps the DM and its history.

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

* chief.profile.adopt review fixes: owner gate first, any page origin refused, brain directory collisions refused, tests for the event and the limit

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

* chief.profile.adopt: refuse a bound participant, revoke its earlier credentials in the same write, and only the brain (or, with no supervisor, the person's terminal) mints the Chief's credential

The adopt claims the participant inside the registry write: under the bindings lock it refuses a
participant with a bound connection (participant_bound, "stop its current agent session first")
and otherwise revokes every credential issued for it. conversation-bind now checks the credential
and binds under the same lock, so a revoked credential never binds after the adopt. For a Chief
record other than agent_mux, conversation-agent-token is refused while a brain supervisor runs
(the supervisor mints the brain's credential in process); with no supervisor only the person's
own terminal mints it, never a page, a paired or remote device or an agent. Tests: a bound
participant is refused; after it unbinds the adopt succeeds and the brain starts; the old
credential is refused; the brain's credential binds; the person mints the post-adopt credential
on a daemon with no supervisor; a page, a device and an agent cannot mint it.

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

* chief.profile.adopt: the Chief-credential check and the mint run under the registry lock

Review finding: a mint that passed the Chief check before an adopt could overwrite the brain's
credential after it. conversation-agent-token now checks and mints inside one registry-locked step
(registry, then the conversation store, the adopt's order).

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

* Regenerate bindings after merge

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

* chief.profile.adopt: clippy (one write struct for mutate, no redundant clone)

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

* resource_attach: chief.profile.adopt is the 54th connection operation

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

* cmux-next: CmuxNextApp cap back to 113692 (frame-strip proof analysis and animation palette toggles leave the App target) (cx-me3xd)

The debug.new_tab frame_strip analysis (frame comparisons, PNGs, report fields) moves to
WindowFrameStrip in CmuxNextDesign beside WindowFrame and MotionFrameProgress; the drag_new
gesture moves to TabStripDebug.dragFirstTab in CmuxNextTabs. DebugFrameStrip keeps only the
wiring (record, send key or gesture, spans), so plus, drag_new and every report field stay.
The ui.animations.<kind> toggles and bounce bind through AnimationKindsSetting.bindActions
(CmuxNextSettings) on the shared SettingChoiceActions save, as ChromeStyleSetting does (ported
from nx-grow-land-fallback b1e0c989). CmuxNextApp 113810 -> 113692; the cap follows.

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

* cx-tgf4h red: cmux chief -p under ACPMUX_AGENT_LAUNCH=deny fails at once with a typed refusal

* cx-tgf4h: the Chief says at once that agents are disabled in this build session

With ACPMUX_AGENT_LAUNCH=deny (the nx-remote gui/input default since HQ
#2130) or CMUX_AGENTS_DISABLED=1, no Chief turn can start an agent.
`cmux chief -p` started a daemon and a brain and waited 240 s for a reply
that could not come.

- cmux-tui-core agent_launch: one test of the kill switch (acpmux
  launch_policy.rs), the reason agent_launch_disabled.
- `cmux chief` (pipe and chat) refuses before it starts or sends anything:
  operation.failed, details.reason agent_launch_disabled, exit 1.
- The daemon's supervisor starts no Chief brain; chief.engine.* and
  chief.stop answer the typed refusal at once.
- optchat-chief host does not start (logs why, exit 0).
- Home: the local Chief conversation's notice says agents are disabled;
  the engine panel maps the typed refusal (localized, all Home languages).
- Every Chief proof script refuses at once under deny and names
  `nx-remote --allow-agents`.

* Channels view: gallery plays for the host's home.currentSelection (red: the page does not serve it yet)

The host-callable command type (hostActions.ts) and two plays: a conversation, the keyboard's
current message and the open thread; the docked list pane answers null. cx-hnmbt

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

* Channels view: home.currentSelection for the Home dock's view switch

The page serves window.cmuxHomeActions["home.currentSelection"] (the agent page's
cmuxAcpmuxActions pattern; the host calls it with callAsyncJavaScript): {conversation,
message?, thread?} = the open conversation, the keyboard's current message or the message a
link marked, and the open thread's root; null on the narrow list pane or with nothing open.
The host never reads the page hash for the hand-off. cx-hnmbt

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

* Channels view: serve home.currentSelection on the page bridge, not a window global

The host calls it with PageRouter.callPage (the typed host-to-page call the page bridge already
has; PageClient.handle on the page): {} -> {conversation, message?} | null. message = the
keyboard's current message, else the message a link marked, else the open thread's root. The
gallery plays drive a real BridgePageClient through __cmuxPageReceive, as the app does. cx-hnmbt

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

* Channels view: home.currentSelection review follow-ups

Layout effect for the answered selection; null before the page's first measure (a docked list
pane never reports a hidden conversation); the gallery host uses a private bridge target; the
thread case is its own play (the gallery opens the thread). cx-hnmbt

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

* acpmux: Codex picks run the in-process bridge, not the npx codex-acp adapter (#20800)

* test(acpmux): the npx codex-acp adapter is offered beside the Codex bridge

Red: with codex and npx on PATH and no codex-acp, discovery keeps the
pinned npx adapter (@agentclientprotocol/codex-acp) as `codex-acp` next
to the in-process bridge. That adapter reads the account through codex's
account/read, which fails for a ChatGPT login behind a routing proxy
(subrouter): its sessions never start ("Authentication required").

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

* acpmux: Codex picks run the in-process bridge, not the npx codex-acp adapter

With codex installed and no codex-acp on PATH, discovery kept the pinned
npx adapter (@agentclientprotocol/codex-acp@1.10.0) as `codex-acp` beside
the in-process bridge. The adapter reads the account through codex's
account/read; with codex 0.162 a ChatGPT login behind a routing proxy
(subrouter) fails that ("selected workspace missing from routing
discovery"), so its chats never started ("Authentication required"),
while the bridge works on the same login.

Discovery no longer offers the npx adapter: an installed codex is the
bridge, and `codex-acp` names the bridge too (like `codex-app-server`), so
sessions, presets and model picks that recorded it run the bridge. A
codex-acp on PATH, an ~/.acpx entry and a config-written launch are
unchanged.

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

* acpmux: one description for the bridge's aliases (rustfmt)

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

---------

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

* cx-tgf4h review: forward chief control to a running brain first; daemon-side deny test; engine/stop CLI text; guard before side effects; fmt

* test: warm the dev server in three agent pane browser tests (#20873)

check:browser-lanes (#20733) requires warmViteServer after listen; #20752,
#20780 and #20785 landed tests without it, so react-apps-check is red on base.

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

* acpmux tests: every acpmux process a test starts gets a hermetic environment (cx-s8wux)

One helper, tests/support/daemon_env.rs, starts the acpmux binary for every
integration test: env_clear, a bare PATH (python3 plus named host tools,
then the system directories), a scratch HOME, and ACPMUX_AGENT_LAUNCH=deny
unless the test drives a stand-in agent (Agents::StandIn keeps the bare
PATH). The 26 test files that started the binary with the host environment
use it; tests/hermetic_daemon_guard.rs refuses a test file that names
CARGO_BIN_EXE_acpmux anywhere else.

Root cause of cx-w014j: a fleet host's PATH holds real codex/claude, which a
test daemon discovered and ran (probes, sign-in checks, auto-updates).

* cx-tgf4h: fmt and clippy

* acpmux tests: the hermetic HOME is <scratch>/home, never a chat's folder

* acpmux tests: review fixes for the hermetic environment (cx-s8wux)

python3 links the interpreter itself (sys.executable), not a version
manager's shim; stale tool links from an earlier run are replaced; the guard
also flags daemon_env::bin() outside a listed use; the live codex test probes
only codex; codex_bridge_config's discovery test runs with launches denied.

* cmux-tui: agent-session-attach takes the agent pane's whole kind list (up to 32; the pane asks 9 since prompt bookmarks), so a remote chat shows after Trust instead of falling back to New Tab with bad request (cx-kpd0v)

* agent pane: the attach asks at most 8 kinds again (session offers come with transcript), so an older remote cmux-tui shows the chat (cx-kpd0v)

* cmux-tui: test fake needs no mut (cx-kpd0v)

* acpmux tests: router_install_secret starts the router through daemon_env (cx-s8wux)

* cmux-next composer: keep base's catalog order; regenerate strings on the merged base

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

* acpmux: one typed protocol registry; generated web types and drift checks (hq#2025, no bead) (#20576)

* acpmux: typed protocol registry and IR (hq#2025, no bead)

One registry names every acpmux method and notification; sessions and
permissions carry serde/schemars types, and the daemon builds
SessionSummary and PermissionGroup from them. ir() emits
spec/acpmux-protocol.json for the web codegen. Tests fail when the
committed IR is stale or the dispatcher serves a name the registry lacks.

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

* webviews: acpmux protocol codegen, typed request helper and drift check (hq#2025, no bead)

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

* acpmux protocol: committed IR, generated web types; permissions and session_changed use them (hq#2025, no bead)

The permission group client and permission_respond go through the typed
request; session_changed and permission_pending are narrowed by the
registry's notification map. The IR declares a peer summary's optional
fields and peer key, permission_pending's always-sent keys, and closed
param objects.

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

* webviews: format direct.ts

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

* webviews: acpmux codegen lives beside the pane protocol codegen, outside the pane sources

Its developer-facing IR errors tripped pane-english, which scans
src/agent-session/acpmux for user-visible English.

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

* chore(next): PR autofix at 1bb7576

- cargo fmt in Native/OptChat/optchat-chief

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38569912312

* chore(next): PR autofix at c601de5

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38593588859

* chore(next): PR autofix at 7a7fb66

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38606761975

* acpmux protocol: register offer_session and offer_respond

Base (#20305) serves two new methods; the registry's completeness test
caught them. Both are untyped requests for now. Spec and generated
TS are regenerated.

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

* acpmux protocol: register prompt_withdraw

Base serves _acpmux/prompt_withdraw; the completeness test caught it. Spec and
generated TS are regenerated.

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

* chore(next): PR autofix at 4e1d3c9

- vp fmt webviews/src/pages/home-channels/HomeChannelsPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38637598208

* acpmux protocol: register the process methods

Base serves _acpmux/process/list and process/kill and sends
_acpmux/process_update; the completeness test caught them. Spec and generated
TS are regenerated.

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

* chore(next): PR autofix at 64ca080

- vp fmt webviews/src/pages/home-channels/cloudHome.ts
- cargo fmt in Native/OptChat/optchat-chief

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38649959912

---------

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: fix two Chief profile relay base reds (concurrency check, Release compile crash) (no bead) (#20876)

* cmux-next: mark the Chief profile relay retry loop as bounded (no bead)

check-concurrency flags its while true as a loop that can spin. It retries
once, only after a lost connection, and every other error throws.

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

* cmux-next: nonisolated deinit for PageCallDeadline.Once (no bead)

The Release compile crashes swift-frontend 6.3.3 in EarlyPerfInliner on
the isolated deinit of this main-actor generic class (exit 65, no error
line), the same crash #20408 fixed elsewhere.

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

---------

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

* fix(cmux-next): the Chief profile relay's retry is a two-attempt for loop, not while true with a wakeup-allow (cx-ebm.59.5)

* cmux-next sidebar perf round 3: Release-build hitch bench with real wheel input; O(1) hover-card hit

- scripts/cmux-next/sidebar-rows-perf-release.py: runs in a Release tagged app (no debug.* methods) inside
  nx-remote --needs input: CLI workspaces (50 with a terminal, 950 empty), HID-tap wheel events, Animation
  Hitches per gesture, A/B of two apps in one job (side by side, interleaved), traces and the recorder's ktrace
  files removed after each export, PTY count logged.
- SidebarListView+HoverCard: the hover-card hit reads the list's row dictionary instead of
  SidebarModel.isPlaceholder, an O(workspaces) section walk on every scroll frame (7-12% of main-thread samples
  while scrolling 1,000 rows in Release).

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

* Channels: a primary or danger button keeps its fill under the pointer (a soft ring shows the hover); gallery play primary-hover

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

* Channels gallery: primary-hover asserts the hover ring and the unchanged fill; a budget with a reason for the Create frame

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

* cmux-motion: Chrome tab strip tween (200 ms easeOutQuad, restart from value), tabStrip geometry tokens, damping <= 0 takes the fallback (hq-1d, no bead)

Additive: MotionTween {TabOpen, TabClose, TabMove}, TweenCurve::EaseOutQuad,
ease_out_quad, TweenParameters, TweenValue (f64 core: retarget restarts the
duration from the current value with no velocity; the same target does not
restart), Tween (f32, token-driven), MotionPolicy::tween (0 under speed off,
Reduce Motion, or tabOpen/tabClose with ui.animations.newTab off),
TabStripGeometry (design-tokens.json motion.tabStrip: max 200, open/close
18, min 56 active / 32 inactive / 64 pinned, reorder 16 x width / 200,
closing mode +40 below / +60 trailing / 0.3 s). cmux-app-ffi ABI 2 exports
cmux_motion_tween_{base,seconds,retarget,step}, cmux_motion_ease and
cmux_motion_tab_strip_geometry. SpringParameters::finite_or now treats a
damping fraction <= 0 like NaN (hq-4e nit). The parity corpus example
prints tween paths (60 Hz: 12 frames for 200 ms).

* acpmux: record a session's git branch and HEAD at start (hq#1920) (#20840)

* test(acpmux): record a session's git branch and head at start

A session should keep its folder's branch and HEAD commit as they were at
session/new, and a fork its own folder's state at fork time (hq#1920), so
agent spend can be joined to the pull request a session produced. These
fail today: neither the saved meta nor _acpmux/info carries gitBranch or
gitHead.

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

* feat(acpmux): record a session's git branch and head at start

session/new and session/fork now store the cwd's checked-out branch and
full HEAD commit in the session meta (gitBranch, gitHead), so a session
can later be joined to the pull request it produced (hq#1920). The values
are read once, as the session starts, from the repository's own files
(HEAD, loose refs, packed-refs, a linked worktree's gitdir and commondir),
never a git process, and off the async runtime. A detached HEAD records
only the head; a folder outside a repository records neither; a lookup
that fails never fails the session. A fork reads its own folder at fork
time instead of copying the parent's. _acpmux/info carries both fields.
Old session.json files load unchanged.

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

* test(acpmux): git state skips non-files, bad branch names and missing folders; follows symlinks

Review of #20840: a FIFO HEAD hung session/new, a symlinked folder was walked
lexically, a missing fork folder took its parent repository's state, and an
invalid ref name was stored as the branch. The test git also runs without the
machine's global or system config.

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

* fix(acpmux): git state reads only small regular files, the physical folder and valid ref names

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

---------

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

* cx-tgf4h: keep CmuxNextApp line count (App size cap)

* acpmux: a pooled agent host no longer spins on Linux reading its own record (cx-7z8yx)

The record watch used notify's inotify backend, whose watch mask always
includes open, close-write and modify, and ran its callback on every event.
The callback reads the host record; on Linux that read queued an open and a
close in the watched directory, which ran the callback again. Every pooled
host spun at 100% CPU (about 200,000 read calls a second).

Linux now has its own inotify watch, like the macOS kqueue watch: a mask of
entry changes only (create, delete, moved from/to) and the directory's own
delete or move, one thread in poll with no timeout, an eventfd to stop it.
A read of the record never queues an event. The notify fallback (other
platforms) ignores access events. macOS is unchanged.

Behavior test (tests/host_lifetime.rs, Linux): a real daemon pools a host;
idle for 3 s it makes fewer than 100 read calls and 30 CPU ticks (before:
599,042 reads, 298 ticks), a rename rewrite of its record keeps it, and the
record removed ends it.

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

* cmux-tui smoke: sidebar drag checks the drawn sidebar document order

Since sidebar-v2 S6 the TUI draws the daemon's sidebar document, where a new
workspace goes to the top (workspaces.newPlacement default), and a workspace
drop is one sidebar.move that changes the document only. The smoke still
assumed the list-workspaces order: it dragged the drawn top row (the new
workspace) below the original, which the product did, and then read
list-workspaces, which a sidebar.move never changes.

The smoke now reads the order from sidebar.get, checks that the rail draws
it, drags the top row below the second (a real reorder), and drags again when
needed so the original workspace ends below the new one.

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

* PR dock chips; tooltips only where nothing else names the control (#20375)

* test: no tooltip on an element whose text shows

Red on base: 105 elements with visible text carry title/data-tooltip.
Command: bun test test/tooltip-rules.test.ts

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

* fix: PR dock chips; tooltips only where nothing else names the control

The pull request dock's bars become content-sized chips (icon, #N, repo, title cut off at
360 px) with the dismiss button inside and no tooltip. Across the pages, a row, chip, link,
path or thought whose text shows carries no title tooltip any more; tooltips stay on
icon-only controls, shortcuts and text shown nowhere else (why a control is disabled or
failed, who reacted, policy detail), each marked tooltip-allow. Tooltips wait the native
hover delay (about a second) and show at once when moving straight on to the next one.

Green: bun test test/tooltip-rules.test.ts

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

* fix: review of tooltip audit

Keep the PR dock's state colours, drop four more tooltips the lint now finds inside
components (a setting's summary, the branch and folder pickers, a video), let a click or
scroll end the quick next-tooltip window, and move two tests to the no-tooltip rule.

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

* test: Backdrop Art's line has no tooltip

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

* chore(next): PR autofix at 047c247

- vp fmt webviews/src/pages/history/HistoryPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38502564051

* test(mock): the worked chat opens its pull request, so mock mode shows the PR dock

Captures of the agent pane in a real window (--showcase runs the in-page
mock) now show the pull request dock.

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

* test: the PR dock takes its own space; the transcript ends above it

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

* chore(next): PR autofix at 39f3ca9

- vp fmt webviews/test/ime-composition-keys.test.ts
- vp fmt webviews/test/new-tab-omnibar-pointer.test.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38567629461

* chore(next): PR autofix at c7cb261

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38592980576

* fix: a channel image keeps its name tooltip (the name shows only when it fails)

Base added title={part.name} on channel image attachments (AttachmentViews.tsx).
A loaded image shows no name, so the tooltip is its only label; mark it with
tooltip-allow. tooltip-rules.test.ts: red before, green after.

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

* chore(next): PR autofix at f221864

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38633116142

* fix: keep the tool card scope hint and Steer shortcut tooltips

Both explain something shown nowhere else, so they stay under tooltip-allow.

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

* chore(next): PR autofix at 022cc8e

- vp fmt webviews/src/pages/home-channels/cloudHome.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38647981824

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* ci: nightly-next recovery initializes the notices submodule before continuing accepted submissions

The recovery job's checkout had no ghostty-next submodule, so the bundle
notice check that notarize-nightly-dmg.sh runs after Apple accepts failed,
and run 38669958906 skipped five accepted builds as 'Apple did not accept'.
Initialize the submodule like the signing job does, and make the skip notice
say that a post-acceptance check can also be the cause.

* ci: the cmux NIGHTLY-identity job also initializes the notices submodule

Run 38669958906's publish-nightly-identity-legacy job saw Apple accept,
then failed the bundle notice check for lack of ghostty-next and retired
the accepted submission of run 38609024986.

* agent pane: progress and stop for a running Claude subagent or workflow (cx-liswe) (#20718)

* test: a running subagent or workflow shows what it does and what it has spent

Red on base: both rows read only "Running" (bun test
test/subagent-progress.test.tsx).

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

* webviews: a running subagent or workflow shows what it does and what it has spent

The subagent fold keeps acpmux's subagent_progress fields (action, tokens,
tool uses, a workflow's agents done of started), and the transcript's
subagent row adds them to its status line through one shared helper
(subagentProgress.ts) the summary list and the Background tasks pane can use.
Three plural strings, translated for every pane locale.

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

* test: a running subagent row has a stop button

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

* feat: stop a running Claude subagent or workflow from its row

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

* chore: restore the catalog's base order after the merge

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

* test: stopping a subagent leaves its row closed, and a refused stop says so

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

* fix: a subagent's stop button waits for Claude and says when the stop failed

The button is off while Claude has the request and until the subagent
ends; a refused or unanswered stop (10 s) turns it into "Couldn't stop
<name>" and it can be tried again. The pane no longer drops the error.
Also moves the stop wiring above showSubagent's doc comment and corrects
two comments.

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

* style: format the subagent progress test

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

* fix: stop rejects without English the pane would never show

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

* chore: restore the catalog's base order after the merge

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

* chore(next): PR autofix at 2fe6cc4

- vp fmt webviews/src/pages/home-channels/HomeChannelsPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38637059713

* test: the agent pane relays a subagent stop for its chat (cx-liswe)

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

* fix: the agent pane may stop a subagent of its chat (cx-liswe)

Adds _acpmux/subagent_stop to the pane's method allowlist: session-scoped,
params sessionId and subagentSessionId, no gesture (it stops work, like
_acpmux/kill). Without it the host refused every stop click.

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

* fix: mirror the subagent stop into the shared pane policy (cx-liswe)

The Swift allowlist took _acpmux/subagent_stop; policy.json, its parity
source for Rust hosts, gets the same request, session scope and params,
with cases for an in-scope stop, another chat and an unknown param.

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

* gallery: a light window with no theme named renders light (#20794)

* test(gallery): a light window with no theme named should show the light default

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

* fix(gallery): a light window with no theme named shows Apple System Colors Light

The gallery defaulted the theme to the dark side of the app's default pair
whatever the window appearance, so colorScheme=light (or Appearance: Light)
rendered every stage in dark colors under a light media query. The default
now follows the appearance, as the app's does with no theme set.

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>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* Channels view: gallery plays for a message link with no link read (red)

A Cloud conversation has no link resolver (G4), so the Messages view's switch hand-off
#/conversation/<id>/message/<id> showed an error. Two plays: a thread reply and a timeline
message, opened through the store's openLink with an owner that has no resolver. cx-hnmbt

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

* Channels view: open a known conversation's message link without the owner's link read

When conversation-link-resolve fails (a Cloud conversation, an older daemon) and the page knows
the conversation, it opens it, pages the timeline until the message shows, opens its thread when
it is a reply, and marks it. The Messages view's switch hands off Cloud selections this way.
cx-hnmbt

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

* Channels view: format parseConversationLink (vp fmt)

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

* Channels view: link fallback review follow-ups

Ids in a known conversation's link may hold '-' (the gallery's sample ids); the scheme check
follows the daemon (cmux[-<tag>], any case); the fallback runs only for a Cloud conversation or
an owner without a link read, so a refused local link (a deleted message) still shows its error.
cx-hnmbt

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

* acpmux: host_lifetime idle test cleans up from the start and never signals a reused pid (cx-7z8yx review)

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

* cmux-tui: move the build identity into a leaf crate so an edit no longer recompiles cmux-remote

cmux-remote's build script hashed the dirty source tree into
CMUX_TUI_BUILD_IDENTITY, so every edit in the workspace reran it and
recompiled cmux-remote and every crate above it (about 8 s of a 12.6 s
one-line edit loop on rbx). The same build script now lives in
cmux-build-identity, which only cmux-tui reads; cmux-remote takes the
identity as an argument (SshBootstrapConfig::defaults,
pinned_linux_payload). The identity value, its inputs and format, and
every skew and SSH re-bootstrap comparison are unchanged.

* test: warm the dev server in the Claude reasoning default browser test (#20884)

#20592 landed after #20873 without warmViteServer, so check:browser-lanes is
red on base again.

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

* cmux-next: frame-strip report as an NSWindow method, not a namespace enum (no bead) (#20887)

The package conventions lint fails every PR on the new all-static public
enum WindowFrameStrip (cx-me3xd). The report reads its window, so it is an
extension on NSWindow; same body, same report.

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

* Home channels: the run card is an inline disclosure (no frame, steps on an indented rail)

The live and done run cards under a Chief's reply lose their box: "Working
for" / "Worked for", the step count, cost and Open sit inline under the
message, and the opened steps hang on a thin rail under the status mark. The
narrow rules stay: the first line never wraps, and below 480 px of card width
the step count and cost move under it with no leading separator.

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

* Home channels: the run rail and columns follow the author's picture

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

* Home channels: the run sheet keeps its error line; run card columns in logical properties

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

* Revert "cmux-motion: Chrome tab strip tween ..." (8a3ee62) until the app-ffi release App 403 is fixed (run 38682698310) (hq-1d, chief go 2026-10-15, no bead)

The release App could not publish cmux-app-ffi-854febb26527 (HTTP 403 on
POST /releases), so the app FFI pin check stays red on the tip. The tween
re-lands with the publish and repin after the App is fixed.

* test(ci): nightly jobs that run the license check must init ghostty-next (#20893)

* test(ci): nightly jobs that run the license check must init ghostty-next

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

* fix(ci): nightly recovery initializes ghostty-next before the license check

Apple accepted, stapled and launch-tested each recovered nightly-next build,
then verify-app-bundle-licenses.sh failed on the missing
ghostty-next/build.zig.zon and the build was skipped as not accepted.

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

---------

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

* fix: keep catalog in base order after feat merge

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

---------

Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: safe-push <safe-push@cmux.local>
teamleaderleo added a commit that referenced this pull request Oct 15, 2026
…ceiling, lower CPU weight; no process scanning) (#20755)

* test(acpmux): a chat's harness runs in its own cgroup scope on Linux (red)

cx-v9s8g, Linux half: systemd-run --user --scope with MemoryMax and
CPUWeight from the profile or daemon env; unscoped when systemd cannot
make a scope; no scope when both limits are 0.

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

* feat(acpmux): each chat's harness in its own cgroup scope on Linux

cx-v9s8g, Linux half: session_scope.rs starts a session's harness under
systemd-run --user --scope (which execs it: same pid and process group)
with MemoryMax (ACPMUX_SESSION_MEMORY_MB, default half the machine's
memory) and CPUWeight (ACPMUX_SESSION_CPU_WEIGHT, default 50), from the
profile's env, then the daemon's; 0 turns one off. The kernel enforces
both, so nothing measures or scans processes. Without systemd-run, or
when it cannot make a scope (asked once per runner and limits), the
harness starts as before. macOS's process-group half stays with
ptyh-noscan after cx-t2sqm.3.

A runaway hitting MemoryMax ends that process, not the scope
(OOMPolicy=continue, dropped on a systemd that refuses it); a probe's
answer holds for 5 minutes.

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

* chore(next): PR autofix at 348a805

- cargo fmt in Native/OptChat/optchat-chief

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38650955451

* cx-tgf4h red: cmux chief -p under ACPMUX_AGENT_LAUNCH=deny fails at once with a typed refusal

* cx-tgf4h: the Chief says at once that agents are disabled in this build session

With ACPMUX_AGENT_LAUNCH=deny (the nx-remote gui/input default since HQ
#2130) or CMUX_AGENTS_DISABLED=1, no Chief turn can start an agent.
`cmux chief -p` started a daemon and a brain and waited 240 s for a reply
that could not come.

- cmux-tui-core agent_launch: one test of the kill switch (acpmux
  launch_policy.rs), the reason agent_launch_disabled.
- `cmux chief` (pipe and chat) refuses before it starts or sends anything:
  operation.failed, details.reason agent_launch_disabled, exit 1.
- The daemon's supervisor starts no Chief brain; chief.engine.* and
  chief.stop answer the typed refusal at once.
- optchat-chief host does not start (logs why, exit 0).
- Home: the local Chief conversation's notice says agents are disabled;
  the engine panel maps the typed refusal (localized, all Home languages).
- Every Chief proof script refuses at once under deny and names
  `nx-remote --allow-agents`.

* cx-tgf4h review: forward chief control to a running brain first; daemon-side deny test; engine/stop CLI text; guard before side effects; fmt

* acpmux tests: every acpmux process a test starts gets a hermetic environment (cx-s8wux)

One helper, tests/support/daemon_env.rs, starts the acpmux binary for every
integration test: env_clear, a bare PATH (python3 plus named host tools,
then the system directories), a scratch HOME, and ACPMUX_AGENT_LAUNCH=deny
unless the test drives a stand-in agent (Agents::StandIn keeps the bare
PATH). The 26 test files that started the binary with the host environment
use it; tests/hermetic_daemon_guard.rs refuses a test file that names
CARGO_BIN_EXE_acpmux anywhere else.

Root cause of cx-w014j: a fleet host's PATH holds real codex/claude, which a
test daemon discovered and ran (probes, sign-in checks, auto-updates).

* cx-tgf4h: fmt and clippy

* acpmux tests: the hermetic HOME is <scratch>/home, never a chat's folder

* acpmux tests: review fixes for the hermetic environment (cx-s8wux)

python3 links the interpreter itself (sys.executable), not a version
manager's shim; stale tool links from an earlier run are replaced; the guard
also flags daemon_env::bin() outside a listed use; the live codex test probes
only codex; codex_bridge_config's discovery test runs with launches denied.

* acpmux tests: router_install_secret starts the router through daemon_env (cx-s8wux)

* fix(cmux-next): the Chief profile relay's retry is a two-attempt for loop, not while true with a wakeup-allow (cx-ebm.59.5)

* cmux-next sidebar perf round 3: Release-build hitch bench with real wheel input; O(1) hover-card hit

- scripts/cmux-next/sidebar-rows-perf-release.py: runs in a Release tagged app (no debug.* methods) inside
  nx-remote --needs input: CLI workspaces (50 with a terminal, 950 empty), HID-tap wheel events, Animation
  Hitches per gesture, A/B of two apps in one job (side by side, interleaved), traces and the recorder's ktrace
  files removed after each export, PTY count logged.
- SidebarListView+HoverCard: the hover-card hit reads the list's row dictionary instead of
  SidebarModel.isPlaceholder, an O(workspaces) section walk on every scroll frame (7-12% of main-thread samples
  while scrolling 1,000 rows in Release).

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

* Channels: a primary or danger button keeps its fill under the pointer (a soft ring shows the hover); gallery play primary-hover

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

* Channels gallery: primary-hover asserts the hover ring and the unchanged fill; a budget with a reason for the Create frame

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

* cmux-motion: Chrome tab strip tween (200 ms easeOutQuad, restart from value), tabStrip geometry tokens, damping <= 0 takes the fallback (hq-1d, no bead)

Additive: MotionTween {TabOpen, TabClose, TabMove}, TweenCurve::EaseOutQuad,
ease_out_quad, TweenParameters, TweenValue (f64 core: retarget restarts the
duration from the current value with no velocity; the same target does not
restart), Tween (f32, token-driven), MotionPolicy::tween (0 under speed off,
Reduce Motion, or tabOpen/tabClose with ui.animations.newTab off),
TabStripGeometry (design-tokens.json motion.tabStrip: max 200, open/close
18, min 56 active / 32 inactive / 64 pinned, reorder 16 x width / 200,
closing mode +40 below / +60 trailing / 0.3 s). cmux-app-ffi ABI 2 exports
cmux_motion_tween_{base,seconds,retarget,step}, cmux_motion_ease and
cmux_motion_tab_strip_geometry. SpringParameters::finite_or now treats a
damping fraction <= 0 like NaN (hq-4e nit). The parity corpus example
prints tween paths (60 Hz: 12 frames for 200 ms).

* acpmux: record a session's git branch and HEAD at start (hq#1920) (#20840)

* test(acpmux): record a session's git branch and head at start

A session should keep its folder's branch and HEAD commit as they were at
session/new, and a fork its own folder's state at fork time (hq#1920), so
agent spend can be joined to the pull request a session produced. These
fail today: neither the saved meta nor _acpmux/info carries gitBranch or
gitHead.

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

* feat(acpmux): record a session's git branch and head at start

session/new and session/fork now store the cwd's checked-out branch and
full HEAD commit in the session meta (gitBranch, gitHead), so a session
can later be joined to the pull request it produced (hq#1920). The values
are read once, as the session starts, from the repository's own files
(HEAD, loose refs, packed-refs, a linked worktree's gitdir and commondir),
never a git process, and off the async runtime. A detached HEAD records
only the head; a folder outside a repository records neither; a lookup
that fails never fails the session. A fork reads its own folder at fork
time instead of copying the parent's. _acpmux/info carries both fields.
Old session.json files load unchanged.

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

* test(acpmux): git state skips non-files, bad branch names and missing folders; follows symlinks

Review of #20840: a FIFO HEAD hung session/new, a symlinked folder was walked
lexically, a missing fork folder took its parent repository's state, and an
invalid ref name was stored as the branch. The test git also runs without the
machine's global or system config.

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

* fix(acpmux): git state reads only small regular files, the physical folder and valid ref names

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

---------

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

* cx-tgf4h: keep CmuxNextApp line count (App size cap)

* acpmux: a pooled agent host no longer spins on Linux reading its own record (cx-7z8yx)

The record watch used notify's inotify backend, whose watch mask always
includes open, close-write and modify, and ran its callback on every event.
The callback reads the host record; on Linux that read queued an open and a
close in the watched directory, which ran the callback again. Every pooled
host spun at 100% CPU (about 200,000 read calls a second).

Linux now has its own inotify watch, like the macOS kqueue watch: a mask of
entry changes only (create, delete, moved from/to) and the directory's own
delete or move, one thread in poll with no timeout, an eventfd to stop it.
A read of the record never queues an event. The notify fallback (other
platforms) ignores access events. macOS is unchanged.

Behavior test (tests/host_lifetime.rs, Linux): a real daemon pools a host;
idle for 3 s it makes fewer than 100 read calls and 30 CPU ticks (before:
599,042 reads, 298 ticks), a rename rewrite of its record keeps it, and the
record removed ends it.

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

* cmux-tui smoke: sidebar drag checks the drawn sidebar document order

Since sidebar-v2 S6 the TUI draws the daemon's sidebar document, where a new
workspace goes to the top (workspaces.newPlacement default), and a workspace
drop is one sidebar.move that changes the document only. The smoke still
assumed the list-workspaces order: it dragged the drawn top row (the new
workspace) below the original, which the product did, and then read
list-workspaces, which a sidebar.move never changes.

The smoke now reads the order from sidebar.get, checks that the rail draws
it, drags the top row below the second (a real reorder), and drags again when
needed so the original workspace ends below the new one.

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

* PR dock chips; tooltips only where nothing else names the control (#20375)

* test: no tooltip on an element whose text shows

Red on base: 105 elements with visible text carry title/data-tooltip.
Command: bun test test/tooltip-rules.test.ts

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

* fix: PR dock chips; tooltips only where nothing else names the control

The pull request dock's bars become content-sized chips (icon, #N, repo, title cut off at
360 px) with the dismiss button inside and no tooltip. Across the pages, a row, chip, link,
path or thought whose text shows carries no title tooltip any more; tooltips stay on
icon-only controls, shortcuts and text shown nowhere else (why a control is disabled or
failed, who reacted, policy detail), each marked tooltip-allow. Tooltips wait the native
hover delay (about a second) and show at once when moving straight on to the next one.

Green: bun test test/tooltip-rules.test.ts

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

* fix: review of tooltip audit

Keep the PR dock's state colours, drop four more tooltips the lint now finds inside
components (a setting's summary, the branch and folder pickers, a video), let a click or
scroll end the quick next-tooltip window, and move two tests to the no-tooltip rule.

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

* test: Backdrop Art's line has no tooltip

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

* chore(next): PR autofix at 047c247

- vp fmt webviews/src/pages/history/HistoryPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38502564051

* test(mock): the worked chat opens its pull request, so mock mode shows the PR dock

Captures of the agent pane in a real window (--showcase runs the in-page
mock) now show the pull request dock.

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

* test: the PR dock takes its own space; the transcript ends above it

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

* chore(next): PR autofix at 39f3ca9

- vp fmt webviews/test/ime-composition-keys.test.ts
- vp fmt webviews/test/new-tab-omnibar-pointer.test.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38567629461

* chore(next): PR autofix at c7cb261

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38592980576

* fix: a channel image keeps its name tooltip (the name shows only when it fails)

Base added title={part.name} on channel image attachments (AttachmentViews.tsx).
A loaded image shows no name, so the tooltip is its only label; mark it with
tooltip-allow. tooltip-rules.test.ts: red before, green after.

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

* chore(next): PR autofix at f221864

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38633116142

* fix: keep the tool card scope hint and Steer shortcut tooltips

Both explain something shown nowhere else, so they stay under tooltip-allow.

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

* chore(next): PR autofix at 022cc8e

- vp fmt webviews/src/pages/home-channels/cloudHome.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38647981824

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* ci: nightly-next recovery initializes the notices submodule before continuing accepted submissions

The recovery job's checkout had no ghostty-next submodule, so the bundle
notice check that notarize-nightly-dmg.sh runs after Apple accepts failed,
and run 38669958906 skipped five accepted builds as 'Apple did not accept'.
Initialize the submodule like the signing job does, and make the skip notice
say that a post-acceptance check can also be the cause.

* ci: the cmux NIGHTLY-identity job also initializes the notices submodule

Run 38669958906's publish-nightly-identity-legacy job saw Apple accept,
then failed the bundle notice check for lack of ghostty-next and retired
the accepted submission of run 38609024986.

* agent pane: progress and stop for a running Claude subagent or workflow (cx-liswe) (#20718)

* test: a running subagent or workflow shows what it does and what it has spent

Red on base: both rows read only "Running" (bun test
test/subagent-progress.test.tsx).

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

* webviews: a running subagent or workflow shows what it does and what it has spent

The subagent fold keeps acpmux's subagent_progress fields (action, tokens,
tool uses, a workflow's agents done of started), and the transcript's
subagent row adds them to its status line through one shared helper
(subagentProgress.ts) the summary list and the Background tasks pane can use.
Three plural strings, translated for every pane locale.

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

* test: a running subagent row has a stop button

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

* feat: stop a running Claude subagent or workflow from its row

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

* chore: restore the catalog's base order after the merge

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

* test: stopping a subagent leaves its row closed, and a refused stop says so

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

* fix: a subagent's stop button waits for Claude and says when the stop failed

The button is off while Claude has the request and until the subagent
ends; a refused or unanswered stop (10 s) turns it into "Couldn't stop
<name>" and it can be tried again. The pane no longer drops the error.
Also moves the stop wiring above showSubagent's doc comment and corrects
two comments.

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

* style: format the subagent progress test

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

* fix: stop rejects without English the pane would never show

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

* chore: restore the catalog's base order after the merge

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

* chore(next): PR autofix at 2fe6cc4

- vp fmt webviews/src/pages/home-channels/HomeChannelsPage.tsx

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38637059713

* test: the agent pane relays a subagent stop for its chat (cx-liswe)

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

* fix: the agent pane may stop a subagent of its chat (cx-liswe)

Adds _acpmux/subagent_stop to the pane's method allowlist: session-scoped,
params sessionId and subagentSessionId, no gesture (it stops work, like
_acpmux/kill). Without it the host refused every stop click.

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

* fix: mirror the subagent stop into the shared pane policy (cx-liswe)

The Swift allowlist took _acpmux/subagent_stop; policy.json, its parity
source for Rust hosts, gets the same request, session scope and params,
with cases for an in-scope stop, another chat and an unknown param.

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

* gallery: a light window with no theme named renders light (#20794)

* test(gallery): a light window with no theme named should show the light default

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

* fix(gallery): a light window with no theme named shows Apple System Colors Light

The gallery defaulted the theme to the dark side of the app's default pair
whatever the window appearance, so colorScheme=light (or Appearance: Light)
rendered every stage in dark colors under a light media query. The default
now follows the appearance, as the app's does with no theme set.

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>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* Channels view: gallery plays for a message link with no link read (red)

A Cloud conversation has no link resolver (G4), so the Messages view's switch hand-off
#/conversation/<id>/message/<id> showed an error. Two plays: a thread reply and a timeline
message, opened through the store's openLink with an owner that has no resolver. cx-hnmbt

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

* Channels view: open a known conversation's message link without the owner's link read

When conversation-link-resolve fails (a Cloud conversation, an older daemon) and the page knows
the conversation, it opens it, pages the timeline until the message shows, opens its thread when
it is a reply, and marks it. The Messages view's switch hands off Cloud selections this way.
cx-hnmbt

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

* Channels view: format parseConversationLink (vp fmt)

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

* Channels view: link fallback review follow-ups

Ids in a known conversation's link may hold '-' (the gallery's sample ids); the scheme check
follows the daemon (cmux[-<tag>], any case); the fallback runs only for a Cloud conversation or
an owner without a link read, so a refused local link (a deleted message) still shows its error.
cx-hnmbt

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

* acpmux: host_lifetime idle test cleans up from the start and never signals a reused pid (cx-7z8yx review)

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

* cmux-tui: move the build identity into a leaf crate so an edit no longer recompiles cmux-remote

cmux-remote's build script hashed the dirty source tree into
CMUX_TUI_BUILD_IDENTITY, so every edit in the workspace reran it and
recompiled cmux-remote and every crate above it (about 8 s of a 12.6 s
one-line edit loop on rbx). The same build script now lives in
cmux-build-identity, which only cmux-tui reads; cmux-remote takes the
identity as an argument (SshBootstrapConfig::defaults,
pinned_linux_payload). The identity value, its inputs and format, and
every skew and SSH re-bootstrap comparison are unchanged.

* test: warm the dev server in the Claude reasoning default browser test (#20884)

#20592 landed after #20873 without warmViteServer, so check:browser-lanes is
red on base again.

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

* cmux-next: frame-strip report as an NSWindow method, not a namespace enum (no bead) (#20887)

The package conventions lint fails every PR on the new all-static public
enum WindowFrameStrip (cx-me3xd). The report reads its window, so it is an
extension on NSWindow; same body, same report.

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

* Home channels: the run card is an inline disclosure (no frame, steps on an indented rail)

The live and done run cards under a Chief's reply lose their box: "Working
for" / "Worked for", the step count, cost and Open sit inline under the
message, and the opened steps hang on a thin rail under the status mark. The
narrow rules stay: the first line never wraps, and below 480 px of card width
the step count and cost move under it with no leading separator.

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

* Home channels: the run rail and columns follow the author's picture

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

* Home channels: the run sheet keeps its error line; run card columns in logical properties

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

* Revert "cmux-motion: Chrome tab strip tween ..." (8a3ee62) until the app-ffi release App 403 is fixed (run 38682698310) (hq-1d, chief go 2026-10-15, no bead)

The release App could not publish cmux-app-ffi-854febb26527 (HTTP 403 on
POST /releases), so the app FFI pin check stays red on the tip. The tween
re-lands with the publish and repin after the App is fixed.

* test(ci): nightly jobs that run the license check must init ghostty-next (#20893)

* test(ci): nightly jobs that run the license check must init ghostty-next

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

* fix(ci): nightly recovery initializes ghostty-next before the license check

Apple accepted, stapled and launch-tested each recovered nightly-next build,
then verify-app-bundle-licenses.sh failed on the missing
ghostty-next/build.zig.zon and the build was skipped as not accepted.

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>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: safe-push <safe-push@cmux.local>
teamleaderleo added a commit that referenced this pull request Oct 15, 2026
… one left edge (cx-w4q7j) (#20892)

* test: Chrome group look fixes from the sidebar groups verdict (red)

A collapsed header shows its member count, the members' line starts under the header bar
rounded, the header ink is white or near-black on the group color, and the header name starts
on the ungrouped rows' column (cg-design-judge 2026-10-14, cx-w4q7j).

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

* fix: Chrome group look: collapsed count, line under the bar, on-color ink, ungrouped column

- A collapsed group header shows its member count after the name.
- The members' line starts just under the header bar with a rounded end, so it no longer cuts
  the bar's rounded corner.
- The header ink is white or near-black, whichever reads better on the group color, not the
  theme's text color (grey on the dark green header in Apple System Colors dark).
- The header name starts on the ungrouped rows' leading column (icon there, name on their text
  column), one left edge for headers and ungrouped rows.

cg-design-judge sidebar groups verdict 2026-10-14, cx-w4q7j.

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

* cx-tgf4h red: cmux chief -p under ACPMUX_AGENT_LAUNCH=deny fails at once with a typed refusal

* cx-tgf4h: the Chief says at once that agents are disabled in this build session

With ACPMUX_AGENT_LAUNCH=deny (the nx-remote gui/input default since HQ
#2130) or CMUX_AGENTS_DISABLED=1, no Chief turn can start an agent.
`cmux chief -p` started a daemon and a brain and waited 240 s for a reply
that could not come.

- cmux-tui-core agent_launch: one test of the kill switch (acpmux
  launch_policy.rs), the reason agent_launch_disabled.
- `cmux chief` (pipe and chat) refuses before it starts or sends anything:
  operation.failed, details.reason agent_launch_disabled, exit 1.
- The daemon's supervisor starts no Chief brain; chief.engine.* and
  chief.stop answer the typed refusal at once.
- optchat-chief host does not start (logs why, exit 0).
- Home: the local Chief conversation's notice says agents are disabled;
  the engine panel maps the typed refusal (localized, all Home languages).
- Every Chief proof script refuses at once under deny and names
  `nx-remote --allow-agents`.

* cx-tgf4h review: forward chief control to a running brain first; daemon-side deny test; engine/stop CLI text; guard before side effects; fmt

* cx-tgf4h: fmt and clippy

* cx-tgf4h: keep CmuxNextApp line count (App size cap)

* acpmux: a pooled agent host no longer spins on Linux reading its own record (cx-7z8yx)

The record watch used notify's inotify backend, whose watch mask always
includes open, close-write and modify, and ran its callback on every event.
The callback reads the host record; on Linux that read queued an open and a
close in the watched directory, which ran the callback again. Every pooled
host spun at 100% CPU (about 200,000 read calls a second).

Linux now has its own inotify watch, like the macOS kqueue watch: a mask of
entry changes only (create, delete, moved from/to) and the directory's own
delete or move, one thread in poll with no timeout, an eventfd to stop it.
A read of the record never queues an event. The notify fallback (other
platforms) ignores access events. macOS is unchanged.

Behavior test (tests/host_lifetime.rs, Linux): a real daemon pools a host;
idle for 3 s it makes fewer than 100 read calls and 30 CPU ticks (before:
599,042 reads, 298 ticks), a rename rewrite of its record keeps it, and the
record removed ends it.

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

* ci: nightly-next recovery initializes the notices submodule before continuing accepted submissions

The recovery job's checkout had no ghostty-next submodule, so the bundle
notice check that notarize-nightly-dmg.sh runs after Apple accepts failed,
and run 38669958906 skipped five accepted builds as 'Apple did not accept'.
Initialize the submodule like the signing job does, and make the skip notice
say that a post-acceptance check can also be the cause.

* ci: the cmux NIGHTLY-identity job also initializes the notices submodule

Run 38669958906's publish-nightly-identity-legacy job saw Apple accept,
then failed the bundle notice check for lack of ghostty-next and retired
the accepted submission of run 38609024986.

* Channels view: gallery plays for a message link with no link read (red)

A Cloud conversation has no link resolver (G4), so the Messages view's switch hand-off
#/conversation/<id>/message/<id> showed an error. Two plays: a thread reply and a timeline
message, opened through the store's openLink with an owner that has no resolver. cx-hnmbt

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

* Channels view: open a known conversation's message link without the owner's link read

When conversation-link-resolve fails (a Cloud conversation, an older daemon) and the page knows
the conversation, it opens it, pages the timeline until the message shows, opens its thread when
it is a reply, and marks it. The Messages view's switch hands off Cloud selections this way.
cx-hnmbt

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

* Channels view: format parseConversationLink (vp fmt)

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

* Channels view: link fallback review follow-ups

Ids in a known conversation's link may hold '-' (the gallery's sample ids); the scheme check
follows the daemon (cmux[-<tag>], any case); the fallback runs only for a Cloud conversation or
an owner without a link read, so a refused local link (a deleted message) still shows its error.
cx-hnmbt

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

* acpmux: host_lifetime idle test cleans up from the start and never signals a reused pid (cx-7z8yx review)

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

* cmux-tui: move the build identity into a leaf crate so an edit no longer recompiles cmux-remote

cmux-remote's build script hashed the dirty source tree into
CMUX_TUI_BUILD_IDENTITY, so every edit in the workspace reran it and
recompiled cmux-remote and every crate above it (about 8 s of a 12.6 s
one-line edit loop on rbx). The same build script now lives in
cmux-build-identity, which only cmux-tui reads; cmux-remote takes the
identity as an argument (SshBootstrapConfig::defaults,
pinned_linux_payload). The identity value, its inputs and format, and
every skew and SSH re-bootstrap comparison are unchanged.

* test: warm the dev server in the Claude reasoning default browser test (#20884)

#20592 landed after #20873 without warmViteServer, so check:browser-lanes is
red on base again.

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

* cmux-next: frame-strip report as an NSWindow method, not a namespace enum (no bead) (#20887)

The package conventions lint fails every PR on the new all-static public
enum WindowFrameStrip (cx-me3xd). The report reads its window, so it is an
extension on NSWindow; same body, same report.

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

* Home channels: the run card is an inline disclosure (no frame, steps on an indented rail)

The live and done run cards under a Chief's reply lose their box: "Working
for" / "Worked for", the step count, cost and Open sit inline under the
message, and the opened steps hang on a thin rail under the status mark. The
narrow rules stay: the first line never wraps, and below 480 px of card width
the step count and cost move under it with no leading separator.

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

* Home channels: the run rail and columns follow the author's picture

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

* Home channels: the run sheet keeps its error line; run card columns in logical properties

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

* Revert "cmux-motion: Chrome tab strip tween ..." (8a3ee62) until the app-ffi release App 403 is fixed (run 38682698310) (hq-1d, chief go 2026-10-15, no bead)

The release App could not publish cmux-app-ffi-854febb26527 (HTTP 403 on
POST /releases), so the app FFI pin check stays red on the tip. The tween
re-lands with the publish and repin after the App is fixed.

* test(ci): nightly jobs that run the license check must init ghostty-next (#20893)

* test(ci): nightly jobs that run the license check must init ghostty-next

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

* fix(ci): nightly recovery initializes ghostty-next before the license check

Apple accepted, stapled and launch-tested each recovered nightly-next build,
then verify-app-bundle-licenses.sh failed on the missing
ghostty-next/build.zig.zon and the build was skipped as not accepted.

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

---------

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

* cmux-next: group header count yields to trailing controls; review test fixes

Drop the collapsed count when a narrow sidebar has no room for it, measure the
ungrouped column the way the header's is, expect on-color inks in the palette
test, and mark ChipInks nonisolated like its neighbours.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: safe-push <safe-push@cmux.local>
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