* Add tab color feature to sidebar workspaces
Lets users assign a custom background color to any sidebar workspace tab
via a right-click "Tab Color" submenu. The primary motivation is working
across multiple projects simultaneously — coloring tabs by project makes
it instant to visually locate the right workspace without reading the title.
- Workspace: adds `customColor: String?` (@Published hex string) and
`setCustomColor()` setter
- TabManager: adds `setTabColor(tabId:color:)` convenience method
- ContentView: 16-color dark palette (all luminance < 0.30, white text
always readable), `Color(hex:)` extension, `coloredCircleImage(hex:)`
helper to render bitmapped NSImage circles (needed because macOS menus
strip SwiftUI foregroundColor from SF Symbols), updated `backgroundColor`
to use custom color at full/70%/35% opacity for active/inactive/
multi-selected states, "Tab Color" submenu in context menu with
"Clear Color" option, and a 1.5pt `Color.primary` border overlay on
the active tab for clear selection indication when custom colors are set
* Add workspace tab color schemes with settings and debug toggles
* Remove Kelly scheme and keep only original tab color palette
* Preserve neutral grayscale when brightening tab colors
* Harden UpdatePill UI test polling timeouts
---------
Co-authored-by: Andreas Fruth <andreas.fruth@gmail.com>
* Remove border below titlebar
Remove the 1px separator line overlay at the bottom of the custom
titlebar and its associated fakeTitlebarSeparatorColor computed property.
* Remove tab hover background in bonsplit
Update bonsplit submodule to remove the background fill on hovered
non-selected tabs.
* Restore titlebar border with system separator color, hover bg on all tabs, browser theme bg
- Add back 1px bottom border on titlebar using NSColor.separatorColor
(matches bonsplit tab separator color)
- Tab hover background now applies to all tabs including the selected one
- Browser address bar and under-page background now use Ghostty theme
background color instead of window background
* Fix file drag-and-drop and file input in browser panel (#194)
Two fixes for the browser panel:
1. File drag-and-drop from Finder: CmuxWebView previously suppressed ALL
drag type registration as a no-op to prevent bonsplit tab drags from
being intercepted. Now it selectively filters out only the text-based
types that conflict with bonsplit (public.text, public.utf8-plain-text,
public.plain-text) and the custom tab transfer types, while allowing
file URL types through so Finder drops work.
2. File <input> elements: Added the WKUIDelegate runOpenPanelWith method
to BrowserUIDelegate so clicking a file input opens the native macOS
file picker (NSOpenPanel), with support for multiple selection and
directory picking as specified by the HTML element.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(claude-opus-4-6): take a look at https://github.com/manaflow-ai/cmux/issues...
* ok
* wok
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Sidebar ports on own line, wider sidebar, CMUX_PORT env vars
- Move listening ports to dedicated sidebar row (removed from branch/directory line)
- Allow sidebar to resize up to 2/3 of screen width (was capped at 360px)
- Add CMUX_PORT, CMUX_PORT_END, CMUX_PORT_RANGE env vars per workspace
- Each workspace gets a dedicated port range (default: base 9100, range 10)
- Add settings UI for port base and range size
- Add portOrdinal to Workspace, monotonic counter in TabManager
Closes#129
* Make port ordinal counter static to avoid overlap across windows
Each window creates its own TabManager, so a per-instance counter
would reset and reuse port ranges. Making it static ensures unique
ranges across all windows.
* Fix portOrdinal race: pass through Workspace init instead of setting after
The first TerminalPanel is created inside Workspace.init, so setting
portOrdinal after init returns meant the initial terminal always got
ordinal 0. Pass portOrdinal as an init parameter and set it before
the TerminalPanel is created.
* Fix P2/P3: snapshot port settings at surface creation, use window screen for sidebar cap
P2: Port base/range are now snapshotted on TerminalSurface when the
panel is created, so changing settings mid-session won't cause
inconsistent CMUX_PORT values across terminals in the same workspace.
P3: Sidebar max width now uses NSApp.keyWindow?.screen instead of
NSScreen.main, so multi-monitor setups get the correct 2/3 cap for
the display the window is actually on.
* Fix P1: snapshot port base/range once per app session, not per panel
Port base and range size are now static properties on TerminalSurface,
initialized once from UserDefaults at first access. This prevents
overlapping port ranges across workspaces when settings are changed
mid-session (e.g., workspace 1 with range=10 at 9110-9119, then
range changed to 5, workspace 2 would overlap at 9110).
The hide-send-unhide pattern in forwardEvent() can recurse infinitely
when gesture recognizer routing re-delivers the event despite isHidden.
Add a re-entrancy guard to break the cycle.
Fixes EXC_BAD_ACCESS (stack overflow) crash in production.