* Add "Match Terminal Background" sidebar setting
Adds a toggle in Settings > Sidebar Appearance that makes the sidebar
use the same background color and transparency as the terminal area.
Uses layer-level opacity on a fully opaque background color (the same
technique as TitlebarLayerBackground) with effective opacity formula
`1 - (1-alpha)^2` to account for the terminal's two stacked
semi-transparent layers (Bonsplit chrome + Ghostty Metal surface).
Also adds a 1px trailing border derived from the terminal chrome color,
matching the bonsplit tab bar separator logic.
* Fix sidebar border color not updating on theme change
Add @State + .onReceive(.ghosttyDefaultBackgroundDidChange) to
SidebarTrailingBorder so the separator color recomputes when the
Ghostty theme changes, matching the pattern used in SidebarBackdrop.
* Address review comments: localize debug toggle, fix separator refresh
- Localize the debug panel toggle label (Codex P1)
- Add .onAppear to SidebarTrailingBorder for initial color (Cubic P2)
- Fix stale doc comment on SidebarTerminalBackgroundView (Cubic P3)
---------
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
* Add customizable sidebar selection highlight color
Expose a `sidebarSelectionColorHex` user default that overrides the
hardcoded blue (#0091FF) selection highlight in the sidebar. Add a
"Selection Highlight" color picker in Settings > Workspace Colors,
following the same pattern as existing tint color pickers. Falls back
to the default accent color when no custom color is set.
Closes#1753
* Fix review feedback: reactivity, reset button, localization
- Add @AppStorage subscription in TabItemView so sidebar selection
color updates reactively when changed in Settings
- Add Reset button in Settings > Workspace Colors > Selection Highlight
- Localize debug panel strings for Selection Color picker
- Clear sidebarSelectionColorHex in resetAllSettings()
* Add customizable notification badge color in sidebar
Add `sidebarNotificationBadgeColorHex` user default to override the
unread notification badge color on workspace tabs. Add a "Notification
Badge" color picker in Settings > Workspace Colors, following the same
pattern as the selection highlight picker. Falls back to the default
accent color when no custom color is set.
Port links were reusing the PR-link preference
(openSidebarPullRequestLinksInCmuxBrowser), causing inconsistent
behavior when users toggled that setting. Adds a dedicated
openSidebarPortLinksInCmuxBrowser setting with its own toggle in
Settings so port and PR link behavior can be controlled independently.
Addresses review feedback from https://github.com/manaflow-ai/cmux/pull/1844
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
* Handle Cmd+O in handleCustomShortcut to prevent Documents folder open
Cmd+O for "Open Folder" was only handled in SwiftUI menu, which can
fail due to focus bugs when terminal is focused. This caused AppKit's
default NSDocumentController to open the Documents folder instead.
Now Cmd+O is intercepted in handleCustomShortcut like other shortcuts.
Fixes#2010
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix fallback directory loss and deduplicate Open Folder logic
Address review feedback:
1. Pass selected directory URL to fallback window creation so the
user's folder choice is not silently discarded
2. Replace inline NSOpenPanel code in cmuxApp.swift menu action
with a call to AppDelegate.showOpenFolderPanel() to avoid
future divergence between the two code paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Set NSOpenPanel directoryURL to current terminal working directory
Address review feedback: set panel.directoryURL to the focused
terminal's working directory so Open Folder starts in a contextually
relevant location instead of AppKit's default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Use shared main-window resolver and openWorkspaceForExternalDirectory in showOpenFolderPanel
Address review feedback: use preferredMainWindowContextForWorkspaceCreation
for directory seeding (works when auxiliary windows are key) and
openWorkspaceForExternalDirectory for workspace creation (ensures
shouldBringToFront and consistent fallback behavior).
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
* Pre-launch app for browser UI test on headless CI runners
XCUIApplication.launch() blocks ~60s then fails on headless WarpBuild
runners because foreground activation requires a GUI login session.
Apply the same pre-launch strategy used for the display resolution test:
- CI shell launches the app with env vars before running xcodebuild
- Test detects pre-launched app via manifest, uses activate() instead of
launch() to avoid killing and relaunching the app
- Falls back to clicking the window for focus via accessibility framework
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Revert "Pre-launch app for browser UI test on headless CI runners"
This reverts commit a540e2fd99aaa1395b91a8d50caa797cdd7551b8.
* feat: cmux.json for custom commands
* tests: add cmux json tests
* fix: pr review feedback: validation, translations, input handling, and palette improvements
- Fix Danish ("Overfladedef inition") and Norwegian ("rotmapp") translation typos
- Add empty-string check for baseCwd fallback in command palette handlers
- Coalesce \r\n into single Return keypress in sendInput
- Redact command text from timeout log to prevent secret leakage
- Add decode-time validation: reject hybrid/empty commands, ambiguous layout
nodes, wrong split children count, and empty pane surfaces
- Namespace custom command IDs with "cmux.config.command." prefix
- Forward command description to palette subtitle when available
- Update tests for new validation rules and ID prefix
* fix: address PR review feedback — per-window config isolation, blank validation, ancestor walk,
palette sanitization
* fix: fallback to current dir cmux.json watching if no any cmux.json found in full acesor walk
* ci: trigger CI for fork PR
* Add directory trust for cmux.json command confirmation
The confirm dialog now shows the actual command text and has an "Always
trust commands from this folder" checkbox. When checked, future confirm
commands from that directory skip the dialog.
Trust is scoped to the git repo root if the cmux.json is inside a repo,
so trusting once covers all subdirectories. Non-git directories are
trusted by exact path. Global config is always trusted.
Trusted directories are persisted in ~/Library/Application Support/cmux/
trusted-directories.json.
* Add trusted directories section to Settings
Shows all trusted directories with per-directory revoke buttons and a
Clear All option. Placed in a "Custom Commands" section between
Automation and Browser in Settings.
* Replace trusted directories list with editable textarea
One path per line, with a Save button that activates on changes.
Users can add, remove, or edit paths directly.
* Auto-save trusted directories on edit, remove Save button
Matches the behavior of other textarea settings (browser host
whitelist, external URL patterns) which auto-save via @AppStorage.
* Sanitize command text in confirm dialog against BiDi attacks
Strip zero-width and BiDi override characters from the command preview
so the dialog shows exactly what will be executed.
---------
Co-authored-by: austinpower1258 <austinwang115@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
* Fix dock icon not auto-switching with system dark mode
The automatic icon mode relied on the asset catalog to handle
appearance-based icon selection, but the compiled Assets.car does not
include dark variant renditions for AppIcon. This meant setting
applicationIconImage to nil had no effect — the icon stayed on the
light variant regardless of system appearance.
Replace the nil-reset approach with an active KVO observer on
NSApp.effectiveAppearance that programmatically swaps between
AppIconDark and AppIconLight images when in automatic mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review feedback: fix async race and harden singleton
- Add guard in async callback to skip stale updates after stopObserving()
- Add private init() to prevent external instantiation of singleton
- Remove unused .new KVO option
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: CHE-3 <schumannzheng@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Allow customizing numbered workspace and surface shortcuts
* Update bonsplit submodule to squashed main commit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Swift app: feedback API endpoint, docs URLs, changelog URL, CLI help
- PostHog proxy: r.cmux.dev -> r.cmux.com
- All 20 README files: docs and blog links
- Homebrew cask: homepage URL in update-homebrew workflow
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
* feat: support window.open() popup windows (#742)
Return a live WKWebView from createWebViewWith using WebKit's supplied
configuration, preserving popup browsing-context semantics (window.opener,
postMessage). This fixes OAuth/OIDC flows and any site relying on standard
popup patterns.
- Add BrowserPopupWindowController: NSPanel-based popup with self-retention,
KVO title/URL, read-only URL label, nested popup depth limit (3),
insecure-HTTP prompt parity, auth challenge parity, download delegate
- Classifier: scripted requests (window.open) create popups; user-initiated
actions (Cmd+click, middle-click, context menu) open tabs
- Retarget context menu "Open Link in New Tab" to bypass createWebViewWith,
wired in both main browser and popup web views
- Cmd+W fast path in AppDelegate for popup windows
- Opener panel owns popup lifecycle; close() tears down all child popups
* fix: Cmd+W closes only the popup, not the parent tab
Add BrowserPopupPanel (NSPanel subclass) that intercepts Cmd+W in
performKeyEquivalent before the swizzled cmux_performKeyEquivalent
can dispatch it to the main menu's "Close Tab" action.
Also refine the popup classifier to reuse browserNavigationShouldOpenInNewTab
for Cmd+click/middle-click detection, add download delegate wiring, and
wire onContextMenuOpenLinkInNewTab for popup web views.
* fix: tighten popup routing and window behavior
* test: cover oversized popup frame clamping
* test: cover plain link-activated popup routing
---------
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
- Config: sidebar-background supports plain hex (#336699) or
light/dark syntax (light:#fbf3db,dark:#103c48)
- Config: sidebar-tint-opacity overrides tint opacity
- Settings UI: per-scheme color pickers, opacity slider (0-70%), reset
- SidebarBackdrop resolves light/dark hex based on @Environment colorScheme
- applySidebarAppearanceToUserDefaults guards on rawSidebarBackground presence
so UI picks survive appearance toggles when no config is set
- Stale light/dark UserDefaults keys cleared when config switches from
dual-mode to single or sidebar-background is removed
- applyPreset() and Reset Tint clear per-scheme overrides
- Debug snapshot (combinedPayload + copySidebarConfig) includes new keys
- ColorPicker labels use String(localized:) per localization policy
- Opacity slider capped at 0.7 to match debug view vibrancy constraint
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, Cmd+W on the last surface kept the workspace alive with a
replacement shell, unless the user toggled a hidden setting. This was
confusing—users expect Cmd+W to close the window when there's nothing
left.
Now Cmd+W (and the tab-strip X button) always close the workspace when
they close its last surface, and close the window when that was the last
workspace. Internal/programmatic closes (e.g. process exit, panel moves)
still spawn a replacement shell so the workspace stays alive.
Key changes:
- Track explicit user close gestures via markExplicitClose / onTabCloseRequest
- Remove the LastSurfaceCloseShortcutSettings toggle (now always-on)
- Use window.performClose for last-workspace window close
- Update tests to match the new behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add accessibilityAddTraits(.isSelected) to Theme and App Icon picker
buttons so VoiceOver announces the active option. Reorder the top of
the App section to: Language, Theme, App Icon.
Addresses review feedback from https://github.com/manaflow-ai/cmux/pull/1367
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add subtitle to App Icon setting to reduce confusion with theme
Users were confusing the App Icon picker (Automatic/Light/Dark) with
the Theme toggle. Add "Dock and app switcher" subtitle to clarify
this setting only affects the icon appearance, not the app theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Replace Theme dropdown with visual appearance picker
Draw window thumbnails showing light/dark previews with traffic light
dots and content bars, matching the macOS System Settings appearance
picker pattern. System mode shows overlapping light+dark thumbnails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Swap theme picker to Gemini's wallpaper + layered window design
Replace flat single-window thumbnails with richer previews: wallpaper
gradient backgrounds, menu bar with Apple logo, two layered windows
with shadows, and a split-mask for the System option (light on left,
dark on right with center divider), matching the macOS System Settings
appearance picker more closely.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Move Theme and App Icon pickers to right-aligned row layout
Both pickers now use an HStack with the label on the left and
thumbnails on the right, matching the SettingsCardRow pattern.
Thumbnails get layoutPriority(1) so the label text compresses
first on narrow windows. Slightly smaller thumbnails (76x50 for
theme, 48px icons) to fit comfortably at minimum settings width.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Top-align labels in Theme and App Icon picker rows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Increase hitbox on picker buttons and remove focus ring
Add contentShape(Rectangle()) for full-area tap targets, increase
padding (8v/10h), and add focusable(false) to prevent the macOS
keyboard focus outline from showing on the buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Use rounder squircle corners on theme thumbnails
Bump cornerRadius from 10 to 14 on the thumbnail clip shape and
border for a more pronounced squircle look.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Use true superellipse squircle shape for theme thumbnails
Add a Squircle shape that draws a superellipse (n=4) path blended
with an ellipse based on corner radius. Apply it to the theme
thumbnail clip and border instead of RoundedRectangle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove custom Squircle struct, use built-in continuous rounded rect
RoundedRectangle(style: .continuous) is Apple's squircle. The custom
superellipse shape was unnecessary.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add last-surface close regression tests
* Keep workspaces open when closing last surface
* Add Cmd+W last-surface close setting
* Share Cmd+W surface-close path
* Add multi-workspace close UI regression test
* Summarize multi-workspace close confirmation
* Add Cmd+Shift+W multi-close UI regression test
* Honor sidebar multi-select for close workspace
---------
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>