- Wrap eval scripts in async IIFE that detects and awaits thenables,
using callAsyncJavaScript when available (macOS 11+) (#603)
- Register console/error telemetry hooks as WKUserScript at document
start so they survive navigation and are active before page JS (#604)
- Return typed envelope {__cmux_t, __cmux_v} from eval to distinguish
undefined from no return value; CLI prints "undefined" (#605)
- Keep dialog hooks as lazy injection only (not document-start) to
avoid suppressing WKUIDelegate native dialogs
- Add regression tests for async wrapper and undefined CLI rendering
Adds `cmux tree` that prints the window > workspace > pane > surface
hierarchy with box-drawing characters. Includes server-side system.tree
RPC for single-round-trip performance.
Features:
- --all flag for all windows (default: current window only)
- --workspace flag to filter to a single workspace
- --json for structured JSON output
- Active path markers (◀ active) and caller identification (◀ here)
- Browser surfaces show their current URL
Closes https://github.com/manaflow-ai/cmux/issues/586
Add a cached lazy keychain fallback to SocketControlPasswordStore so
that authentication paths in TerminalController can transparently read
a legacy keychain password without blocking on every request. The
keychain is read at most once and the result is cached behind an
NSLock. File-based and environment passwords still take priority.
Closes https://github.com/manaflow-ai/cmux/issues/579
* Fix manual unread clear race on focused tab
* Add mark-as-read tab action and show ring for manual unread
* Flash then clear manual unread on tab focus
* Add tmux rename-window workspace compatibility
Implement workspace.rename in the v2 API and wire CLI commands rename-workspace/rename-window with help text.
Add a regression test that validates API and CLI rename parity plus error handling.
Refs: https://github.com/manaflow-ai/cmux/issues/153
* Add full tmux compatibility command matrix and regression coverage
Addresses review feedback from https://github.com/manaflow-ai/cmux/pull/219 by resolving read-screen targets against requested workspace/surface instead of the selected workspace.
* Move port scanning from shell to app-side with batching
Replace per-shell `ps -axo + lsof` scanning with a centralized
PortScanner singleton in the app. Each shell now sends lightweight
`report_tty` (once per session) and `ports_kick` (on preexec/precmd)
socket messages. The app coalesces kicks across all panels and runs a
single `ps -t <ttys> + lsof -p <pids>` covering every active panel.
Also fixes a macOS 26 Tahoe regression where `getsockopt(LOCAL_PEERPID)`
returns ENOTCONN on accepted sockets when the peer disconnects before
the handler thread starts. This was silently breaking ALL socket
commands sent via ncat --send-only. The fix captures the peer PID in
the accept loop immediately after accept(), and falls back to
LOCAL_PEERCRED (uid check) when the PID lookup fails.
* Fix PR review feedback: burst timing and auth comment clarity
- P2: burstDelays were accumulating (0.5+1.5+3+... = ~22.5s) instead of
firing at absolute offsets from burst start. Now uses burstStart anchor
so scans fire at 0.5s, 1.5s, 3s, 5s, 7.5s, 10s as intended.
- P1: Clarify LOCAL_PEERCRED fallback rationale — same security boundary
as socket file permissions (0600), does not widen attack surface.
Long-lived connections still get full descendant check via LOCAL_PEERPID.
* Socket access control: process ancestry check + file permissions
Redesign socket control modes from (off, notifications, full) to
(off, cmuxOnly, allowAll):
- cmuxOnly (default): uses LOCAL_PEERPID + sysctl process tree walk to
verify the connecting process is a descendant of cmux. External
processes (SSH, other terminals) are rejected.
- allowAll: hidden mode accessible only via CMUX_SOCKET_MODE=allowAll
env var, skips ancestry check. Legacy "full"/"notifications" env
values map here for backward compat.
- off: disables socket entirely.
Security hardening:
- Server: chmod 0600 on socket after bind (owner-only access)
- CLI: stat() ownership check before connect (reject fake sockets)
Removes per-command allow-list (isCommandAllowed) — once a process
passes the ancestry check, all commands are available.
Includes migration for persisted UserDefaults values and env var
aliases (cmux_only, cmux-only, allow_all, allow-all).
* Add /sync-branch skill for submodule + main sync