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
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
cmux_daily_active deduplicates by UTC date, so PostHog hourly retention
cohorts show 0s. Add a companion cmux_hourly_active event that fires at
most once per UTC hour, deduped via UserDefaults. No flush() after
hourly events (let them batch). The existing 30-minute timer provides
adequate hour-boundary coverage without changes.
XCUITest launches the app as a separate process that doesn't inherit
XCTest env vars (XCTestConfigurationFilePath, etc.), so
isRunningUnderXCTest() returns false. The app then hits
shouldBlockUntaggedDebugLaunch() and exits with code 64, causing the
test runner to hang waiting for the app to launch.
Fix: detect CMUX_UI_TEST_* env vars set via XCUIApplication.launchEnvironment
and skip the launch guard. Also revert the failed CMUX_TAG ci.yml workaround.