fix: restore nightly CLI compilation after Cursor approvals - #10820
Merged
Merged
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe CLI now persists approval metadata without the legacy command text. The Cursor persistence test verifies command length and omission. Project-root discovery uses a renamed variable and retains the current-directory fallback. ChangesCursor hook persistence
Project-root discovery
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: ✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
austinywang
added a commit
that referenced
this pull request
Aug 26, 2026
… in the rebase The pre-rebase toolchain-fix commit had absorbed these cmux.swift hunks when it was amended, so dropping it in favor of main's #10820/#10822 dropped them too: the vm-tui-connect dispatch, tui in every vm usage string and the help block, and the internal access on applyWindowOrCallerContext / setTerminalForegroundProcessGroup that CMUXCLI+VMTui.swift needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
austinywang
added a commit
that referenced
this pull request
Aug 26, 2026
… in the rebase The pre-rebase toolchain-fix commit had absorbed these cmux.swift hunks when it was amended, so dropping it in favor of main's #10820/#10822 dropped them too: the vm-tui-connect dispatch, tui in every vm usage string and the help block, and the internal access on applyWindowOrCallerContext / setTerminalForegroundProcessGroup that CMUXCLI+VMTui.swift needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
austinywang
added a commit
that referenced
this pull request
Aug 26, 2026
… in the rebase The pre-rebase toolchain-fix commit had absorbed these cmux.swift hunks when it was amended, so dropping it in favor of main's #10820/#10822 dropped them too: the vm-tui-connect dispatch, tui in every vm usage string and the help block, and the internal access on applyWindowOrCallerContext / setTerminalForegroundProcessGroup that CMUXCLI+VMTui.swift needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
austinywang
added a commit
that referenced
this pull request
Aug 26, 2026
… in the rebase The pre-rebase toolchain-fix commit had absorbed these cmux.swift hunks when it was amended, so dropping it in favor of main's #10820/#10822 dropped them too: the vm-tui-connect dispatch, tui in every vm usage string and the help block, and the internal access on applyWindowOrCallerContext / setTerminalForegroundProcessGroup that CMUXCLI+VMTui.swift needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
austinywang
added a commit
that referenced
this pull request
Aug 27, 2026
…kspaces project them (local + cloud, one drag/drop path) (#10887) * cloud: one bulky free machine with a 5-day window, Pro gets five Plan shape: the free plan now includes one full-size machine (24 GB default and cap — the free machine demos the product; the paywall is the window and the count, not the machine's usefulness) and Pro includes five machines (24 GB default, 32 GB cap). 24576 joins the memory picker options. All numbers stay env-overridable per plan. Free access window: a free-plan machine older than 5 days (CMUX_VM_FREE_ACCESS_WINDOW_DAYS, 0 disables) is preserved but unreachable — attach, ssh, exec, ports, and sessions fail with a 402 vm_access_requires_pro upgrade prompt, while list/status/rename/delete keep working so the machine stays visible and disposable. The gate keys on the caller's CURRENT plan, so upgrading unlocks existing machines immediately. Enforced in one place (requireAccessibleUserVm) that every access workflow shares; the five REST routes thread the caller's plan and map the typed error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Machines panel: free-window countdowns and locked rows (#10760) * machines: surface the free access window — countdown rows, locked rows, upgrade routing The list payload now carries freeAccessWindowDays (0 for paid plans) so clients render policy from the wire instead of hardcoding it. The Machines panel mirrors the backend's window math per row: free-plan machines show a days-left countdown in the subtitle, and a machine past the window renders locked — lock glyph in place of the activity dot, Locked in the subtitle, and double-click/context-menu routing to the shared Pro upgrade presenter instead of a doomed connect (the backend still enforces with 402s; the UI just stops walking into them). Rename/Status/Delete stay available on locked rows so the machine remains manageable and disposable. Strings localized en+ja; snapshot window math unit-tested against the backend's boundary behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * machines: flip free-window rows at the boundary itself, not on a poll tick Review follow-up: the countdown/lock facet was only as fresh as the 45s list poll. Expiry is a known future timestamp the client can compute (createdAt + window), so the panel now arms a one-shot timer at exactly the next transition across the fleet — each day-boundary where the label decrements, and finally the expiry — and recomputes the facet locally with no network, re-arming for the next boundary. Rows flip at the moment the state changes; the slow poll is left covering only what genuinely needs the server (machines created or deleted elsewhere). The recompute happens above the lazy-list snapshot boundary, so the panel's snapshot rule (cmux#2586) holds. Boundary math unit-tested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: cmux reload-cloud <cmux-reload-cloud@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * worktree: drop stored defaults on identity lets so Xcode 26.6 builds main After #10781, worktreeDeviceID/worktreeFileID were both defaulted at the declaration and assigned in the explicit init, which the current toolchain rejects ("immutable value may only be initialized once"). The init's parameter defaults keep the same call-site contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cli: cmux vm run/push/pull/wait and the cmux-cloud-vm agent skill vm run routes a command to a cloud machine without naming one: sticky per-directory binding, then an idle agent-pool machine, then a sleeper, then a freshly provisioned pool machine. push/pull move files over the exec channel (base64 chunks, SHA-256 verified, directories as tarballs); wait blocks until ready and optionally wakes the machine. The skill lets any coding agent drive machines from plain CLI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vm push: 64 KiB argv-bound chunks, no AppleDouble sidecars, line-safe progress Live dogfood on Blaxel: a 512 KiB chunk base64-encodes past Linux's 128 KiB per-argument limit ("argument list too long"), macOS tar shipped ._* files onto the machine, and chunk progress ran together when stderr was captured. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vm run: pool membership is the persisted id list, not the display label; review fixes - The router now only drafts machines it provisioned itself (ids recorded in ~/.cmuxterm/vm-run-pool.json at create time, pruned when machines vanish); a user machine renamed agent-pool is never used. Test covers the impostor. - Staging tarball is removed if reading it throws before the defer is armed. - Push/pull chunk progress is localized (cli.vm.push.progress, cli.vm.pull.progress). - vm --help, the usage contract, and the contract doc list open/ports/tools/ handoff/promote-template, which the dispatcher already handled. - Sticky-binding fixture uses a fixed instant, not the host clock. - Skill recipes: --sync runs inside the synced dir (no remote $PWD), port readiness poll instead of sleep, eligibility filter instead of .vms[0], background test exit status captured to a status file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: free access window is 7 days Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vm run: lock the pool store across processes; idempotent, run-scoped recipes - updateVMRunPool does the read-modify-write under flock on a sibling lock file, so two routers provisioning at once both land in the store; covered by a two-process test against two mock sockets. - Dev-server recipe reuses a live server or starts one with a workspace pidfile and log; test recipe uses per-run log/status paths written atomically. - Document that --sync is additive. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * vm run: pool-store failures propagate; recipes validate the dev server and use unique run ids - updateVMRunPool/saveVMRunPool throw on lock or write failure and createPoolVM reports the machine it provisioned but could not record, instead of a silent unlocked update. - The dev-server recipe reuses a server only when the recorded pid is alive and owns :3000 (netstat -p), refuses to start a second server on a port someone else owns, and clears stale metadata. - Test-run ids come from uuidgen, not the epoch second. - Skill docs: cmux vm shell is a cmux-tui session now that machines run the cmux-tui remote daemon; agents keep working through vm run/exec. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: run the cmux-tui remote daemon on Blaxel machines beside cmuxd-remote (Phase 1) Implements the next open item of docs/cloud-cmux-tui-daemon.md (#10800): every Blaxel machine gets the pinned static-musl cmux-tui (CMUX_VM_BLAXEL_TUI_URL + _SHA256, verified in-VM, installed on the persistent home volume) running `server start --remote-ws` under the sandbox supervisor, with its own private preview. attach-endpoint accepts transport:"cmux-remote" and returns the tokenized /v1/link route plus a single-use enrollment invitation when the caller's device is not enrolled; a new cmux-remote/approve route approves the pending claim the control plane invited. Opt-in per deployment; no change for clients that do not ask. Measured on Blaxel: a WebSocket upgrade with the preview token as a query parameter completes on the raw <hash>.preview.bl.run host but is refused through the vm.cmux.sh custom domain, so the daemon preview is created unbranded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: cmux vm shell and the Machines panel open cmux-tui sessions - `cmux vm tui <id>` and, by default, `cmux vm shell <id>` (which the Machines panel launches) open a workspace whose pane runs the local cmux-tui client against the machine's authenticated /v1/link route; the hidden vm-tui-connect helper hands the terminal to the client and approves the device enrollment through the app socket, remembering the device fingerprint per machine. The websocket attach remains only for deployments without a cmux-tui pin. - Socket methods vm.cmux_remote_info / vm.cmux_remote_approve and the VMClient calls behind them; capabilities list updated. - With the pin configured, new Blaxel machines get cmux-tui only: no cmuxd-remote install or process; the sleep watcher counts cmux-tui's terminal children as work. - Client discovery probes candidates with `remote-probe --json` so the SSH-remote bootstrap's shell wrapper at ~/.cmux/bin/cmux is skipped. - Localized en+ja strings; help, usage contract and docs updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * blaxel: fresh-machine cmux-tui bootstrap waits for the sandbox API and installs curl Found by creating a machine under the pin: a just-created sandbox 404s its API for a few seconds (the cmuxd path only survived because encoding the Go binary took that long), and a stock blaxel/base-image has no curl until the background provisioning adds it. The first write now retries until the API answers, and the installer adds curl via apk or falls back to busybox wget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: cmux-tui is pinned by the published manifest and the app bundles the client - The Blaxel driver resolves the daemon build from the artifacts manifest (rolling latest by default, CMUX_VM_CMUX_TUI_MANIFEST_URL to pin a commit, CMUX_VM_CMUX_TUI_ENABLED=0 as the kill switch); the sha256 comes from the manifest, never from env. An installed daemon that no longer matches the manifest is reinstalled on attach. The endpoint reports the daemon's build identity and remote protocol. - scripts/install-cmux-tui-client.sh bundles a universal, sha256-verified cmux-tui client into Contents/Resources/bin like the Ghostty helper; reload.sh, ci.yml and release.yml run it. The CLI looks there first and checks the client/daemon remote protocol before opening a pane, naming the stale side. - cmux-tui-artifacts.yml publishes on main pushes again so latest/ tracks main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cmux-remote: send a User-Agent on direct WebSocket dials Hosted ingress in front of cmux Cloud machines (CloudFront on the branded vm.cmux.sh domain) refuses upgrades that omit User-Agent, and tungstenite sends none by default, so the daemon route had to fall back to the raw preview host. Direct dials now carry cmux-tui/<version>; no Origin is set because the daemon rejects browser-style upgrades. Unit test covers the header and that the endpoint query (route token, lane) survives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * nightly: bundle the cmux-tui client like ci/release do Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * integration: restore vm tui dispatch/usage/help/helper access * cloud: one bulky free machine with a 5-day window, Pro gets five Plan shape: the free plan now includes one full-size machine (24 GB default and cap — the free machine demos the product; the paywall is the window and the count, not the machine's usefulness) and Pro includes five machines (24 GB default, 32 GB cap). 24576 joins the memory picker options. All numbers stay env-overridable per plan. Free access window: a free-plan machine older than 5 days (CMUX_VM_FREE_ACCESS_WINDOW_DAYS, 0 disables) is preserved but unreachable — attach, ssh, exec, ports, and sessions fail with a 402 vm_access_requires_pro upgrade prompt, while list/status/rename/delete keep working so the machine stays visible and disposable. The gate keys on the caller's CURRENT plan, so upgrading unlocks existing machines immediately. Enforced in one place (requireAccessibleUserVm) that every access workflow shares; the five REST routes thread the caller's plan and map the typed error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Machines panel: free-window countdowns and locked rows (#10760) * machines: surface the free access window — countdown rows, locked rows, upgrade routing The list payload now carries freeAccessWindowDays (0 for paid plans) so clients render policy from the wire instead of hardcoding it. The Machines panel mirrors the backend's window math per row: free-plan machines show a days-left countdown in the subtitle, and a machine past the window renders locked — lock glyph in place of the activity dot, Locked in the subtitle, and double-click/context-menu routing to the shared Pro upgrade presenter instead of a doomed connect (the backend still enforces with 402s; the UI just stops walking into them). Rename/Status/Delete stay available on locked rows so the machine remains manageable and disposable. Strings localized en+ja; snapshot window math unit-tested against the backend's boundary behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * machines: flip free-window rows at the boundary itself, not on a poll tick Review follow-up: the countdown/lock facet was only as fresh as the 45s list poll. Expiry is a known future timestamp the client can compute (createdAt + window), so the panel now arms a one-shot timer at exactly the next transition across the fleet — each day-boundary where the label decrements, and finally the expiry — and recomputes the facet locally with no network, re-arming for the next boundary. Rows flip at the moment the state changes; the slow poll is left covering only what genuinely needs the server (machines created or deleted elsewhere). The recompute happens above the lazy-list snapshot boundary, so the panel's snapshot rule (cmux#2586) holds. Boundary math unit-tested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: cmux reload-cloud <cmux-reload-cloud@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * cloud: free access window is 7 days Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: run the cmux-tui remote daemon on Blaxel machines beside cmuxd-remote (Phase 1) Implements the next open item of docs/cloud-cmux-tui-daemon.md (#10800): every Blaxel machine gets the pinned static-musl cmux-tui (CMUX_VM_BLAXEL_TUI_URL + _SHA256, verified in-VM, installed on the persistent home volume) running `server start --remote-ws` under the sandbox supervisor, with its own private preview. attach-endpoint accepts transport:"cmux-remote" and returns the tokenized /v1/link route plus a single-use enrollment invitation when the caller's device is not enrolled; a new cmux-remote/approve route approves the pending claim the control plane invited. Opt-in per deployment; no change for clients that do not ask. Measured on Blaxel: a WebSocket upgrade with the preview token as a query parameter completes on the raw <hash>.preview.bl.run host but is refused through the vm.cmux.sh custom domain, so the daemon preview is created unbranded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: cmux vm shell and the Machines panel open cmux-tui sessions - `cmux vm tui <id>` and, by default, `cmux vm shell <id>` (which the Machines panel launches) open a workspace whose pane runs the local cmux-tui client against the machine's authenticated /v1/link route; the hidden vm-tui-connect helper hands the terminal to the client and approves the device enrollment through the app socket, remembering the device fingerprint per machine. The websocket attach remains only for deployments without a cmux-tui pin. - Socket methods vm.cmux_remote_info / vm.cmux_remote_approve and the VMClient calls behind them; capabilities list updated. - With the pin configured, new Blaxel machines get cmux-tui only: no cmuxd-remote install or process; the sleep watcher counts cmux-tui's terminal children as work. - Client discovery probes candidates with `remote-probe --json` so the SSH-remote bootstrap's shell wrapper at ~/.cmux/bin/cmux is skipped. - Localized en+ja strings; help, usage contract and docs updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * blaxel: fresh-machine cmux-tui bootstrap waits for the sandbox API and installs curl Found by creating a machine under the pin: a just-created sandbox 404s its API for a few seconds (the cmuxd path only survived because encoding the Go binary took that long), and a stock blaxel/base-image has no curl until the background provisioning adds it. The first write now retries until the API answers, and the installer adds curl via apk or falls back to busybox wget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: cmux-tui is pinned by the published manifest and the app bundles the client - The Blaxel driver resolves the daemon build from the artifacts manifest (rolling latest by default, CMUX_VM_CMUX_TUI_MANIFEST_URL to pin a commit, CMUX_VM_CMUX_TUI_ENABLED=0 as the kill switch); the sha256 comes from the manifest, never from env. An installed daemon that no longer matches the manifest is reinstalled on attach. The endpoint reports the daemon's build identity and remote protocol. - scripts/install-cmux-tui-client.sh bundles a universal, sha256-verified cmux-tui client into Contents/Resources/bin like the Ghostty helper; reload.sh, ci.yml and release.yml run it. The CLI looks there first and checks the client/daemon remote protocol before opening a pane, naming the stale side. - cmux-tui-artifacts.yml publishes on main pushes again so latest/ tracks main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cmux-remote: send a User-Agent on direct WebSocket dials Hosted ingress in front of cmux Cloud machines (CloudFront on the branded vm.cmux.sh domain) refuses upgrades that omit User-Agent, and tungstenite sends none by default, so the daemon route had to fall back to the raw preview host. Direct dials now carry cmux-tui/<version>; no Origin is set because the daemon rejects browser-style upgrades. Unit test covers the header and that the endpoint query (route token, lane) survives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * nightly: bundle the cmux-tui client like ci/release do Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cli: restore the vm tui dispatch, usage, help, and helper access lost in the rebase The pre-rebase toolchain-fix commit had absorbed these cmux.swift hunks when it was amended, so dropping it in favor of main's #10820/#10822 dropped them too: the vm-tui-connect dispatch, tui in every vm usage string and the help block, and the internal access on applyWindowOrCallerContext / setTerminalForegroundProcessGroup that CMUXCLI+VMTui.swift needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: the free access window gates cmux-tui attaches too openVmCmuxRemote and approveVmCmuxRemoteEnrollment resolve the machine through requireAccessibleUserVm with the caller's current plan, and both routes map VmFreeAccessExpiredError to the same 402 upgrade prompt the websocket attach uses, so a free machine past its window is locked on every transport. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cmux-remote: rustfmt * integration: rustfmt * cmux-tui: remote-probe advertises direct-ws-user-agent So a control plane can hand a client the branded machine host only when its direct WebSocket dials carry a User-Agent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: portable sha256sum pin check for cmux-tui install; advertise direct-ws-user-agent capability The cmux-tui install script used `sha256sum -c -s`; `-s` is BusyBox-only and GNU coreutils (the xfce-vnc desktop image) rejects it, so every create failed with `sha256sum: invalid option -- 's'` and POST /api/vm returned 502. Redirect output instead, which both implementations accept. Also plumb `clientCapabilities` from the attach request through to the Blaxel driver so only cmux-tui clients that send a User-Agent get the branded machine host. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: cloud cmux-tui daemon design (from #10800) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: Blaxel machines are cmux-tui only; desktop pane redirects top-level; home volume scales with memory - Remove cmuxd-remote from the Blaxel driver: no daemon injection, no CMUX_VM_BLAXEL_DAEMON_*, no legacy websocket PTY attach, no kill switch. The watcher, previews and revoke paths are cmux-tui only; the machine's bare branded host (<machine>.vm.cmux.sh) now belongs to the cmux-tui preview. openAttach on Blaxel fails with vm_attach_transport_unsupported (409) pointing clients at transport "cmux-remote". - Desktop wrapper: the noVNC page is a top-level redirect, not an iframe. The gateway's bl_preview_token cookie is third-party inside a cross-site frame and WebKit drops it, which rendered unstyled noVNC with a dead Connect button. Also opts the page out of prerendering (connection()) and drops the nested html/body layout that caused hydration mismatches. - Home volume: 24 GB plan default machines got a 5 GB disk. Size the volume from memory (<=16 GB -> 32 GB, <=32 GB -> 64 GB, else 128 GB); CMUX_VM_BLAXEL_HOME_VOLUME_MB still wins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: every Cloud VM open goes through cmux-tui; exec the client in place so the pane can type - vmOpenShell is the single open path for vm new/fork/restore/shell/attach/base open/base reset, the sidebar cloud button and the Machines panel; it opens the cmux-tui workspace first and only falls back to websocket/SSH when the control plane reports no cmux-tui at all. vm_attach_transport_unsupported is never a fallback signal. - vm-tui-connect no longer spawns the client and races tcsetpgrp: it starts a detached vm-tui-approve helper for the enrollment approval and execs the cmux-tui client in place, so the pane's foreground process is the TUI from its first tty read. Intermittent swallowed keystrokes came from the client reaching raw mode before the handoff. - The desktop split re-focuses the terminal surface after opening. - remote-probe capabilities are forwarded as clientCapabilities so the control plane can hand out the branded <machine>.vm.cmux.sh route to clients that send a User-Agent. - Workspaces carry a cloud VM binding (workspace.cloud_vm_bind) so Base detection works without a legacy remote configuration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: provision machines with the standard toolset and agents; clamp home volume to Blaxel's 16 GB ceiling The old provision step was Alpine-only (apk) and a no-op on the Ubuntu desktop image, so a machine came with python3 and wget and nothing else. Machines now run a background provisioning script on every bootstrap: ripgrep/fd/jq/tmux/git/curl/gh/xdotool, node 22, bun, uv, Claude Code / Codex / OpenCode / Pi (into the persistent /root so they survive sandbox resurrection), and the CUA driver (cua-computer-server) where the image lacks it. Blaxel refuses volumes above 16 GB, so the memory-scaled tiers stop there: <=4 GB -> 8 GB, otherwise 16 GB (the 24 GB plan default previously got 5 GB). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * web: desktop wrapper route is never instant-navigated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: free plans read 'N of 1 machine' and show when free cloud access expires The list payload carries a server-authoritative freeAccessExpiresAt per machine (and the earliest across them). The Machines panel meter uses singular/plural forms, and free plans get a banner under the control bar counting down the 7-day window (expires in 6d 23h / expires today / expired) that opens the existing Pro upgrade flow. cmux vm ls prints the same footer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: shared Cloud tree model (machines → cmux-tui workspaces → terminals, desktop, ports) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cli: cmux vm tree / open <target> / route / agent, and the cloud-vm skill teaches agents to route work to machines vm tree shows machines → cmux-tui workspaces → terminals (title, cwd, agent badge, open marker), desktop and ports; vm open addresses any node (<m>/<ws>/<term>, <m>:desktop, <m>:port/<n>) and keeps the <id> <port> form; vm route exposes the machine chooser vm run already uses; vm agent runs Claude Code / Codex / OpenCode / Pi inside the chosen machine's cmux-tui session as a new terminal that shows up in the tree. vm desktop and the shell's desktop split share one path (vm.desktop_open). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: Finder-like Cloud tree in the right sidebar with drag-to-pane The Cloud tab is an NSOutlineView: machine → Workspaces (cmux-tui) → terminals (lifecycle, title, cwd, agent badge, open marker) → Desktop → Ports, with asleep/connecting/error placeholders, persisted expansion, keyboard navigation, per-node context menus, and a com.cmux.cloud-surface.transfer drag that drops a terminal, desktop or port as a pane at the drop position through the same CloudTreeServicing path the CLI uses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud: headless cmux-tui links per machine, tree service, and vm.tree/terminal_open/terminal_new/desktop_open/port_open/link_socket The app keeps one headless 'remote connect --headless --json' link per awake machine (never waking a sleeping one), reads 'session current snapshot' and follows 'session current events' to build the Cloud tree, and opens a remote terminal locally as a pane running 'attach --terminal <id>'. Bindings between local surfaces and remote terminals make terminal_open reuse an open pane. Deleting a machine now closes its cmux-tui-bound workspace too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: CLIVMTransferTests uses ProcessRunResult; cloud drop handler is main-actor isolated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: resolve the cloud tree service inside the main-actor drop handler Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: cloud tree menu item action runs on the main actor Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: Int64 createdAt literals in MachinesPanelModelTests; drop a no-op await in the link manager Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: persist the cloud VM workspace binding in the session snapshot Restored vm:<id> workspaces keep their WorkspaceCloudVMBinding so workspace(forCloudVMID:), the sidebar cloud button's Base reuse, and vm.terminal_open find the machine's workspace again after relaunch. Only the binding is persisted; the pane's one-shot link is not replayed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: cloud VM binding survives the session snapshot round-trip Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: clear the five Swift warnings over the CI budget Three never-mutated vars and an unused optional binding in CLI/cmux.swift and TerminalController+MobileWorkspaceList.swift, plus the occlusion observer in GhosttyTerminalView calling a main-actor method from its main-queue closure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cli: opening a machine lands a plain terminal pane; vm tui is the explicit full-client attach vm new / base open / shell / fork / restore, the sidebar cloud button and the Machines panel now create a terminal in the machine's cmux-tui session through vm.terminal_new and show it as a single-terminal pane (attach --terminal), like an ssh session — no cmux-tui sidebar or tabs in the pane. vm tree renders link state (connecting / asleep / error) instead of hiding it behind '(none yet)'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud tree: drops honor the drop side; monochrome rows A drag from the Cloud tree now carries the real Bonsplit destination (pane, orientation, insert-first → left/right/up/down, or tab index) through CloudTreeOpenTarget into the same surface.split / surface.create path every other pane drag uses, so dropping on the left edge splits left instead of always splitting right. vm.terminal_open/desktop_open/port_open accept pane_id/surface_id/direction/tab_index. Rows follow the Files sidebar: secondary/tertiary labels and template symbols, one status dot per machine, a single dim 'CPU · Mem · Disk' line instead of colored gauges. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cmux-tui: freeze the operation catalog at 125 after terminal.output_read #10855 added terminal.output_read to spec/resource-operations-v2.json without bumping the frozen count in test_check_resource_api_boundary, so the cmux-tui SDKs and cmux-tui spec checks fail on every merge with main (125 != 124). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud tree: one row grid — chevron slot, icon column, dot with its own slot, chevron on the name line Every row lays out as (level+1)×16pt indent → 6pt → 16pt icon slot → 8pt → title, so glyphs form a column and rows without a chevron reserve its slot. Machine rows put the status dot in its own 10pt slot and top-align the disclosure with the name line instead of letting it float between the subtitle lines next to the dot. Trailing markers get a 10pt gap and an 8pt edge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud tree: an untitled terminal shows its cwd or 'terminal', never its raw id Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * surfaces: the catalog — terminals, screens and browsers as resources; panes as projections One @mainactor owner (SurfaceCatalog) holds resource identities (local | cloud machine × terminal | screen | browser) and their projections (resource, workspace, panel). Providers push resources in and materialize panes; project(_:into:) is the single open/reuse path; projections persist as records and re-resolve when a provider reports the resource again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * surfaces: local + cmux-tui providers, the tree as a catalog view, one drag path, surface.* socket + CLI - LocalSurfaceProvider registers every terminal/browser pane as a resource; projections are recorded at the single panels-will-change seam (add/remove/transfer), moved on tab transfer, and persisted (remote ones) as surfaceProjections in the session snapshot; a restored remote pane is a placeholder until its provider re-projects it. - CmuxTuiSurfaceProvider (one per cloud machine, registry-driven) turns the headless link's snapshot/events into terminal / screen / port-browser resources and materializes panes through SurfacePaneFactory — the one place a SurfaceDestination becomes a pane. - The right-sidebar tree is a view of SurfaceCatalog.snapshot: This Mac first (terminals grouped by local workspace, browsers), then each machine (workspaces → terminals, Desktop, Ports); every open is catalog.project; one com.cmux.surface-resource drag/drop path for every row and both machines, landing at the drop pane and edge. - surface.catalog / surface.project / surface.new_terminal socket methods; vm.* wrappers keep their shapes; cmux vm tree / surface ls|open|new-terminal on the CLI; vm new/shell/agent create terminals through the catalog. CloudTreeService/ServiceAccess/Model are gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: machine deletion tells the cmux-tui provider registry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: quote the Workspace+SurfaceCatalog.swift path in the project Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: SurfacePaneFactory imports Bonsplit for PaneID Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: snapshot memberwise argument order Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: agent payload literal is [String: Any] Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: refresh task is explicitly Task<Void, Never> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: provider init sets machineID Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * surfaces: socket destinations accept pane/surface handle refs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: irx keepalive waits for the first pong with a deadline instead of a fixed sleep Inherited from #10782; the test-determinism gate on main flags the sleep-then-assert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * surfaces: resolve split anchors through the workspace's live panes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * surfaces: one catalog change notification per runloop turn Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud tree: cloud machines only for now; no reloads during a drag; coalesced catalog reads The sidebar shows only cloud machines (This Mac stays in the catalog and behind CloudTreeNodeBuilder.includesLocalMachine). Catalog changes collapse to one read per runloop turn, are deferred while a drag is in flight, and update rows in place when the tree structure is unchanged — a busy remote shell retitling no longer re-runs reloadData under the cursor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: test files import the app as cmux_DEV under the CI scheme; two warnings under budget Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cloud tree: drop the unused stats gauge view and four orphaned strings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: main-actor tree tests run on the main actor Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: cmux reload-cloud <cmux-reload-cloud@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cmux-clicompilation under Xcode 26.5 / Swift 6.3 by explicitly encoding the persistedPendingCursorShellApprovalfields while keeping the legacycommandkey decode-only.projectRootbinding is not an invalid redeclaration.cmux163: #10787 nightly worktree compilation.Testing
CLINotifyProcessIntegrationRegressionTests.testCursorShellApprovalDistinguishesUnsandboxedAndSandboxedPayloadsto assert that persisted approval metadata round-trips through the real CLI hook path and does not emit the legacy decode-only key.ef4670da0f.3704118e5f.git diff --check, pbxproj normalization, package-resolved policy, workspace package grouping, and test wiring). The mandated file-length script/TSV is absent from this checkout; no budget file was created or changed.Demo Video
Not applicable: compiler-only repair.
Review Trigger (Copy/Paste as PR comment)
Checklist
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by CodeRabbit