Repository navigation
Fix #5128: open links on Cmd-click inside alt-screen TUIs (Claude/Codex) - #5406
Conversation
Fixes #5128. Clicking a link inside a fullscreen alternate-screen TUI (Claude Code, Codex) opened the OS default browser instead of honoring the configured cmux link-open target. cmux's GHOSTTY_ACTION_OPEN_URL handler is already mode-independent (resolveTerminalOpenURLTarget routes per BrowserAvailabilitySettings, no mouse-mode branch); the gap was in ghostty core, where link hover state was refreshed only when mouse reporting was off or shift released capture, so a Cmd-click under a mouse-grabbing TUI never fired open_url. Bumps the ghostty submodule to 55d154a (previous pin 176bd55 + the two link-fix commits from manaflow-ai/ghostty#71, merged into fork main). The fix also evaluates links locally when the ctrl/super link modifier is held, using the effective mouse-reporting state, matching iTerm2 and macOS Terminal. Publishes and pins the matching GhosttyKit xcframework (xcframework-55d154a...-crashsubdir-cmux-crash-v1) and updates docs/ghostty-fork.md. No cmux Swift change is required (no cmux-only gap), so there are no new user-facing strings to localize. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughBump the ChangesGhostty Fork Pin Update
Sequence Diagram(s)(omitted) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Suggested reviewers
Poem
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 inconclusive)
✅ Passed checks (17 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR bumps the
Confidence Score: 5/5Safe to merge — the change is a submodule bump with matching prebuilt checksum, updated docs, and no cmux Swift routing changes. The submodule HEAD (34cbf18) has a correctly-keyed entry in ghosttykit-checksums.txt so prebuilt lookup will succeed. The docs are internally consistent with the submodule SHA and archive URL. The ghostty-side fix is a pure input-handling change with no cmux Swift or routing code touched. The swift-file-length-budget update reflects legitimate Swift file changes that arrived via the merge-from-main commit. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["User Cmd-clicks a link"] --> B{"mouseLinkRefreshAllowed?"}
B -- "Before fix: over_link = false" --> C["link-click branch SKIPPED"]
C --> D["Click reported to TUI program"]
D --> E["OS default browser opens"]
B -- "After fix: ctrlOrSuper held" --> F["over_link refreshed"]
F --> G["ghostty fires GHOSTTY_ACTION_OPEN_URL"]
G --> H["cmux resolveTerminalOpenURLTarget"]
H --> I["Configured browser target opens"]
Reviews (13): Last reviewed commit: "Refresh Swift file-length budget for Con..." | Re-trigger Greptile |
Addresses codex/greptile review of the link fix: under mouse reporting a Cmd-click over a link still leaked a half-click to the program because mouseButtonCallback reported the press (link-open runs only on release). The ghostty follow-up (manaflow-ai/ghostty#74) suppresses the whole click — press and release — whenever the ctrl/super link chord is held, keyed on the modifier like the existing shift-release path so cursor jitter can't leak a press or a release. Eliminates the half-click in both directions. Re-pins the ghostty submodule from 55d154a to d1dbbec, repoints the prebuilt GhosttyKit release/checksum, and updates docs/ghostty-fork.md. d1dbbec is an ancestor of manaflow-ai/ghostty main (PR #71 and #74 merged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/ghostty-fork.md`:
- Around line 259-261: The markdown line containing "`#74`" is being parsed as a
heading (MD018); update the text referencing PR `#74` in the docs so the hash is
escaped or the reference rephrased (for example use "\`#74`", "PR `#74`", or "PR
74") to ensure it remains plain text; modify the sentence that mentions
`manaflow-ai/ghostty` `main`, `d1dbbec9b`, and `#74` so the hash is escaped and
the line no longer starts with an ATX token.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7dd215cd-d534-4b05-a72d-db0b7a6cb5c1
📒 Files selected for processing (3)
docs/ghostty-fork.mdghosttyscripts/ghosttykit-checksums.txt
…d links Final review iteration (codex P2). After #74 suppressed the press/release of a ctrl/super-chord link click, cursorPosCallback could still emit .motion reports during a Cmd-held drag (click_state == .press), leaking button-motion to a mouse-grabbing program. ghostty #75 mirrors the shift "grab override" for the ctrl/super chord in the motion path, so the link chord now suppresses the whole click+drag — press, release, and motion — consistently. Re-pins the ghostty submodule from d1dbbec to 76ead3e and repoints the prebuilt GhosttyKit release/checksum + docs. 76ead3e is an ancestor of manaflow-ai/ghostty main (PR #71, #74, #75 merged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 37f5e63. Configure here.
Final review iteration (codex P2 x2). After #74/#75 suppressed the whole click+ drag for the ctrl/super link chord, two edges remained: the suppression fired for any button (swallowing ctrl/super right/middle clicks instead of delivering them to the program), and a stale link highlight/cursor could persist when the chord was released through cursorPosCallback's mods. ghostty #76 scopes the suppression to the left button and clears the hover by refreshing when over_link is set (mirroring keyCallback's existing reset branch). Re-pins the ghostty submodule from 76ead3e to f241952 and repoints the prebuilt GhosttyKit release/checksum + docs. f241952 is an ancestor of manaflow-ai/ghostty main (PR #71, #74, #75, #76 merged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/ghostty-fork.md`:
- Line 275: The line starting with the literal tokens "`#75`" and "`#76`" is being
parsed as ATX headings; update the text on that line (the occurrences of "`#75`"
and "`#76`") to escape the hashes (e.g., "\`#75`" and "\`#76`") or wrap them in inline
code (e.g., `#75`, `#76`) so markdownlint MD018 no longer treats them as
headings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 28ce1834-f3de-4309-bae8-e4c85a9fbc2d
📒 Files selected for processing (3)
docs/ghostty-fork.mdghosttyscripts/ghosttykit-checksums.txt
Addresses the final review round on the link-under-mouse-reporting fix: - codex P2: the suppression re-checked live modifiers, so releasing ctrl/super before the mouse button could leak the release. ghostty #77 latches the decision at left-button press (mouse.link_click_active) and applies it through the release. - greptile P2: the latch was cleared only inside the mouse-reporting block, so toggling reporting off mid-click could leave it stale; it is now cleared unconditionally on left release. Re-pins the ghostty submodule from f241952 to 59fb750 and repoints the prebuilt GhosttyKit release/checksum + docs. 59fb750 is an ancestor of manaflow-ai/ghostty main once #77 merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
docs/ghostty-fork.md (1)
285-285:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winEscape
#75to avoid markdown heading parsing.Line 285 starts with
#75, which markdownlint interprets as an ATX heading token (MD018). Prefix with "PR" or escape the hash to keep this as plain text.Suggested fix
-#75, `#76`, and `#77` are merged into fork `main`, keeping `59fb750c0` an ancestor). +PR `#75`, `#76`, and `#77` are merged into fork `main`, keeping `59fb750c0` an ancestor).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/ghostty-fork.md` at line 285, The line starting with "`#75`" is being parsed as a Markdown heading (MD018); update the text (the fragment showing "`#75`, `#76`, and `#77` are merged into fork `main`, keeping `59fb750c0` an ancestor`) so the leading hashes are not treated as ATX headings by either escaping the hashes (e.g., "\`#75`") or prefixing them with "PR" (e.g., "PR `#75`, PR `#76`, and PR `#77`...") to ensure the PR numbers render as plain text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ghostty`:
- Line 1: The submodule pointer is referencing commit
59fb750c0f21a2d0b1b61db491050360d308d3b8 which exists only on
origin/fix-5128-link-click-lifecycle, not on manaflow-ai/ghostty main; before
merging this update, ensure that commit is merged or pushed into the
manaflow-ai/ghostty main branch (or change the submodule to point to a commit
already on main) so the submodule SHA is reachable from manaflow-ai/ghostty
main.
---
Duplicate comments:
In `@docs/ghostty-fork.md`:
- Line 285: The line starting with "`#75`" is being parsed as a Markdown heading
(MD018); update the text (the fragment showing "`#75`, `#76`, and `#77` are merged
into fork `main`, keeping `59fb750c0` an ancestor`) so the leading hashes are
not treated as ATX headings by either escaping the hashes (e.g., "\`#75`") or
prefixing them with "PR" (e.g., "PR `#75`, PR `#76`, and PR `#77`...") to ensure the
PR numbers render as plain text.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1bb8b88e-8ba7-47f2-b14f-73486d581af8
📒 Files selected for processing (3)
docs/ghostty-fork.mdghosttyscripts/ghosttykit-checksums.txt
Final review round on the link-under-mouse-reporting fix (codex P2/P3): the report-suppression latched at press but the link-open path re-derived from live modifiers, so releasing ctrl/super before the button swallowed the click, and the latch reset wasn't reached on the link-open early return. ghostty #78 makes linkAtPos use the latched chord and attempts processLinks whenever the click is latched, and clears the latch via a function-level defer. One press-time decision now drives press/drag/release suppression and link opening. Re-pins the ghostty submodule from 59fb750 to 9f014e9 and repoints the prebuilt GhosttyKit release/checksum + docs. 9f014e9 is an ancestor of manaflow-ai/ghostty main once #78 merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/ghostty-fork.md`:
- Line 292: The line that starts with "`#75`, `#76`, `#77`, and `#78` are merged into
fork `main`, keeping `9f014e98b` an ancestor)" is being parsed as a Markdown ATX
heading; update the text in docs/ghostty-fork.md (the line beginning with "`#75`")
to prevent heading parsing by escaping the hashes or rendering them as
code—e.g., replace leading "#" with "\#" for each PR number or wrap the sequence
in backticks (or use an HTML entity like "&`#35`;") so the PR numbers remain plain
text.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b5211458-a4c4-4a02-b7d3-ad8fb04a7581
📒 Files selected for processing (3)
docs/ghostty-fork.mdghosttyscripts/ghosttykit-checksums.txt
…-5128-alt-screen-link-open
… on a link Final review round (codex): the latched link-open path opened the link under the release cursor for any in-flight ctrl/super click, so a chord drag that started off a link and released over one opened that link (its press was suppressed). ghostty #79 captures whether the press was over a link (link_press_over_link) and only opens via the latched path when it was, so an off-link-started drag is swallowed rather than opening a link it merely released over. Re-pins the ghostty submodule from 9f014e9 to df789cd and repoints the prebuilt GhosttyKit release/checksum + docs. df789cd is an ancestor of manaflow-ai/ghostty main once #79 merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolved by later commits; CodeRabbit current check is passing and the inline MD018 thread is marked resolved.
Resolved by later commits; CodeRabbit current check is passing and the inline MD018 thread is marked resolved.
…-link-open # Conflicts: # docs/ghostty-fork.md # ghostty # scripts/ghosttykit-checksums.txt
The origin/main merge (sidebar scroll + macOS 27 crash fixes, PR #5670) grew Sources/ContentView.swift to 19161 and Sources/SessionIndexView.swift to 2877, which exceed the inherited budget. Bump only those two entries to match; this is upstream main debt surfaced by the merge, not a change from the ghostty bump. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Fixes #5128.
Problem
Clicking a link inside a fullscreen alternate-screen TUI (Claude Code, Codex) opened the OS default browser instead of honoring the configured cmux link-open target (built-in browser, etc.). In a normal main-screen shell the same link routed correctly. The routing flipped to external the moment a mouse-reporting alt-screen TUI was active.
Root cause (ghostty core, not cmux routing)
cmux's
GHOSTTY_ACTION_OPEN_URLhandler is already mode-independent: it resolves the target viaresolveTerminalOpenURLTargetand routes to the embedded browser / external perBrowserAvailabilitySettings— there is no mouse-mode branch in cmux. The gap was in ghostty core: under mouse reporting, link hover state was only refreshed when mouse reporting was off (or shift released capture). Holding the Cmd/ctrl link modifier wasn't considered, soover_linkstayedfalse, the link-click branch inmouseButtonCallbackwas skipped, and the Cmd-click was reported to the program — which is what triggered the OS default browser. Once ghostty firesopen_url, cmux already honors the setting.Fix
Bumps the
ghosttysubmodule toe610c8e16, the currentmanaflow-ai/ghosttymainhead from manaflow-ai/ghostty#80. That merge commit combines:f78189ac1— the Ghostty iOS render bounded-acquire line already pinned by current cmuxmain.df789cd4b— the full Terminal links open in external default browser instead of cmux's built-in browser when a fullscreen (alt-screen) TUI is active #5128 link-click fix line, including fix: open terminal links on cmd-click even when mouse reporting is active ghostty#71, Revert "fix cmux crashing issue" #74, Release v0.46.0 #75, Fix sidebar drag-and-drop broken by FileDropOverlayView #76, Bump version to 0.47.0 #77, Fix claude shim conflicting with --resume and --continue #78, Fix FileDropOverlay recursion crash on mouse events #79.Net behavior: the link chord owns only the left click+drag lifecycle (press/drag/release) when it starts on a link; everything else reaches the program and hover never sticks. This keeps the main-branch Ghostty work and the #5128 fix instead of choosing one side of the submodule conflict.
No cmux Swift routing changes are needed.
Cross-repo bits
e610c8e16is reachable from forkmain.xcframework-e610c8e166ce3ac2dc13f36e542b287bb78f9cd3-crashsubdir-cmux-crash-v1and pinned its archive SHA-256 inscripts/ghosttykit-checksums.txt.docs/ghostty-fork.mdupdated with the new fork head, the merged-line summary, and the Fix zsh git branch refresh race after cwd change #71/Revert "fix cmux crashing issue" #74-Release v0.48.0 #80 notes.Tests
resolveTerminalOpenURLTarget) is mode-independent and already covered.mouseLinkRefreshAllowedState) covering the regression truth table.mouseButtonCallback/cursorPosCallback, which is integration-level (needs a liveSurface+ a mouse-reporting program); it was verified by cmux dogfood before this conflict-resolution pass. I did not rerun local tests/builds/reload in this pass per handoff constraints.No user-facing cmux strings changed, so no localization file changes are needed.