Propagate workspace remote state + heartbeat into browser panels, add heartbeat emission in remote session controller, extend docker bootstrap regression for heartbeat continuity after blank browser open, and scrub workspace/surface env vars in tagged reload launches.
* Set cmux TestAction to Debug for UI tests
* Broaden XCTest detection for debug launch gate
* Fix AutomationSocketUITests launch hang in CI
* Stabilize CI Swift package resolution for test jobs
* Stabilize Xcode Cloud UI test focus and socket handling
* Add Xcode Cloud pre-xcodebuild submodule bootstrap
* Harden Xcode Cloud bonsplit bootstrap fallback
Sidebar body was calling sidebarOrderedPanelIds() multiple times per
render for branches, directories, and pull requests. Now computes it
once and passes through. Reduces redundant work during scroll frames.
Closes https://github.com/manaflow-ai/cmux/issues/655
- Notification/focus flash uses workspace customColor (fallback: accent)
- Selection bar/indicator uses workspace customColor when set
- Flash color propagated through Panel.triggerFlash(color:) API
- Browser panel flash overlay uses workspace color
- Regression tests for flash color resolution
Fixes https://github.com/manaflow-ai/cmux/issues/557
* Add "Open Folder…" command to open a workspace at a chosen directory
Adds a native folder picker (NSOpenPanel) accessible from:
- Command Palette (⌘⇧P → "Open Folder…")
- File menu with ⌘O shortcut
Selecting a folder opens a new workspace at that path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Rename openRepository → openFolder, add customizable shortcut
- Rename command ID from palette.openRepository to palette.openFolder
- Register openFolder in KeyboardShortcutSettings (default: Cmd+O)
- Wire menu bar shortcut through settings instead of hardcoding
- Add commandPaletteShortcutAction mapping for shortcut hint display
* Dismiss command palette before showing Open Folder panel
The NSOpenPanel.runModal() call blocked the main thread, keeping the
command palette visible behind the file picker. Wrapping in
DispatchQueue.main.async lets the palette dismiss first.
* Trigger GitHub PR refresh
---------
Co-authored-by: michalstrnadel <michal.strnadel@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Registers palette.triggerFlash wired to triggerFocusFlash() (same as
Cmd+Shift+H). Shortcut hint reads from KeyboardShortcutSettings so it
stays in sync with custom bindings.
Closes https://github.com/manaflow-ai/cmux/issues/633
Adds CmuxCLIPathInstaller with symlink management at /usr/local/bin/cmux,
exposed via Cmd+Shift+P command palette (VS Code style). Install entry
shown when CLI is not in PATH, uninstall entry shown when it is.
Falls back to osascript admin privilege escalation when /usr/local/bin
is not user-writable. Uses attributesOfItem instead of fileExists to
correctly handle dangling symlinks from relocated app bundles.
Closes https://github.com/manaflow-ai/cmux/issues/618
Cmd+Shift+Enter toggles zoom on the focused pane, expanding it to fill
the workspace. Splitting or creating new tabs auto-unzooms. Zoom state
shown as icon in sidebar tab. Includes bonsplit zoom toggle support.
Closes https://github.com/manaflow-ai/cmux/issues/136
Add nil guard in forceRefresh() to prevent dereferencing freed surface
pointer. Split else-if chains in Workspace.swift so
requestBackgroundSurfaceStartIfNeeded() runs if surface is freed during
the refresh call. Add regression test exercising the crash path.
- 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
Add window-identity check to windowDragHandleShouldCaptureHit so stale
leftMouseDown events from other apps (Finder, Dock) during launch don't
trigger the SwiftUI hierarchy walk while initial layout is mutating.
Add NSLock to breadcrumb limiter for thread safety. Update existing
tests to pass eventWindow for window-attached drag handles.
All four switch statements (case list, commandPaletteTitle,
commandPaletteKeywords, applicationBundlePathCandidates) are now
in consistent alphabetical order.
The app sometimes launched to a frozen blank state with an empty sidebar
and no terminal loaded. This was caused by restoreSessionSnapshot emitting
intermediate @Published states (empty tabs, nil selectedTabId) that left
SwiftUI's mountedWorkspaceIds empty.
Two fixes:
1. Make restoreSessionSnapshot atomic: build the new tab list locally
before assigning to @Published properties in a single batch, so
SwiftUI observers never see an intermediate empty state.
2. Add a startup recovery timer that detects and fixes broken state
(empty tabs, invalid selection, unmounted workspaces) 500ms after
the view appears, with Sentry breadcrumbs for diagnostics.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds a "Send anonymous telemetry" toggle in Settings that lets users
disable Sentry crash reporting and PostHog analytics. The setting is
frozen at launch so toggling mid-session shows a restart hint. The hint
correctly clears if the user toggles back to the launch-time value.
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
Moves socket control password from the macOS login keychain to a
plain file at ~/Library/Application Support/cmux/socket-control-password.
This eliminates the system keychain prompt that interrupts users on
first launch or after keychain changes.
- Directory created with 0700, file written with 0600 permissions
- One-time migration copies existing keychain password to the file,
deletes the keychain entry, and records a migration version in
UserDefaults so it runs only once
- CLI SocketPasswordResolver also reads from the file path
- Security framework import is now conditional (#if canImport)
- Adds SocketControlPasswordStoreTests covering round-trip, env
priority, path resolution, and migration behavior
Fixes https://github.com/manaflow-ai/cmux/issues/541
The equalize splits command was a no-op that always returned false.
Implement it by recursively walking the bonsplit tree and setting
every split divider position to 0.5. Also register the command in
the command palette with a "workspace has splits" precondition so
it only appears when there are multiple panes.
Adds a regression test that creates a nested split layout, skews
divider positions, equalizes, and verifies all dividers are at 0.5.
Fixes https://github.com/manaflow-ai/cmux/issues/571