Commit graph

558 commits

Author SHA1 Message Date
Lawrence Chen
ae79d32494
Add inline VS Code open-directory command palette action (#685)
* Add inline VS Code directory command-palette action

* Harden inline VS Code serve-web lifecycle handling

* Add command-palette actions to stop/restart inline VS Code server

* Fix inline VS Code serve-web review comments

* Fix serve-web stop/start race and add regression test
2026-03-01 18:53:08 -08:00
Lawrence Chen
8378bbeaa2
Add dark mode app icon for macOS Sequoia (#702)
* Add dark mode app icon variant for macOS Sequoia

Adds dark appearance entries to the AppIcon asset catalog so macOS 15+
automatically shows a dark-background icon when the system is in dark
mode. The chevron gradient and glow are preserved by recompositing the
foreground over a dark background (#1C1C1E).

Includes a generation script (scripts/generate_dark_icon.py) that
derives the dark PNGs from the light originals.

* Add icon picker in Settings and fix dark icon quality

Use the Figma chevron layer (design/cmux-icon-chevron.png) composited
over a dark background for pixel-perfect results, no white halo or
darkened gradient. Falls back to mathematical recomposition if the Figma
layer is missing.

Add an "App Icon" picker to Settings (under Theme) with three visual
options: Automatic (follows system appearance via asset catalog dark
variants on macOS 15+), Light, and Dark. The selection persists via
UserDefaults and is applied on launch in AppDelegate.ensureApplicationIcon.

* Fix dark icon chevron scale to match light icon

The Figma export was ~25% larger than the repo icon. Scale the Figma
chevron layer by 0.80x before compositing so the chevron size matches
exactly between light and dark variants.

* Use enhanced glow for dark icon

Add a soft blue bloom around the chevron on the dark background using
two Gaussian blur passes (wide at r=25 and tight at r=12) composited
at reduced opacity beneath the sharp chevron. Makes the icon pop more
against the dark squircle.
2026-03-01 03:57:09 -08:00
Lawrence Chen
bc1b6fd9eb
Honor Ghostty background-opacity across all cmux chrome (#667)
* Honor Ghostty background-opacity across all cmux chrome

Parse background-opacity from Ghostty config and propagate it through
the entire chrome pipeline: bonsplit tab bar (via RRGGBBAA hex),
browser panel/omnibar, titlebar, empty panel, and window background.

Decouple glass effect from sidebar blend mode — bgGlassEnabled now
defaults to false so opacity works independently. Add
GhosttyBackgroundTheme helper for consistent color+opacity resolution
across all UI surfaces.

Fixes https://github.com/manaflow-ai/cmux/issues/263

* Titlebar and chrome opacity matches terminal background-opacity

Use CALayer-level opacity for the titlebar background instead of SwiftUI
Color alpha, matching the terminal's Metal compositing path. Account for
the double alpha stacking in the terminal area (Bonsplit container bg +
Ghostty renderer) so the titlebar visually matches.

Also fix opacity-only config changes not triggering titlebar refresh on
Cmd+Shift+, reload.
2026-03-01 03:48:46 -08:00
doug
e01236115e
Fix: use policy constants for minimum window size instead of hardcoded 800×600 (#715)
The root ContentView body had `.frame(minWidth: 800, minHeight: 600)`
hardcoded since the initial commit, preventing users from resizing the
window narrower than 800px even when the sidebar is hidden and a narrow
terminal layout is perfectly usable.

Replace the magic numbers with the existing SessionPersistencePolicy
constants (minimumWindowWidth = 300, minimumWindowHeight = 200), which
were already defined and used for session-restore frame validation.
This gives those constants a second job as the canonical size floor and
makes it easy to tune the minimum in one place.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 02:42:41 -08:00
Austin Wang
aa8fc7232a
Fix Shift+Space IME toggle inserting space (#641) (#670) 2026-02-28 21:12:17 -08:00
Lawrence Chen
f451766d12
Add cmux <path> to open directories and Homebrew binary stanza (#705)
* Add `cmux <path>` to open directories and Homebrew binary stanza

CLI: `cmux .` or `cmux /path/to/dir` opens a new workspace at the
given directory. If the app isn't running, it launches first and waits
for the socket. Also adds `--cwd` flag to `new-workspace`.

Server: `workspace.create` now accepts an optional `cwd` parameter,
passed through to `TabManager.addWorkspace(workingDirectory:)`.

Homebrew: adds `binary` stanza to the cask so `cmux` CLI is globally
available after `brew install --cask cmux`. Updated both the cask file,
the CI workflow template, and the manual release script so automated
version bumps preserve the stanza.

* Address review: validate cwd type, fix socket detection, propagate errors

- looksLikePath now also matches paths containing `/` (e.g. `foo/bar`)
- openPath uses socket connection attempt instead of fileExists to detect
  whether the app is running (Unix sockets may not appear on filesystem)
- launchApp/activateApp now throw instead of swallowing errors with try?
- Server validates that cwd param is a string, returns invalid_params error
  if wrong type is passed
2026-02-28 20:25:41 -08:00
Lawrence Chen
838d1b07b1
Fix local HTML file routing in open wrapper (#684)
* Route local HTML open targets to cmux browser

* Keep file:// omnibar navigation inside cmux browser

* Load local file URLs via WKWebView file API

* Add browser regression test for local file URL loads

* Address PR feedback on local HTML and file URL handling
2026-02-28 19:08:39 -08:00
Lawrence Chen
7143359c04
Stabilize UI keyboard/focus regressions and flaky omnibar/sidebar tests (#689) 2026-02-28 07:09:37 -08:00
Lawrence Chen
7916b2d418
Fix Xcode Cloud UI tests by running TestAction in Debug (#672)
* 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
2026-02-28 01:48:49 -08:00
Lawrence Chen
168e6b9b25
Auto-heal missing CLI listener socket (#679)
* Auto-heal missing CLI socket listener

* Add Sentry socket listener breadcrumbs and failure capture
2026-02-28 01:19:38 -08:00
Lawrence Chen
c3b55e2a9f
Fix Cmd+plus zoom handling on non-US layouts (#680) 2026-02-28 00:16:03 -08:00
Lawrence Chen
f73887154d
Precompute panel ordering to reduce sidebar scroll lag (#661)
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
2026-02-27 18:44:07 -08:00
Lawrence Chen
1392bd16d7 Revert "Use workspace color for notification ring and selection bar (#664)"
This reverts commit 4bfe95d125.
2026-02-27 18:24:51 -08:00
Lawrence Chen
4bfe95d125
Use workspace color for notification ring and selection bar (#664)
- 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
2026-02-27 18:14:19 -08:00
Austin Wang
c5f749640a
Fix terminal wrap width for overlay scrollbar (#522) 2026-02-27 17:15:32 -08:00
Austin Wang
5c065bcf05
Merge pull request #646 from manaflow-ai/cmux/cmd-w-fails
Fix browser split behavior and prevent tagged app auto-close
2026-02-27 17:03:51 -08:00
Lawrence Chen
1fa0f2bcb6
Add Open Folder command (Cmd+O) (#656)
* 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>
2026-02-27 16:28:18 -08:00
Austin Wang
f72ce07ad5
Merge pull request #585 from manaflow-ai/fix/issue-552-trackpad-scroll-not-working
Fix trackpad scrolling in terminal panes
2026-02-27 11:44:51 -08:00
austinpower1258
469f95d398 Fix split-button browser flow to seed terminal split 2026-02-27 11:42:18 -08:00
Cheul
8968f787ca
Fix Codex non-empty composer space tap starting transcription in cmux (#540)
* Fix space hold-to-talk by normalizing keyUp event metadata

* Add regression test for synthetic Space key release metadata
2026-02-27 03:42:09 -08:00
Lawrence Chen
23d140a2a6
Add 'Flash Focused Panel' to command palette (#638)
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
2026-02-27 02:43:46 -08:00
Lawrence Chen
5a763a8b5e
Rename 'tab color' to 'workspace color' in user-facing strings (#637)
Closes https://github.com/manaflow-ai/cmux/issues/635
2026-02-27 02:43:08 -08:00
Lawrence Chen
49e93e4b4c
Add command palette entries to install/uninstall cmux CLI in PATH (#626)
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
2026-02-27 01:53:13 -08:00
Lawrence Chen
978341b228
Add zoom/maximize focused pane in splits (#634)
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
2026-02-27 01:50:56 -08:00
Lawrence Chen
dca8992901
Fix use-after-free in ghostty_surface_refresh after sleep/wake (#432) (#619)
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.
2026-02-27 01:44:02 -08:00
Lawrence Chen
9ae737026d
Fix browser eval: await promises, always-on console hooks, undefined detection (#613)
- 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
2026-02-27 01:42:27 -08:00
Lawrence Chen
2202044af4
Fix drag-handle crash on launch from stale foreign-window events (#490) (#620)
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.
2026-02-27 01:42:17 -08:00
Lawrence Chen
c70ac25eef
Sort TerminalDirectoryOpenTarget enum cases alphabetically (#628)
All four switch statements (case list, commandPaletteTitle,
commandPaletteKeywords, applicationBundlePathCandidates) are now
in consistent alphabetical order.
2026-02-27 01:18:52 -08:00
Lawrence Chen
e14c5a383f
Add Tower to command palette Open Directory targets (#627) 2026-02-27 00:42:42 -08:00
Lawrence Chen
24bc23630a
Disable Sentry sendDefaultPii to match anonymous telemetry label (#623)
sendDefaultPii=true auto-collects usernames, emails, and IPs, which
contradicts the "Send anonymous telemetry" setting label. Set to false.
2026-02-26 23:53:11 -08:00
Lawrence Chen
e20d692094
Remove duplicate telemetry assignment in resetAllSettings (#611) 2026-02-26 22:14:17 -08:00
Austin Wang
a326514bf6
Fix frozen blank launch state caused by session restore race condition (#399) (#565)
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>
2026-02-26 22:10:21 -08:00
Lawrence Chen
fa6a18c753
Add telemetry opt-out setting (#610)
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.
2026-02-26 22:02:29 -08:00
Lawrence Chen
6f459918c5
Add throttled breadcrumbs for drag-handle hit-test anomalies (#527) 2026-02-26 20:37:50 -08:00
Lawrence Chen
e74012a728
Add cmux tree command for full hierarchy view (#592)
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
2026-02-26 20:04:09 -08:00
ALPER
4cb278c854
Fix interaction crash in titlebar drag hit-testing (#600) 2026-02-26 20:02:53 -08:00
Travis Carr
570ed27b5d
Add Kagi as a search provider option (#561)
Co-authored-by: Travis Carr <tcarr@nvidia.com>
2026-02-26 16:23:10 -08:00
Austin Wang
c51171294e
Merge pull request #590 from manaflow-ai/fix/issue-582-sidebar-branch-refresh
fix: keep sidebar git branch updates responsive after sleep/wake
2026-02-26 15:27:21 -08:00
austinpower1258
6b85265255 fix: avoid blocking git branch socket updates on main thread 2026-02-26 15:21:27 -08:00
Lawrence Chen
847ce008ed
Restore lazy keychain reads for socket password (#589)
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
2026-02-26 15:16:27 -08:00
Austin Wang
df119c75d5
Merge pull request #588 from manaflow-ai/fix-issue-572
Fix selected workspace status color contrast
2026-02-26 15:14:49 -08:00
austinpower1258
cdad265f1d Fix selected-workspace status contrast 2026-02-26 15:12:10 -08:00
Austin Wang
0c5ffd7f5a
Merge pull request #567 from manaflow-ai/fix/issue-490-launch-crash-drag-handle
Fix crash on launch: exclusive access violation in drag handle hit test
2026-02-26 15:06:37 -08:00
austinpower1258
eeb6122e3c Fix terminal pane trackpad scroll routing 2026-02-26 14:43:13 -08:00
Austin Wang
c537c845f7
Merge pull request #566 from manaflow-ai/fix/issue-432-surface-refresh-crash-after-wake
Fix use-after-free crash in ghostty_surface_refresh after wake
2026-02-26 14:35:44 -08:00
Lawrence Chen
163f8572e4
Replace keychain password storage with file-based storage (#576)
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
2026-02-26 14:29:12 -08:00
Lawrence Chen
780f959a48
Fix equalize splits to recursively set all dividers to 0.5 (#575)
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
2026-02-26 14:27:18 -08:00
Lawrence Chen
b1846aaec4
Fix notification bell hover crash by conditionally tracking hover (#574)
Only enable .onHover tracking on TitlebarControlButton when the style
uses hoverBackground (e.g. pillGroup). Styles without a visible hover
background no longer install the tracking area, preventing the crash
on notification-bell hover.

Also switches the notifications anchor from .overlay to .background so
AppKit hit-testing no longer conflicts with the popover anchor view.

Includes regression test for the hover-tracking policy.

Fixes https://github.com/manaflow-ai/cmux/issues/537
2026-02-26 14:26:28 -08:00
austinpower1258
1217ba3295 Fix crash on launch: exclusive access violation in drag handle hit test (#490)
During app launch, mouseMoved events can trigger hitTest on the drag
handle while SwiftUI is still modifying view state in a layout pass.
The previous blacklist approach (only deferring mouseMoved, cursorUpdate,
nil) let unexpected event types slip through — e.g. activation events
where NSApp.currentEvent is not the mouseMoved being routed — causing
contentView.hitTest() to re-enter SwiftUI views and trigger an exclusive
access violation.

Switch to a whitelist: only leftMouseDown (the sole event the drag
handle actually handles) proceeds with the full view-hierarchy walk.
All other event types bail out immediately. The deferred-event check
runs after suppression recovery (which uses only ObjC associated-object
calls, safe from Swift exclusivity) so stale suppression is still
cleared on passive events, but before the view-hierarchy walk that
triggered the crash.

Fixes #490

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:04:46 -08:00
austinpower1258
501e893fba Fix use-after-free in ghostty_surface_refresh after wake (#432)
Prevent crash (KERN_INVALID_ADDRESS at ghostty_surface_refresh) during
geometry reconcile after wake-from-sleep by adding proper lifetime
guards for freed surfaces:

- Re-read self.surface before each ghostty C call in forceRefresh()
  instead of using a stale captured local that can outlive the surface
- Nil out self.surface in deinit before scheduling the async free Task,
  so in-flight closures see nil and bail out
- Re-check surface validity in reconcileTerminalGeometryPass() after
  reconcileGeometryNow() which can trigger AppKit layout that frees
  surfaces

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:28:24 -08:00