Repository navigation
CmuxNext: a tab dropped on a strip lands by the pointer (cx-6ggef) - #20549
teamleaderleo wants to merge 131 commits into
Conversation
…s its App Attest provider; freeModel.enabled (cx-ds09i) Relay (cmux-coderouter free_tier.rs): attest_provider on the admin socket, peer-checked (same user; a Team-signed build: the cmux app that contains the relay, cmux-link app_caller), production origin only in release apps (staging and the dev Worker only in DEV builds), one provider and one request at a time. The relay builds the client data hash from the server challenge, keeps the free token in memory only (never in status or logs), drops it when the provider ends, when the setting turns off or an account signs in (also for a lease in flight), and starts a lease only at the first signed-out data-plane request (20 s, in its own task). App Attest refuses a second attestation of a key in a later launch, so a new month takes a fresh key. The account bearer wins. App: Packages/Shared/CmuxAppAttest (DeviceAttesting, AppleDeviceAttest, KeychainAttestKeyStore); FreeTierAttestProvider (CmuxNextAgentPane) answers only purpose cmux.free-tier.v1 over a 32-byte hash on an AcpmuxCheckedLine connection, one keychain item per bundle id; AppServices+FreeTier follows freeModel.enabled (default on, MDM lock, agents refused: privacy) and the sign-in (a restoring session counts as signed in). Behavior tests: acpmux/tests/router_free_tier.rs (real relay, admin socket, stand-in app and API; 7 tests, Linux rbx and hosted macOS 38362901804). Red check of the in-flight race at a3b1066 recorded on cx-ds09i. scripts/cmux-next/free-tier-attest-e2e.sh: T1/T2 on a real Mac. Security review hq-84: APPROVE at 8b1c3f8.
…xports reset to the tip before regeneration (cx-ds09i)
…LI (red) (cx-ebm.60.1, cx-ebm.60.2) The person makes, edits and deletes Chiefs with cmux chief new|list|edit|delete; a Chief on its own bound connection changes its own picture and only the fields its self_edit lists; another agent is refused. Red: the daemon has no chief.list/get/create/update/delete/avatar.* operations yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dit|delete (cx-ebm.60.1, cx-ebm.60.2, cx-ebm.60.3) Multiple Chiefs per Chief home (Lawrence 2026-10-14: "create new chiefs too with specific roles, names, ... profile pics (chiefs need to be able to do it themselves too), personality, system prompt, tools"). Daemon: chief_registry.rs owns chiefs.sqlite3 in the session state directory. A record has id (= the conversation participant id; agent_mux is the default Chief, written on first open; new ones agent_<26 base32>), display_name, role, personality, instructions (system prompt additions), avatar (PNG/JPEG/GIF/WebP <= 1 MiB, bytes by SHA-256, collected when no record names them), tools (closed catalog), harnesses, engine, self_edit, is_default, rev. Deleted ids stay as tombstones. Idempotency ledger per caller. cmux.protocol/2: chief.list, chief.get, chief.avatar.get (read); chief.create, chief.update, chief.delete, chief.avatar.set (mutation). Callers: the owner (Unix, no link peer, user_local) and the Chiefs (a connection bound with conversation-bind to a live record's id). A Chief reads every record and changes only its own self_edit fields (default: avatar); tools, harnesses, engine, self_edit, create and delete are the owner's; anything else is chief_self_edit_denied before any write. Pages, WebSocket, relayed and remote connections and non-Chief agents get origin.forbidden. Not MCP tools. CLI: cmux chief list | new --name N [profile] | edit CHIEF [profile] [--clear-avatar] | delete CHIEF, CHIEF an id or a unique name, --json. schemas/chief-profile/tool.json: the Chief's self-edit tool (profile) for the brain (wired in cx-ebm.60.5 after the per-build Chief home lands). Catalog: 271 operations (84 read, 168 mutation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…moved AgentTabPaneSource.paneEnvironment) (cx-ds09i)
…nabled on the tip (cx-ds09i; export-settings cmux-ci step 02f78faaf8d0)
…cx-ebm.60.1, cx-ebm.60.2) Review (correctness subagent, 2026-10-14): - The cloud catalog already has chief.list/create/update with another shape; the app platform merges both catalogs by name with the local op winning, so equal names hid the cloud ops. The daemon ops are now chief.profile.list/get/create/update/delete/avatar.set/avatar.get; the generated app-host types keep the cloud chief.* ops. - idempotency.conflict names the committed operation; the ledger keeps the newest 256 keys per caller. - harness, model and effort are single-line. - CLI: "needs a newer daemon" only when the first chief.profile.list call is refused as unknown; a value error prints the daemon's reason. The picture is checked for 1 MiB before any write; when the picture write fails after the create or edit committed, the CLI says what committed. edit with no change, and --clear-avatar outside edit, are usage errors. - The spec states the trust limit (a Chief turn with a shell is the same OS user; the self_edit rule guards the model); hardening is cx-ebm.60.9. - Generated: app-host d.ts/ops/scopes and the AppPlatform scopes copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-multichief # Conflicts: # cmux-tui/bindings/cpp/.cmux-resource-api.json # cmux-tui/bindings/go/.cmux-resource-api.json # cmux-tui/bindings/java/.cmux-resource-api.json # cmux-tui/bindings/python/.cmux-resource-api.json # cmux-tui/bindings/rust/.cmux-resource-api.json # cmux-tui/bindings/typescript/.cmux-resource-api.json # cmux-tui/bindings/zig/.cmux-resource-api.json # cmux-tui/spec/resource-api-v2.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gate.sh runs split, newterm, split with a slow host, new-tab and cold new-tab proofs on the GUI host and fails on a lost key; typeahead-compare.py counts keys sent by terminal id; creation-hold-proof.py is superseded (named in the gate header)
…testStarter); CmuxNextApp keeps a two-line hook (cx-ds09i; CmuxNextApp size cap)
… the app's life (cx-ds09i; CmuxNextApp size cap)
…ale submodule checkout had moved it back); signed-in fallback true when the services are gone (cx-ds09i move-check)
…plus only the CmuxAppAttest lines (cx-ds09i final check: a stale regeneration had dropped CmuxNextBrowserHistory, CmuxNextCLIInstall, CmuxNextNowPlaying and two CmuxNextCompat test edges)
ae65773 (cx-ds09i; export-settings cmux-ci step 788077f4a088)
…-size baseline takes the tip's 113750 (the tip's own raise covers the hook)
…erves (cx-4bd8m) Austin's cmux NEXT registry grew to 10.7 GB in 8.5 h under a build without journal maintenance (auto_vacuum off, 4.47M journal rows). The maintenance worker's first step converts such a registry with PRAGMA auto_vacuum= INCREMENTAL; VACUUM; while it holds the registry: on that file every client of the owner would read "not connected" for minutes after the next update. Convert only while live data is at most 64 MiB. Above it the conversion is deferred (one diagnostic per owner); sealing still runs and deletes archived rows, and SQLite reuses their pages, so the file stops growing once sealing keeps up. It does not shrink: sealed segments stay in the registry, so giving the free pages back needs a compaction that does not hold the registry (follow-up bead). Debug-only overrides for the interval and the bound keep the behavior test small. Red/green: legacy_registry_maintenance. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Narrow tabs (titles that fit them) still took a right-end drop as before the tab on the first fix: the drop math lays the strip out without title widths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…20534) * test: a local merge commit reuses the fetched same-tree acpmux (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: a local merge commit reuses the fetched same-tree acpmux reload.sh on a developer Mac stopped with "no cached acpmux" for any commit no workflow published (a local integration of feat-cmux-next and PRs), even though the tree fetch had just put that tree's checksum-verified acpmux in place. build-acpmux.sh now seeds its commit cache from it when it has every requested architecture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 7be0d24 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38542356066 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
* webviews: test that every popup draws one hairline edge Red: --acpmux-popup-elevation stacks a composer-edge hairline on the one already in --ui-popup-shadow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: popups draw one hairline, not two --acpmux-popup-elevation stacked a 0.5px composer-edge hairline on the hairline already in --ui-popup-shadow. It now is the shared popup shadow, so every menu and popover has one edge. Increase Contrast colors that one edge in the popup's ink, which the composer-edge hairline did before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 1cc6616 - vp fmt webviews/src/agent-session/acpmux/modelPickerLayout.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38520503432 * webviews: test that popups draw no border over the hairline and clear it under borders none Red: the pages' .ui-popup and the chat find bar draw a border over the --ui-popup-shadow hairline, and appearance.borders none leaves the hairline drawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: one rim on page popups and the find bar; borders none clears it The pages' .ui-popup drew a 1px border over the --ui-popup-shadow hairline; it now draws no border. The chat find bar keeps its border (its focus cue) and casts --ui-popup-drop, the shadow without the hairline. appearance.borders none sets --ui-popup-edge transparent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: format modelPickerLayout.ts (base fmt red) Keeps cmux-autofix's vp fmt of the base file, which the base merge replaced with the unformatted copy; react-apps-check fails on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * webviews: the Channels palette draws one rim; test follows the summary card Red after the base merge: the new Channels palette (.lg-palette, ledger.css) drew a 1px border over the --ui-popup-shadow hairline, and the summary popover became .acpmux-summary-card. The palette now draws no border. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 54dd59d - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38543983469 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
…ggef) The drop math laid the strip out without the chrome style's title widths, so a narrow tab read as twice its drawn width and a drop on its right end landed before it. Both layouts now apply TabTitleWidths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(clears the concurrency red) (#20485) * fix: clear two feat-cmux-next check reds tree-publish-v2's stub uploader takes --conflict-exit-code, which the tree publisher now passes (af8b68e). PaneAnimationsSetting carries the namespace-type justification its ratcheted sibling settings have. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep PaneAnimationsSetting internal to CmuxNextSettings Nothing outside the module uses it, so it needs no namespace-type allow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at c2bdb98 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38530638157 * fix: name the owner of ControlWorkspaceInfoCache's publish hop check-concurrency flags the unowned Task d0a62be added; it is a one-shot main-actor hop that holds the cache weakly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 7cf07e3 - regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38544346314 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
…hover card (#20483) * test: a notified compact row stays one line; its text reads in the hover card Leo 2026-10-14: "why is it even 2 lines in the first place?" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: compact sidebar rows are one line by default; the notification text moves to the hover card sidebar.workspaceRow.notification is now off by default (Leo 2026-10-14). #19862 turned it on for classic parity; the setting stays as an opt-in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings schema hash for the notification default Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings schema hash on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: take base's settings exports after the base merge (regenerated next) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: regenerate the settings exports on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: refresh the defaults snapshot on the merged base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the hover card template lists the notification fact; comments say where the text shows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…p-drop-pointer # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextTabs/TabStripView+Layout.swift
Split plan: no split neededThis PR's real change is 2 files, +196/-3, not 251. The GitHub file list (free tier, Chief registry, backend, webviews, OptChat) is stale: GitHub stops recomputing a conflicting PR's diff.
The free-tier, Chief and settings commits in the list came in through merges of The only conflict is one line: feat's tab-strip refactors changed Slice: #21626, the same two commits (live check, then fix) on the current Recommendation: close this PR once #21626 lands. |
…21626) * test: live check for a drop on another pane's tab (cx-6ggef) strip-drop-e2e.py splits a three-tab workspace right and drags a left tab at hand pace onto the right pane's tab at 85% (expects after) and 15% (expects before) of its width, with default and one-letter titles. On feat DEV 5bf8644 it fails 2/4: both 85% drops land before the tab. Carved from #20549. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CmuxNext: a tab dropped on a strip lands by the pointer (cx-6ggef) An external tab drop resolved as if the pointer were the middle of a phantom tab as wide as the strip's standard width, so the after slot needed the pointer past the tab's right edge plus half a standard width. resolvePhantom now hands resolveTab the pointer itself: the slot edge nearest the pointer wins, where the ghost card sits. Group drags keep their width-based placement. Carved from #20549. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: pin the pointer-midpoint drop slot for a narrow tab (cx-6ggef) resolveTab's doc and parameter still described the card's leading edge; an external drop now passes the pointer. Say so, note the narrow-tab hysteresis limit, and pin 15% and 85% drops on a 48 pt tab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Already landed as #21626, the same change (cx-6ggef); every line of this diff is on feat-cmux-next. Closing. |
Summary
Fixes cx-6ggef. On feat-cmux-next, a tab dragged onto the right end of another pane's last tab landed before that tab, and the golden split-drag case
move.to-other-panefailed (classic's bonsplit passes it). For an external drop, the strip took the pointer for the middle of a phantom tab as wide as the strip's standard width, so the "after" slot needed the pointer past the tab's right edge plus half a standard width.The drop now goes to the slot edge nearest the pointer: past a tab's middle means after it, the way bonsplit and Chrome behave and where the ghost card sits. Group drags keep their width-based placement. The change is in
TabStripView.resolvePhantom(TabStripView+Phantom.swift). The hit test still uses the base layout, so the gap moving doesn't make the index flicker. Same-strip reordering is untouched (it uses the dragged tab's leading edge inTabStripView+Drag).scripts/cmux-next/strip-drop-e2e.py(new) splits a three-tab workspace right and drags a left tab, at hand pace, onto the right pane's tab: at 85% of its width (expects after) and at 15% (expects before). It runs twice: once with default titles, once with one-letter titles (renameTab).Testing
strip-drop-e2e.pysplit-drag.move.to-other-pane, real HID on cua-4resolvePhantomchange, older base)An intermediate commit also gave the drop math title-fitted widths. Base fe71fdf then removed title fitting, so the merge drops it.
Pre-push: crash ratchet, concurrency, god files (TabStripView did not grow), system-blue all pass.
Fleet receipts on 6d02cdb:
check-release-compile.sh(Xcode 26 Release) BUILD SUCCEEDED;run-swift-testing-suites.sh Packages/macOS/CmuxNext296 passed, 1 failed:NowPlayingCardTests(sidebar now-playing card), whose test process died mid-test with no assertion, as in this PR's macOS 27 report-only run. That is unrelated to the tab strip. PR reds that don't gate: Tour the app (infra), rails (red on feat too).Proof
Before/after recording of the tab row, from the app's window snapshots (cua-4 DEV builds): A dropped on the right end of TARGET lands as
A, TARGETbefore andTARGET, Aafter; B at 15% lands first in both. I watched it. The media is published inline at landing.Changelog
Fixed: A tab dropped on the right half of another pane's tab now lands after it, not before
🤖 Generated with Claude Code