Commit graph

1089 commits

Author SHA1 Message Date
Lawrence Chen
8a3ab6b3f0
Fix command palette focus after terminal find (#2089)
* test: cover command palette focus guard

* fix: block terminal find from stealing palette focus

* test: cover text view focus-stealer fallback

* Add regression for hidden DevTools sync republish loop

* Avoid redundant DevTools visibility publishes

* test: cover browser find focus after workspace round-trip

* fix: restore browser find focus after workspace round-trip

* fix: keep browser find caret on workspace return

* Add workspace round-trip split find regressions

* Keep inactive find overlays from stealing focus

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-25 17:27:54 -07:00
Lawrence Chen
b42f64fbe3
Fix update attempt refreshing pill without actually updating (#2168)
* Fix update attempt refreshing pill without actually updating

The attemptUpdate() subscriber watched for .updateAvailable state to
auto-confirm, but showUpdateFound used setStateAfterMinimumCheckDelay
which delays the transition by up to 2 seconds. During that window,
dismissUpdateInstallation (from a background probe race) could cancel
the pending transition, reverting state to idle without ever confirming.
The subscriber then tore down on the transient idle, silently abandoning
the update.

Fix: move auto-confirm to the Sparkle driver level via an
autoInstallOnNextUpdate flag. When set, showUpdateFound immediately
calls reply(.install) bypassing the delay entirely. The subscriber
is kept as a fallback but no longer tears down on transient idle
while the flag is active.

Closes https://github.com/manaflow-ai/cmux/issues/2166

* Revert "Fix update attempt refreshing pill without actually updating"

This reverts commit 1cd842dd924bf114b096f222851c47d2e36ad4d9.

* Fix update attempt refreshing pill without actually updating

The attemptUpdate() subscriber tore down monitoring whenever it saw
.idle after observing progress. During check startup (retry loop,
background probe race), state can transiently return to .idle before
Sparkle's interactive check begins. The subscriber interpreted this
as "check completed" and stopped monitoring, so the auto-confirm
for .updateAvailable never fired.

Fix: add !state.isIdle to the teardown guard so monitoring only
stops on terminal failures (.notFound, .error), not transient idle.

Closes https://github.com/manaflow-ai/cmux/issues/2166

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-25 16:55:29 -07:00
Austin Wang
cbf08459d6
Fix Cmd+N workspace creation snapshot crashes (#2173)
* Add regression tests for Cmd+N workspace snapshot mutations

* Fix Cmd+N workspace creation snapshot races
2026-03-25 16:52:04 -07:00
Austin Wang
9f2adce830
fix: guard inherited terminal config against stale surfaces (#2101)
* test: add stale inherited surface regression

* fix: guard inherited terminal config against stale surfaces

* fix: address stale surface review feedback
2026-03-25 16:49:54 -07:00
Austin Wang
99ca3c9b9a
Fix sidebar update pill cached popover flow (#2142)
* test: cover cached update pill first-click flow

* fix: use cached sidebar update popover
2026-03-25 04:21:03 -07:00
Austin Wang
049d296267
Fix browser pane restore after reopen (#2141) 2026-03-25 04:11:43 -07:00
Austin Wang
11a841e020
Merge pull request #2133 from manaflow-ai/issue-2131-cmd-n-crash-regression
Fix Cmd+N crash from stale workspace creation snapshots
2026-03-25 02:40:57 -07:00
austinpower1258
17e8bb172d Fix Cmd+N crash from stale workspace creation snapshots 2026-03-25 02:38:20 -07:00
austinpower1258
ad2c65e0ac Add regression test for Cmd+N snapshot close race 2026-03-25 02:38:10 -07:00
Austin Wang
71a64a1234
Fix titlebar double-click zoom handling (#2130) 2026-03-25 02:15:15 -07:00
Austin Wang
0ea16b12c2
Fix window position restore on relaunch (#2129)
* test: cover accessible window frame restore

* fix: preserve accessible window frame on relaunch
2026-03-25 02:05:13 -07:00
Austin Wang
da70f3fa47
Add regression coverage for Cmd+N workspace creation crash (#2127)
* Add Cmd+N workspace snapshot regression coverage (#2017)

* Add dev flag to stress Cmd+N workspace creation
2026-03-25 01:50:57 -07:00
Lawrence Chen
0d8597caf9
New window inherits size from current window (#2124)
* New window inherits size from current window

When creating a new window via Cmd+Shift+N, use the key window's
frame dimensions instead of the hardcoded 460x360 default. The new
window cascades from the existing window's position so it doesn't
stack directly on top.

* Use Ghostty's cascade algorithm for new window positioning

Match upstream Ghostty's window cascade logic: maintain a
lastCascadePoint that tracks where the next window should appear.
First window seeds the point from its own top-left corner, subsequent
windows advance the cascade point via NSWindow.cascadeTopLeft(from:).
On window close, reset the cascade point to the closing window's
position so the next window appears nearby.

New windows still inherit the key window's size so Cmd+Shift+N
creates a window matching the previous one's dimensions.

* Fix frame-to-contentRect conversion and use preferred window resolver

Convert existingFrame to a content rect via
NSWindow.contentRect(forFrameRect:styleMask:) so the new window
matches the source window's actual size instead of growing by
titlebar insets on each Cmd+Shift+N.

Use preferredMainWindowContextForWorkspaceCreation to resolve the
source window, consistent with showOpenFolderPanel and other
callers.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-25 01:26:06 -07:00
Austin Wang
ffb660dee8
Fix first click on detected update pill (#2117) 2026-03-25 00:51:34 -07:00
Lawrence Chen
57237d9faa
Sanitize command before execution, not just display (#2122)
The confirm dialog showed a sanitized command (BiDi/zero-width stripped)
but executed the raw string, creating a display/consent mismatch.
Now the command is sanitized once and the same string is used for both
display and execution.

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-25 00:28:30 -07:00
Achieve
5b82041160
Handle Cmd+O in handleCustomShortcut to prevent Documents folder open (#2034)
* 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>
2026-03-25 00:26:30 -07:00
jorge g
68ff39c444
Fix Ghostty resize_split keybind support (#1899)
* test: add resize_split regression coverage

* fix: implement Ghostty resize_split behavior

* test: cover more resize_split cases

* test: deduplicate split snapshot helper

* Resolve merge conflict: keep both splitNodes and waitForCondition helpers

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-25 00:26:27 -07:00
Austin Wang
3952c2588b
Fix workspace creation crash after restore (#1985)
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-25 00:04:03 -07:00
Lawrence Chen
a7e5050552
Fix SSH control master cleanup on remote teardown (#2104)
* test: add SSH control master cleanup regressions

* fix: close SSH control master on remote teardown

* test: keep SSH workspace after child exit

* fix: keep SSH workspace after child exit

* fix: keep connecting SSH workspaces after child exit

* test: add SSH child-exit demotion regression

* fix: keep SSH workspace after connected shell exit

* fix: address SSH cleanup review feedback

* test: cover SSH cleanup without explicit controlpath

* fix: clean up SSH control masters without explicit controlpath

* test: cover remote detach cleanup edge cases

* fix: preserve SSH sessions during remote detach

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-25 00:01:39 -07:00
Ariel Tobiana
7cbd07e8cb
Add set-color/clear-color workspace actions for tab color via CLI (#1873)
* Add set-color/clear-color workspace actions for tab color via CLI

Expose the existing tab color functionality through the workspace-action
CLI command, enabling programmatic tab color setting without the GUI
context menu.

Supports both named colors (Red, Blue, Amber, etc.) and hex values
(#RRGGBB). Named colors resolve against the built-in palette via
case-insensitive matching.

Usage:
  cmux workspace-action --action set-color --color blue
  cmux workspace-action --action set-color --color "#C0392B"
  cmux workspace-action set-color Amber
  cmux workspace-action clear-color

* Return explicit null color in clear_color JSON response

Restore "color": null in the clear_color response payload so JSON
consumers can distinguish "color was cleared" from "no color field".

---------

Co-authored-by: Ariel Tobiana <arieltobiana@gmail.com>
2026-03-24 23:58:54 -07:00
I LUK KIM
533699f98c
feat: add arrow keys, shift+tab, home/end/delete/pageup/pagedown to sendNamedKey (#1920)
The socket API's send-key command only supported enter, escape, tab,
backspace, and ctrl+letter. Arrow keys and shift+tab had to be sent
as raw escape sequences via send_text, but 0x1B is filtered out by
socketTextChunks and converted to a standalone Escape key event,
breaking multi-byte sequences like \x1b[A (ArrowUp).

This commit extends sendNamedKey to handle:
- Arrow keys: up/down/left/right (with arrow_up/arrowup aliases)
- shift+tab / shift-tab / backtab
- home, end
- delete / del / forward_delete
- pageup / page_up
- pagedown / page_down

These map directly to the existing sendKeyEvent infrastructure using
the appropriate kVK_* keycodes and modifier flags.

Co-authored-by: I Luk Kim <yirugi@gmail.com>
2026-03-24 23:58:51 -07:00
Lawrence Chen
23253e6ddf
Validate workspace color during cmux.json decode (#2112)
Reject invalid color values at parse time with a clear error message
instead of silently ignoring them. Colors are normalized to #RRGGBB
via WorkspaceTabColorSettings.normalizedHex during decode.

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-24 22:58:27 -07:00
Austin Wang
321f8c14c8
fix(browser): keep IME Enter on composition path (#2108)
* test: cover browser IME Enter composition routing

* fix(browser): keep IME Enter on composition path
2026-03-24 22:56:55 -07:00
Austin Wang
983ef2537d
Skip sidebar PR lookup on main/master (#2110) 2026-03-24 22:56:40 -07:00
Pratik Pakhale
b9c656b90c
feat: cmux.json for custom commands (#2011)
* 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>
2026-03-24 22:28:46 -07:00
Achieve
03355ca3fc
Consume Cmd+number shortcuts even when workspace index is out of bounds (#2033)
When pressing Cmd+N for a workspace number that doesn't exist,
the event was not consumed and fell through to Ghostty's goto_tab
binding, which could create a new window. Now the event is always
consumed when the digit matches, preventing unintended window creation.

Fixes #1970

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:26:31 -07:00
Achieve
9a24db93a7
Fix browser portal leaking to other tabs on Bonsplit tab switch (#2000)
* 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.

* Fix browser portal leaking to other tabs on Bonsplit tab switch

When switching between Bonsplit tabs within a workspace, portal-hosted
WKWebViews from deselected browser panels could remain visible above the
newly selected tab. This happened because Bonsplit's keepAllAlive mode
hides non-selected tabs via SwiftUI .opacity(0), but the portal layer
renders at the AppKit window level and is not affected by SwiftUI
opacity changes.

Explicitly hide browser portals for deselected tabs in the pane during
tab selection, ensuring the portal visibility state is always in sync
regardless of SwiftUI re-render timing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: austinpower1258 <austinwang115@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 22:26:27 -07:00
Elvis Tran
b919541044
Fix panel resize stuttering when tiled with browser panels (#1969)
* Fix panel resize stuttering when tiled with browser panels (#1968)

During divider drag, the portal sync system was doing O(N²) work per
frame: each geometry callback synced ALL web views, and multiple
callbacks fired per layout pass (setFrameSize + setFrameOrigin + layout).

Two changes:

1. synchronizeWebViewForAnchor now only syncs the primary web view and
   defers the all-sync. Each panel fires its own geometry callback, so
   secondary syncs are redundant on the hot path.

2. HostContainerView.setFrameOrigin/setFrameSize use markGeometryDirtyIfNeeded
   which defers the callback to layout(), coalescing 2-3 notifications
   per frame into one. An async fallback ensures origin-only changes
   (without a subsequent layout) are still delivered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix premature geometryRevision increment in markGeometryDirtyIfNeeded

Address reviewer feedback (Greptile, CodeRabbit): geometryRevision and
lastReportedGeometryState are now only updated when the callback
actually fires, not eagerly.  This prevents updateNSView from seeing a
premature revision delta and triggering a redundant synchronizeForAnchor
before the coalesced notification arrives.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:24:17 -07:00
Hiroki Kajiwara
a395e8c343
fix: prevent Japanese IME confirmation Enter from executing command (#2075)
* fix: prevent Japanese IME confirmation Enter from executing command

Korean IME commits a syllable and executes on a single Enter, but
Japanese/Chinese IME use Enter only to confirm conversion — a second
Enter is needed to execute. Restrict the extra Return forwarding in
shouldSendCommittedIMEConfirmKey to Korean input sources only.

* refactor: use case-insensitive check for Korean input source ID
2026-03-24 22:24:13 -07:00
Austin Wang
22448197de
Fix Ghostty font-family fallback chain regression (#1308)
* test: add font-family fallback regression coverage

* fix: preserve Ghostty font-family fallback chains

* fix: align CJK fallback scan with Ghostty config semantics

* fix: reuse app support config selection for CJK scan
2026-03-24 22:23:27 -07:00
Matthew Z.
4a8fd3d0fe
Fix dock icon not auto-switching with system dark mode (#1928)
* 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>
2026-03-24 22:19:49 -07:00
Lawrence Chen
65867b86ee
fix: resolve workspace placement before init (#2099)
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-24 21:38:48 -07:00
BillionToken
bc5b6442eb
fix: increase contentSideHitWidth to prevent accidental window resize (#2018)
Co-authored-by: BillionClaw <267901332+BillionClaw@users.noreply.github.com>
2026-03-24 20:54:55 -07:00
Matthew Z.
a0ae085531
Fix workspace creation failing after long uptime (#1930)
When MainWindowContext.window (weak var) becomes nil after extended
uptime, resolvedWindow(for:) falls back to windowForMainWindowId()
which searches NSApp.windows by identifier. However, the recovered
window was only assigned back to context.window without reindexing
the mainWindowContexts dictionary — leaving the ObjectIdentifier key
stale. Subsequent lookups via contextForMainTerminalWindow() would
miss the context, causing addWorkspaceInPreferredMainWindow() to
return nil and Cmd+N to fall back to opening a new window.

Call reindexMainWindowContextIfNeeded() when re-resolving a window
so the dictionary key matches the current NSWindow object.

Fixes #1929

Co-authored-by: CHE-3 <schumannzheng@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:54:48 -07:00
Achieve
bc9f884e69
Export CMUX_SOCKET alongside CMUX_SOCKET_PATH in terminal env (#1991)
* Export CMUX_SOCKET alongside CMUX_SOCKET_PATH in terminal environment

The app only exported CMUX_SOCKET_PATH when setting up the terminal
environment, but some scripts and hooks (e.g. claude-hook) expect
CMUX_SOCKET. The CLI launcher code already exports both (cmux.swift
lines 9288-9289), but the app-side terminal setup was missing the
alias. This caused claude-hook stop to fail with 'TabManager not
available' when CMUX_SOCKET was empty.

Fixes #1905

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Cache socketPath to avoid redundant call

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:54:44 -07:00
Matthew Z.
818864dd4a
Fix sidebar notification persisting after being read (#1933)
* Fix sidebar notification persisting after being read

latestNotification(forTabId:) fell back to latestByTabId when no
unread notifications existed, causing read notifications to persist
in the sidebar even after the user marked them as read, killed all
processes, or switched branches. The sidebar should only display
unread notifications.

Remove the fallback to latestByTabId so the sidebar notification
text clears once all notifications for a workspace are read.

Fixes #1642

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update test expectation for unread-only latestNotification semantics

After markRead, latestNotification(forTabId:) now returns nil since
it no longer falls back to read notifications. Update the test
assertion to match.

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>
2026-03-24 20:54:41 -07:00
Joshua Swanson
f436d46668
fix(browser): use native value setter for React compatibility (#2059)
* fix(browser): use native value setter for React/Vue/Angular compatibility

fill, type, and select commands set input values via direct property
assignment (el.value = x), which does not trigger state updates in
frameworks that override the value setter on element instances.

Use Object.getOwnPropertyDescriptor on the prototype to call the
native setter, which bypasses the framework override and allows the
subsequent input/change events to propagate correctly through
React's synthetic event system.

Affects: browser.fill, browser.type, browser.select

* walk prototype chain instead of instanceof for cross-realm and web component support

---------

Co-authored-by: joshuaswanson <joshuaswanson@users.noreply.github.com>
2026-03-24 20:47:27 -07:00
Austin Wang
56602066a1
Revert Sparkle manual update dialog flow from #1908 (#2090)
* Restore inline sidebar update checks and embed appcast changelog

* Revert Sparkle manual update dialog flow
2026-03-24 20:44:54 -07:00
Lawrence Chen
17bcbcc1cb
Fix all split panes appearing focused after layout restoration (#2088)
* Fix all split panes appearing focused after layout restoration

Ghostty C surfaces default to focused=true (Terminal.zig), but
TerminalSurface.lastFocusState was initialized to false. During
restoration, unfocus() is called before C surfaces exist (views not in
window yet), so the ghostty_surface_set_focus(false) call was silently
dropped. When surfaces were later created, the dedup guard
(false != false) prevented the unfocus from ever reaching the renderer.

Three changes:
- Initialize lastFocusState=true to match Ghostty's default
- In setFocus(), update lastFocusState before the surface-nil guard so
  the desired state is tracked even when the C surface doesn't exist yet
- In createSurface(), sync focus state after creation so surfaces that
  were logically unfocused before the C surface existed get the correct
  state applied

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

* Sync focus state unconditionally in createSurface

Per review feedback: always call ghostty_surface_set_focus(createdSurface,
lastFocusState) instead of only syncing when !lastFocusState. This avoids
coupling to Ghostty's default focused=true and is more robust if the
upstream default ever changes.

* Keep lastFocusState in sync with AppKit responder focus calls

The becomeFirstResponder, resignFirstResponder, and ctrl-key fast paths
call ghostty_surface_set_focus directly without updating lastFocusState.
This could cause the dedup guard in setFocus() to skip a needed call, or
createSurface() to replay a stale state on surface recreation.

Add recordExternalFocusState() and call it alongside each direct C focus
call so lastFocusState stays authoritative.

* Rename lastFocusState to desiredFocusState

The variable now tracks focus intent (may be set before the C surface
exists), not just the last-applied state. Update the name and doc
comment to reflect this.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-24 20:36:35 -07:00
Grimmer Kang
2a2374afcf
feat: expose per-surface TTY in tree output (#2040)
Add tty field to surface items in system.tree JSON response,
reading from existing surfaceTTYNames dictionary. Also show
tty= in the CLI text tree output for terminals that have a
registered TTY.

This enables external tools (e.g. CodeV) to cross-reference
claude process TTYs with cmux surfaces for accurate session
detection when multiple sessions share the same working directory.
2026-03-24 20:27:23 -07:00
Austin Wang
7ffa447708
Fix sidebar badges not refreshing on workspace state change (#2046)
* Add regression test for stale sidebar PR refresh

* Refresh sidebar badges when workspace metadata changes

* Resolve gh for app-side PR probes

* Coalesce sidebar redraws during prompt updates
2026-03-24 19:18:18 -07:00
Lawrence Chen
9b3a6ba28b
Merge pull request #2025 from manaflow-ai/issue-1357-ghost-terminal-sidebar-bleed
Fix #1357: hide stale terminal portal after restore churn
2026-03-24 18:32:31 -07:00
Lawrence Chen
7f1e8835fe
Nudge titlebar folder icon right by 1px 2026-03-23 23:06:10 -07:00
Lawrence Chen
c544d49b79
Shift titlebar folder icon left 2026-03-23 19:54:18 -07:00
austinpower1258
836360db36 fix: hide stale terminal portal after restore churn 2026-03-23 19:19:05 -07:00
Lawrence Chen
1c45915a86
Avoid crash in workspace insert index 2026-03-23 19:10:33 -07:00
austinpower1258
94c656fbbd Force windows visible on headless CI runners for UI test rendering
Two fixes:
1. Use FileManager.temporaryDirectory for diagnostics path instead of
   hardcoded /tmp/ — Process-spawned app inherits the test runner's
   sandbox and can't write to /tmp/.
2. Add orderFrontRegardless() after activate() in the UI test window
   creation path — on headless CI runners, activate() silently fails
   and windows stay invisible, preventing terminal rendering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 03:53:19 -07:00
austinpower1258
fc858fcfa4 Revert UI test foreground activation changes back to 56a4d258
Reverts cbb21872, 54ec524a, 10fd323b, 75375ab7, 82a16aa7 — all
attempts to fix display resolution UI test foreground activation
on CI that introduced regressions. Restores the state from the
last fully green CI run (56a4d258).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 02:38:06 -07:00
Austin Wang
cbb2187260
Fix UI test foreground activation on CI (#1981) 2026-03-23 01:42:03 -07:00
Austin Wang
56a4d25836
Fix blank terminal renders after workspace switches (#1964) 2026-03-22 18:57:30 -07:00