* 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>
Add Startpage (startpage.com) to the BrowserSearchEngine enum alongside
Google, DuckDuckGo, Bing, and Kagi. Startpage provides an OpenSearch-
compatible suggestions endpoint at /osuggestions, so autosuggestions
work out of the box using the existing OSJSON parser.
Co-authored-by: Zlatko Cajic <git@zlat.co>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
keyCodeForShortcutKey() did not map arrow glyphs (←→↑↓) to their
macOS key codes (123-126). The shortcut recorder correctly stored
arrow keys as glyphs via storedKey(), but matchShortcut() could
not resolve them back to key codes for ANSI fallback matching.
This only affected non-directional shortcut actions (e.g. Next/Previous
Surface) since pane focus shortcuts use a separate matchDirectionalShortcut()
path that already handles arrow keys.
- 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>
* Fix stale Claude status in sidebar by adding missing hooks and OSC suppression
The Claude Code integration only used 3 hooks (SessionStart, Stop, Notification),
leaving gaps that caused stale sidebar status. Now uses 6 hooks:
- SessionEnd: clears status when Claude exits (covers Ctrl+C where Stop doesn't fire)
- UserPromptSubmit: clears "Needs input" and sets "Running" on new prompt
- PreToolUse (async): clears "Needs input" when Claude resumes after permission grant
Also:
- Suppress OSC 9/99 desktop notifications for workspaces with active Claude hook
sessions to prevent duplicates from the raw OSC path
- Store Claude process PID in status entries for stale-session detection
- Add 30-second sweep timer that checks agent PIDs and clears stale entries
(safety net for SIGKILL/crash where no hook fires)
- Update wrapper test expectations for the new hook set
Fixes https://github.com/manaflow-ai/cmux/issues/1301
* Don't show "Running" status on Claude launch, only when actually working
SessionStart now registers the PID for tracking and OSC suppression via
set_agent_pid without setting a visible status entry. "Running" only
appears when the user submits a prompt (UserPromptSubmit) or Claude
starts using tools (PreToolUse).
Added set_agent_pid / clear_agent_pid socket commands to decouple PID
tracking from visible status entries. OSC suppression checks agentPIDs
instead of statusEntries so it works during the initial idle period.
* Don't restore status entries across app restarts
Status entries are ephemeral runtime state tied to running processes
(e.g. claude_code "Running"). Restoring them after restart shows stale
status for processes that no longer exist.
* Address PR review comments and remove debug logging
- session-end: only clear status/PID/notifications when Stop didn't fire first
- PID sweep: check errno == ESRCH instead of treating all kill(pid,0) failures as dead
- Validate CMUX_CLAUDE_PID > 0
- Propagate tracked PID in pre-tool-use setClaudeStatus
- OSC suppression: use tabManagerFor(tabId:) for multi-window support
- clearAgentPID: resolve tab UUID before async dispatch
- restoreSessionSnapshot: also clear agentPIDs alongside statusEntries
- Fix AskUserQuestion surfaceId overwrite (wrong workspace notification)
- Fix notification text matching for "Claude Code needs your attention"
- AskUserQuestion: render option labels as bracketed inline text
- Remove artificial text truncation limits
- Remove temporary JSONL debug logging from all handlers
* Use resolveTabIdForSidebarMutation in clearAgentPID
The SwiftUI TextField lost arrow-key and backspace handlers when the
query prefix (">") was deleted, because the scope transition tore down
the .onKeyPress modifiers. Using an NSViewRepresentable with an AppKit
field editor keeps navigation commands (up/down/enter/escape) on the
native delegate, making them immune to SwiftUI scope changes.
Fixes#1409
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fallback stable socket listener to user socket path
* Move stable socket path out of /tmp
* Keep socket health checks active on fallback paths
---------
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.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>
Snapshot TabManager's published state (tabs, selectedTabId) at the start
of workspace creation so mutations don't bounce through Combine-backed
accessors mid-creation. Prevents crashes when adding a workspace via
Cmd+N, the new-workspace button, or any other creation path that
triggers re-entrant publishes.
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>