Commit graph

1965 commits

Author SHA1 Message Date
Lawrence Chen
960006e6d6
reload.sh: default to build-only, add --launch flag (#2097)
* reload.sh: default to build-only, add --launch flag to open app

By default, reload.sh now builds and prints the app path without
launching. Pass --launch to get the previous behavior (kill existing
instance and open). This lets agents build without stealing focus,
and the user can cmd-click the printed path to launch when ready.

* CLAUDE.md: use reload.sh output for app path instead of hardcoded home dir

The templates hardcoded /Users/lawrencechen/ which broke cmd-click
on machines with a different home directory. Agents now read the
actual path from reload.sh's "App path:" output.

* CLAUDE.md: add concrete example for app path URL format

Uses a fictional /Users/jane/ to make it clear the path comes from
reload.sh output, not a hardcoded value.

* CLAUDE.md: clearer step-by-step instructions for app path URL

Explicit 3-step recipe (grab path, prepend file://, format as link)
with example showing the reload.sh output and the expected result.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-24 21:45:48 -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
Lawrence Chen
3a44889906
Remove fork PR guards from CI workflows (#2092)
* Remove fork PR guards from CI workflows

Fork PRs are already gated by GitHub's "Require approval for outside
collaborators" setting. The workflow-level guards were redundant and
prevented WarpBuild jobs from running even after maintainer approval.

* Address review feedback: extend guard test, skip upload on fork PRs

- Guard test now covers build-ghosttykit.yml and ci-macos-compat.yml
  (not just ci.yml)
- Skip xcframework upload when GHOSTTY_RELEASE_TOKEN is unavailable
  (fork PRs), so the build still validates without failing at publish

* Check GHOSTTY_RELEASE_TOKEN at runtime instead of step if

secrets context can't be reliably used in step if: conditions.
Check the env var inside the script instead.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-24 21:08:06 -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
BillionToken
6d9c93732c
docs: remove outdated Claude Code hooks section from notifications (#2053)
The Claude Code hooks section referenced pre-0.60 configuration using
matchers (idle_prompt, permission_prompt) that are no longer valid in
current Claude Code versions. Replace with a link to the official
Claude Code documentation.

Fixes #2009

Co-authored-by: BillionClaw <267901332+BillionClaw@users.noreply.github.com>
2026-03-24 20:54:51 -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
Achieve
b24a53dc06
Add -r shorthand to SKIP_SESSION_ID check in claude wrapper (#1992)
* Add -r shorthand to SKIP_SESSION_ID check in claude wrapper

The wrapper checked for --resume but not its -r shorthand, causing
claude -r to fail with a --session-id conflict error because the
wrapper injected its own --session-id alongside the implicit --resume.

Fixes #1987

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

* Remove invalid -r=* pattern from SKIP_SESSION_ID check

Short options don't use the = form, so -r=* would never match a real
CLI invocation. Keep only -r as the shorthand for --resume.

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:26:50 -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
8c0aee3155
test: clarify stale portal rebind sync points 2026-03-24 00:04:30 -07:00
Lawrence Chen
441118b1bb
Merge pull request #2030 from manaflow-ai/task-titlebar-folder-icon-left
Shift titlebar folder icon 7px left
2026-03-23 23:46:59 -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
Lawrence Chen
22c50a4416
Merge pull request #2023 from manaflow-ai/task-fix-add-workspace-insert-index-crash
Avoid crash when creating a new workspace
2026-03-23 19:27:02 -07:00
austinpower1258
836360db36 fix: hide stale terminal portal after restore churn 2026-03-23 19:19:05 -07:00
austinpower1258
e41f39bd75 test: cover stale terminal portal after restore-like rebind 2026-03-23 19:18:53 -07:00
Lawrence Chen
4f5a3174e6
Clarify workspace insertion regression test 2026-03-23 19:16:39 -07:00
Lawrence Chen
1c45915a86
Avoid crash in workspace insert index 2026-03-23 19:10:33 -07:00
Lawrence Chen
202a699747
Add regression test for workspace insertion 2026-03-23 19:10:33 -07:00
Lawrence Chen
142c62c756
Add dual licensing (AGPL + commercial) (#2021)
* Add dual licensing (AGPL + commercial)

Add commercial license option for organizations that cannot comply with
AGPL. Contact founders@manaflow.com for details. Updates LICENSE preamble,
all README translations, and CONTRIBUTING.md.

* Fix AGPL identifier and strengthen contributor license grant

- Use AGPL-3.0-or-later (not AGPL-3.0) in all READMEs to match LICENSE
- Replace weak "retains the right" clause in CONTRIBUTING.md with explicit
  contributor license grant for commercial sublicensing

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
2026-03-23 18:53:39 -07:00
austinpower1258
b5fb304af0 Handle headless CI runners in browser find focus UI test
On WarpBuild runners without a GUI session, XCUIApplication.launch()
blocks ~60s then fails with "Failed to activate application (current
state: Running Background)". Wrap launch() in XCTExpectFailure so the
test can continue — keyboard and element APIs work via accessibility
even when the app is in .runningBackground.

Increase test execution time allowance from 120s to 180s to account
for the 60s activation timeout on headless runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 04:46:18 -07:00
austinpower1258
381aab0d83 Add persistent virtual display for all UI regression tests
The browser find focus test was failing because XCUIApplication.launch()
cannot foreground-activate the app on headless CI runners (WarpBuild)
without a display. The display resolution test already had its own virtual
display, but it was scoped to that step only.

Create a persistent virtual display at the start of the ui-regressions job
that stays alive for all test steps. Also switch the browser test from
`test` to `test-without-building` since the build step already ran.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 04:35:43 -07:00
austinpower1258
81aaa8e2d0 Fix UI test harness validation: make startPath optional
The CI display helper now uses --start-delay-ms instead of --start-path
because the XCTest sandbox prevents writing to /tmp/. The harness manifest
no longer includes startPath, but the test guard still required it, causing
"Incomplete external display harness configuration" errors.

Make startPath optional in both the manifest and environment variable
harness loading paths, and gate the start signal write on displayStartPath
being non-empty.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 04:26:30 -07:00
austinpower1258
82a9ccf218 Fix sandbox file write issue: use start-delay-ms for display helper
The sandboxed XCTest runner can't write the start signal file to /tmp/.
Added --start-delay-ms to create-virtual-display.m as alternative to
--start-path. CI uses 10s delay so the test captures baseline render
stats before churn begins. Test skips start signal write when
pre-launched.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 04:16:57 -07:00
austinpower1258
0c4415ceba Pre-launch app from CI shell to escape XCTest sandbox
The XCTest runner is sandboxed, causing Process-spawned apps to
inherit sandbox restrictions. The CI step now:
1. Builds for testing first (separate step)
2. Launches display helper and app from the shell (non-sandboxed)
3. Waits for app diagnostics and render stats
4. Writes manifests for the test to find the pre-launched state
5. Runs test-without-building

The test detects the pre-launch manifest and skips its own app launch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 04:05:46 -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
6233f1b2f0 Use Process with sandbox-aware temp paths for UI test app launch
The Process-spawned app inherits the test runner's sandbox. Previous
attempts failed because diagnostics used hardcoded /tmp/ which the
sandboxed app can't write to. Now using FileManager.temporaryDirectory
for all temp paths (resolves to the sandbox container's tmp), and
inheriting the full test runner environment so the child shares the
same sandbox context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 03:43:26 -07:00
austinpower1258
79aae4fe83 Use NSWorkspace with activates=false to launch app in UI test
Root cause: Process inherits the XCTest runner's sandbox, preventing
the app from writing diagnostics to /tmp/. NSWorkspace.openApplication
goes through LaunchServices, which launches the app in its own process
context outside the sandbox. Using activates=false avoids the 60s
foreground activation timeout that killed the previous NSWorkspace
attempt on headless CI runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 03:34:56 -07:00
austinpower1258
eee5862ca7 Add verbose diagnostics to display resolution UI test launch failure
Include the app's stdout/stderr log contents and full env dump in the
error message so we can see what happens on CI when the app runs but
doesn't write diagnostics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 03:23:25 -07:00
austinpower1258
e4ef74c8b2 Fix env contamination in Process-based UI test app launch
The test runner's environment contains XCTest variables
(DYLD_INSERT_LIBRARIES, XCInjectBundle, etc.) that cause the app to
hang when inherited by a Process-launched binary. Pass only system
essentials + our CMUX_UI_TEST_* vars, matching how the smoke test
launches the app with a clean environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 03:14:29 -07:00
austinpower1258
88751b2d12 Launch app binary directly via Process in display resolution UI test
The smoke test (smoke-test-ci.sh) passes on the same WarpBuild runners
because it launches the binary directly. XCUIApplication.launch() and
NSWorkspace.openApplication both require foreground activation which
fails on headless CI runners since ~04:00 UTC 2026-03-23. Running the
binary directly via Process works without WindowServer activation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 02:59:49 -07:00
austinpower1258
ae064802c6 Use NSWorkspace to launch app in display resolution UI test
XCUIApplication.launch() hard-fails with a 60-second timeout when
it can't foreground the app on headless CI runners. This test never
uses XCUIApplication for interaction (no taps/keys) — it only reads
a diagnostics file.

Replace with NSWorkspace.openApplication which launches through
Launch Services, passes env vars via OpenConfiguration, and returns
immediately without blocking on activation failure.

Also add CI retry loop since runner environment is flaky.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 02:48:31 -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
austinpower1258
82a16aa746 Replace XCUIApplication with NSWorkspace for display regression test
XCUIApplication.launch() blocks for 60 seconds trying to foreground
the app on headless CI runners, then hard-fails the test (not
recoverable with continueAfterFailure). This test doesn't need
XCUIApplication — it never taps buttons or types keys, it only reads
a diagnostics file.

Switch to NSWorkspace.openApplication which:
- Launches through Launch Services (proper macOS app lifecycle)
- Passes environment vars via OpenConfiguration
- Returns immediately with NSRunningApplication handle
- Doesn't block or hard-fail on activation issues

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 02:29:45 -07:00
austinpower1258
75375ab7af Fix display resolution UI test foreground activation on CI
XCUIApplication.launch() fails to activate the app on headless CI
runners, reporting "Failed to activate application (current state:
Running Background)". With continueAfterFailure=false, this kills the
test before ensureForegroundAfterLaunch can retry.

Fix by temporarily setting continueAfterFailure=true around launch(),
then retrying activation via app.activate(). Also add a retry loop in
the CI workflow since foreground activation is inherently flaky on
headless runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 02:19:12 -07:00
austinpower1258
10fd323bb0 Fix display regression UI test launch gating 2026-03-23 02:05:07 -07:00
austinpower1258
54ec524a63 Fix display regression launch on CI runner 2026-03-23 01:54:29 -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
BillionToken
59f526a452
fix(terminal): prevent cursor movement on double-click selection (#1709)
Double-clicking to select text in the terminal was causing unwanted cursor
movement because the mouse position was being updated on both the first and
second clicks. This disrupted the selection gesture and caused the cursor to
jump to a different position than intended.

Fix by only updating the mouse position on the first click (clickCount == 1),
allowing the terminal's selection logic to handle multi-click gestures without
cursor interference.

Fixes manaflow-ai/cmux#1698

Co-authored-by: BillionClaw <267901332+BillionClaw@users.noreply.github.com>
2026-03-22 18:54:12 -07:00
Lawrence Chen
da1bfedb87
Merge pull request #1965 from manaflow-ai/task-scrollbar-fix-mainline
Preserve explicit wheel scrollback against passive follow
2026-03-22 18:51:15 -07:00
Gale
ef9d917bef
Fix reload.sh build failure exit handling (#1888) 2026-03-22 18:40:08 -07:00
Lawrence Chen
c1c028e628
Preserve explicit wheel scrollback against passive follow 2026-03-22 18:11:06 -07:00
Lawrence Chen
7634abe616
Add regression test for wheel scrollback follow bug 2026-03-22 18:11:00 -07:00