Skip to content

Add opt-in setting to open Cmd-clicked markdown files in cmux viewer - #2904

Merged
austinywang merged 1 commit into
manaflow-ai:mainfrom
SeongJaeSong:feat/cmd-click-markdown-viewer
Apr 15, 2026
Merged

austinywang merged 1 commit into
manaflow-ai:mainfrom
SeongJaeSong:feat/cmd-click-markdown-viewer

Conversation

@SeongJaeSong

@SeongJaeSong SeongJaeSong commented Apr 15, 2026 •

Copy link
Copy Markdown

Summary

  • What: Adds an opt-in setting (app.openMarkdownInCmuxViewer, default off) that routes Cmd-clicked markdown paths (.md, .markdown, .mkd, .mdx) in the terminal to the built-in cmux markdown viewer panel (with live reload) instead of the preferred editor. Reuses an existing viewer panel when one already shows the same file.
  • Why: Closes Route command-clicked .md files to cmux markdown viewer #1778. Agent workflows (Claude Code, etc.) reference a lot of markdown files in terminal output — piping them into the formatted live-reload viewer is a much better experience than opening raw markdown in an editor.

Behavior

Toggle Target Result
Off (default) any path Preserves existing PreferredEditorSettings.open / NSWorkspace.open behavior
On local, readable, regular .md* file Splits a viewer panel to the right (or focuses an existing viewer for the same path)
On same file already displayed in a viewer Focuses the existing panel (mirrors browser-link reuse)
On remote workspace, missing file, directory, non-regular file, unreadable file Falls back to preferred editor / system opener
On file://host/... (non-local), or URL with #fragment / ?query Falls through to system opener so the host / anchor is preserved

Implementation notes

  • New CmdClickMarkdownRouteSettings enum in Sources/cmuxApp.swift:
    • isMarkdownPath(_:) — cheap extension check, safe off main thread.
    • shouldRoute(path:) — full readiness check (toggle + extension + readable + regular file via attributesOfItem). Mirrors the existing markdown.open socket path's isReadableFile guard.
  • Two integration points — both reuse the existing Workspace.newMarkdownSplit API that powers cmux markdown open:
    • GHOSTTY_ACTION_OPEN_URL in GhosttyTerminalView.swift for Ghostty-consumed clicks (URL-formed targets, OSC-8 hyperlinks). Runs before the browser-link early return so the setting works regardless of browser.openTerminalLinksInCmuxBrowser.
    • handleCommandClickRelease fallback path for word-under-cursor resolutions.
  • Both sites check the remote-workspace guard before any filesystem probe, so remote terminals never stat local paths on the main thread.
  • Settings plumbing: new key registered in CmuxSettingsFileStore.supportedSettingsJSONPaths, parsed from settings.json, included in the default settings template, and published in web/data/cmux-settings.schema.json.
  • Settings UI: a toggle row beneath Open Files With in the App section.
  • Localizations added for the title and subtitle in Localizable.xcstrings (en / ja / ko / zh-Hans / zh-Hant / de / es / fr / it).

Testing

  • How: Manually exercised the feature in a Debug build (reload.sh --tag pr-1778 --launch) — toggled the setting off/on and Cmd-clicked the paths below in a terminal panel.
  • What was verified:
    • Toggle off (default): .md Cmd-click opens in the preferred editor — no regression.
    • Toggle on, local .md: splits a viewer panel to the right with live reload.
    • Toggle on, same .md clicked again: second click focuses the existing panel (no duplicate split).
    • Toggle on, different .md: new split is created.
    • Toggle on, non-md (.zshrc, etc.): opens in preferred editor (no false-positive routing).
    • Settings UI toggle renders under Open Files With and persists across restarts.
    • Settings > App crash from precondition failure on an unknown JSON path was caught during development and fixed by registering the new key in supportedSettingsJSONPaths + parser + default template.
  • Not exercised locally (would need a more involved harness / remote VM):
    • Remote workspace fallback — covered by the code path but not manually reproduced.
    • file:// URLs with #fragment / ?query — covered by the guard.
    • Non-regular / unreadable files — covered by the isReadableFile + typeRegular check.

Happy to expand coverage or add an automated test if there's a harness suggestion for the cmd-click fallback paths.

Demo Video

I don't have a suitable recording setup here — happy to add a short clip if it helps. In the meantime, the behavior is reproducible in any Debug build by toggling Settings > App > Open Markdown in cmux Viewer and Cmd-clicking an .md path in a terminal.

  • Video URL or attachment:
Screen.Cast.2026-04-15.at.12.39.43.PM.mp4

Review Trigger (Copy/Paste as PR comment)

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

Checklist

  • I tested the change locally
  • I added or updated tests for behavior changes
  • I updated docs/changelog if needed
  • I requested bot reviews after my latest commit (copy/paste block above or equivalent)
  • All code review bot comments are resolved
  • All human review comments are resolved

Summary by CodeRabbit

  • New Features
    • Added "Open Markdown in cmux Viewer" toggle: when enabled, Cmd-clicking Markdown files opens (or focuses) a built-in markdown viewer panel instead of the preferred editor. Disabled by default.
  • Configuration
    • New persistent setting exposed in app settings and schema.
  • Localization
    • Added localized title and subtitle strings for the new setting across supported locales.

@vercel

vercel Bot commented Apr 15, 2026

Copy link
Copy Markdown

@claude is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f96c9a3f-50e7-4251-81f6-529dcfbcb41d

📥 Commits

Reviewing files that changed from the base of the PR and between bda43bf and 63180ed.

📒 Files selected for processing (6)
  • Resources/Localizable.xcstrings
  • Sources/GhosttyTerminalView.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/Workspace.swift
  • Sources/cmuxApp.swift
  • web/data/cmux-settings.schema.json
✅ Files skipped from review due to trivial changes (2)
  • Resources/Localizable.xcstrings
  • Sources/GhosttyTerminalView.swift
🚧 Files skipped from review as they are similar to previous changes (2)
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • web/data/cmux-settings.schema.json

📝 Walkthrough

Walkthrough

Adds a persisted setting and UI toggle to route Cmd-clicked Markdown file paths from the terminal into a cmux Markdown viewer panel (open/focus), with routing guards for remote workspaces, workspace split creation, and localization entries.

Changes

Cohort / File(s) Summary
Localization
Resources/Localizable.xcstrings
Added two localization keys: settings.app.openMarkdownInCmuxViewer and settings.app.openMarkdownInCmuxViewer.subtitle with per-locale translations.
Terminal routing
Sources/GhosttyTerminalView.swift
When enabled, cmd-click/URL handling for local Markdown paths attempts openOrFocusMarkdownSplit(...) first; falls back to existing external open logic if routing fails. Added remote-workspace guard before local-path checks.
App settings & UI
Sources/cmuxApp.swift
Introduced CmdClickMarkdownRouteSettings (key/default/isEnabled/isMarkdownPath/shouldRoute) and an @AppStorage openMarkdownInCmuxViewer toggle in SettingsView; reset-all restores default.
Settings persistence
Sources/KeyboardShortcutSettingsFileStore.swift
Added app.openMarkdownInCmuxViewer to supported settings JSON paths, default template, and parsing to persist the boolean in managed defaults.
Workspace panel management
Sources/Workspace.swift
Added openOrFocusMarkdownSplit(from:filePath:) to focus an existing MarkdownPanel by canonical path or create a new markdown split.
Web schema
web/data/cmux-settings.schema.json
Added app.openMarkdownInCmuxViewer boolean schema property (default: false); reformatted some enum/array literals for consistency only.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Terminal as GhosttyTerminalView
    participant Settings as CmdClickMarkdownRouteSettings
    participant Workspace as Workspace
    participant Viewer as MarkdownPanel
    participant Editor as PreferredEditorSettings

    User->>Terminal: Cmd-click markdown file path
    Terminal->>Terminal: Parse URL / determine local vs remote
    Terminal->>Settings: shouldRoute(path)?
    alt Remote workspace or routing disabled
        Terminal->>Editor: Open with preferred editor (NSWorkspace)
        Editor-->>User: File opened externally
    else Local & routing enabled
        Settings->>Settings: Resolve symlinks & verify readable file
        alt Routable markdown file
            Terminal->>Workspace: openOrFocusMarkdownSplit(from, filePath)
            Workspace->>Viewer: Focus existing or create new markdown panel
            Viewer-->>User: Rendered markdown panel
        else Not routable
            Terminal->>Editor: Open with preferred editor
            Editor-->>User: File opened externally
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped on keys and found a markdown trail,

Cmd-clicked a path and followed the tale.
Cmux opened a panel — warm, formatted, and bright,
Panels like carrots in a cozy code night.
🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature: adding an opt-in setting for routing Cmd-clicked markdown files to the cmux viewer.
Description check ✅ Passed The description follows the template with comprehensive Summary, Testing, and Demo Video sections; checklist items are mostly complete (tested locally, video provided).
Linked Issues check ✅ Passed The implementation fully addresses issue #1778: opt-in setting added, markdown routing implemented, existing panel reuse logic included, fallback behavior for edge cases working correctly.
Out of Scope Changes check ✅ Passed All changes are scoped to the stated objective of adding markdown routing via cmd-click; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
Sources/GhosttyTerminalView.swift (1)

3260-3299: Extract the markdown viewer open/focus flow into one helper.

Both handlers duplicate the same MarkdownPanel lookup/focus/create sequence. A shared helper would keep the reuse logic, split parameters, and caller-specific fallback behavior from drifting again.

Also applies to: 7876-7897

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/GhosttyTerminalView.swift` around lines 3260 - 3299, Extract the
duplicated MarkdownPanel lookup/focus/create flow into a single helper (e.g. a
function like openOrFocusMarkdown(filePath: String, termSurface:
TerminalSurface, workspace: Workspace, fallback: (URL) -> Void) -> Bool) and
call it from both handlers instead of repeating the block inside performOnMain.
The helper should perform the CmdClickMarkdownRouteSettings.shouldRoute check,
guard against remote terminals via
termSurface/owningWorkspace/isRemoteTerminalSurface, look up an existing panel
by casting panels values to MarkdownPanel and comparing filePath, call
workspace.focusPanel(existingId) if found, or call
workspace.newMarkdownSplit(...) to create and focus the new panel; return true
on handled and call the provided fallback (e.g. PreferredEditorSettings.open)
when shouldRoute fails. Replace the two duplicated sequences with calls to this
helper, passing the file URL/path and the appropriate fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/cmuxApp.swift`:
- Around line 3995-4007: The helper should return or propagate the canonicalized
(resolved) path instead of only a Bool so downstream reuse checks use the same
normalized value; update shouldRoute(path:) (or the callsite immediately after
it) to produce and return the resolved path used for validation (the `resolved`
variable created via (path as NSString).resolvingSymlinksInPath) and then use
that resolved string for the MarkdownPanel reuse lookup and any comparisons
(replace usages of raw fileURL.path or the original path with the resolved path
when comparing against (panel as? MarkdownPanel)?.filePath and when
creating/finding viewers so all consumers compare the same canonical path, e.g.
return the canonical path from shouldRoute or canonicalize right after
validation before the viewer lookup/creation flow.

In `@Sources/GhosttyTerminalView.swift`:
- Around line 3260-3299: The branch handling local file URLs currently always
returns true after PreferredEditorSettings.open(fileURL), causing the open_url
action to be consumed even when the markdown viewer is not actually used; update
the performOnMain closure so that when
CmdClickMarkdownRouteSettings.shouldRoute(path:) is false (the guard else path
where PreferredEditorSettings.open(fileURL) is called) you do not consume the
action—return false instead—while keeping the existing returns of true when you
actually focus an existing MarkdownPanel (workspace.focusPanel), or create/open
one (workspace.newMarkdownSplit); this ensures only successful viewer routing
(via CmdClickMarkdownRouteSettings.shouldRoute, existingId handling, or
newMarkdownSplit) consumes the action and everything else falls through to the
original NSWorkspace path.

---

Nitpick comments:
In `@Sources/GhosttyTerminalView.swift`:
- Around line 3260-3299: Extract the duplicated MarkdownPanel
lookup/focus/create flow into a single helper (e.g. a function like
openOrFocusMarkdown(filePath: String, termSurface: TerminalSurface, workspace:
Workspace, fallback: (URL) -> Void) -> Bool) and call it from both handlers
instead of repeating the block inside performOnMain. The helper should perform
the CmdClickMarkdownRouteSettings.shouldRoute check, guard against remote
terminals via termSurface/owningWorkspace/isRemoteTerminalSurface, look up an
existing panel by casting panels values to MarkdownPanel and comparing filePath,
call workspace.focusPanel(existingId) if found, or call
workspace.newMarkdownSplit(...) to create and focus the new panel; return true
on handled and call the provided fallback (e.g. PreferredEditorSettings.open)
when shouldRoute fails. Replace the two duplicated sequences with calls to this
helper, passing the file URL/path and the appropriate fallback.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5c232d9e-4035-436a-869d-ea15c33ca45c

📥 Commits

Reviewing files that changed from the base of the PR and between 1085927 and f4ba1eb.

📒 Files selected for processing (5)
  • Resources/Localizable.xcstrings
  • Sources/GhosttyTerminalView.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/cmuxApp.swift
  • web/data/cmux-settings.schema.json

Comment thread Sources/cmuxApp.swift
Comment thread Sources/GhosttyTerminalView.swift Outdated
@greptile-apps

greptile-apps Bot commented Apr 15, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds an opt-in app.openMarkdownInCmuxViewer toggle (default off) that intercepts Cmd-clicked .md/.markdown/.mkd/.mdx paths in the terminal and routes them to the built-in cmux markdown viewer panel, reusing an existing viewer panel when one already displays the same file. Two integration points cover both Ghostty-consumed URL clicks and the word-under-cursor fallback path. Previous review concerns (silent nil drop on split creation, missing fallback to preferred editor) are addressed in the current implementation.

Confidence Score: 5/5

Safe to merge — opt-in feature with correct fallback behavior in all identified failure paths.

All prior P0/P1 concerns (silent nil drop on split creation failure, missing PreferredEditorSettings fallback in handleCommandClickRelease) are addressed. Remaining findings are P2 style nits. The feature is default-off, remote workspace guard is in place, and both integration points fall back cleanly to the system opener when routing is inapplicable or fails.

Sources/GhosttyTerminalView.swift — main-thread file I/O in shouldRoute (network-volume hang risk, already noted in prior threads but not yet moved off-main).

Important Files Changed

Filename Overview
Sources/GhosttyTerminalView.swift Two integration points: OPEN_URL action pre-filters off-main then routes on-main; handleCommandClickRelease routes before the PreferredEditorSettings fallback. Nil-from-split-creation is now handled in both paths.
Sources/cmuxApp.swift Adds CmdClickMarkdownRouteSettings enum with isEnabled(), isMarkdownPath(), and shouldRoute() helpers; wires the @AppStorage toggle and settings UI row; resets to default on settings clear.
Sources/Workspace.swift Adds openOrFocusMarkdownSplit which reuses an existing viewer by canonical (symlink-resolved) path, or delegates to newMarkdownSplit; correctly marked @discardableResult.
Sources/KeyboardShortcutSettingsFileStore.swift Registers app.openMarkdownInCmuxViewer in supportedSettingsJSONPaths, parses it in the app section handler, and includes it in the default settings template.
web/data/cmux-settings.schema.json Adds openMarkdownInCmuxViewer boolean property with correct default and description to the app section.
Resources/Localizable.xcstrings Adds title and subtitle localization keys for en, ja, ko, zh-Hans, zh-Hant, de, es, fr, it.

Sequence Diagram

sequenceDiagram
    participant T as Terminal (I/O thread)
    participant M as Main Thread
    participant W as Workspace

    T->>T: GHOSTTY_ACTION_OPEN_URL fires
    T->>T: isEnabled() [UserDefaults, thread-safe]
    T->>T: isMarkdownPath(path) [cheap ext check]
    alt toggle off OR non-markdown
        T->>M: performOnMain: NSWorkspace.open(url)
    else toggle on AND markdown ext matches
        T->>M: performOnMain: shouldRoute(path)
        M->>M: isReadableFile + attributesOfItem
        alt not readable / not regular / remote workspace
            M-->>T: false → fall through to NSWorkspace.open
        else passes all guards
            M->>W: openOrFocusMarkdownSplit(from:filePath:)
            W->>W: resolvingSymlinksInPath → scan panels
            alt existing viewer found
                W-->>M: MarkdownPanel (focused)
            else no existing viewer
                W->>W: newMarkdownSplit(...)
                W-->>M: MarkdownPanel? (nil on failure)
            end
            alt split succeeded
                M-->>T: routed=true → return consumed
            else split failed (nil)
                M-->>T: routed=false → fall through to NSWorkspace.open
            end
        end
    end

    Note over T,W: handleCommandClickRelease (main thread)
    M->>M: shouldRoute(path)
    alt routing succeeds
        M->>W: openOrFocusMarkdownSplit(from:filePath:)
        W-->>M: MarkdownPanel?
    end
    alt nil or any guard failed
        M->>M: PreferredEditorSettings.open(url)
    end
Loading

Reviews (4): Last reviewed commit: "Route Cmd-clicked .md files to cmux mark..." | Re-trigger Greptile

Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/GhosttyTerminalView.swift">

<violation number="1" location="Sources/GhosttyTerminalView.swift:3282">
P1: Don’t consume the open_url action when markdown routing is disabled; returning true here bypasses the existing `NSWorkspace.open` path and changes the default-off behavior for local markdown file URLs.</violation>

<violation number="2" location="Sources/GhosttyTerminalView.swift:3291">
P2: Check `newMarkdownSplit` result and fall back to the preferred editor on failure; otherwise this path can silently do nothing when split creation fails.</violation>

<violation number="3" location="Sources/GhosttyTerminalView.swift:7881">
P2: Markdown open-or-focus routing logic is duplicated across two click handlers, increasing drift risk and maintenance cost.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread Sources/GhosttyTerminalView.swift Outdated
@@ -3257,6 +3257,48 @@ class GhosttyApp {
#endif

@cubic-dev-ai cubic-dev-ai Bot Apr 15, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Markdown open-or-focus routing logic is duplicated across two click handlers, increasing drift risk and maintenance cost.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/GhosttyTerminalView.swift, line 7881:

<comment>Markdown open-or-focus routing logic is duplicated across two click handlers, increasing drift risk and maintenance cost.</comment>

<file context>
@@ -7831,6 +7873,28 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
+        if let termSurface = terminalSurface,
+           let workspace = termSurface.owningWorkspace(),
+           !workspace.isRemoteTerminalSurface(termSurface.id),
+           CmdClickMarkdownRouteSettings.shouldRoute(path: resolution.path) {
+            if let existingId = workspace.panels.first(where: { _, panel in
+                (panel as? MarkdownPanel)?.filePath == resolution.path
</file context>
Fix with Cubic

Comment thread Sources/GhosttyTerminalView.swift Outdated
@SeongJaeSong

Copy link
Copy Markdown
Author

Addressed all three bots' review feedback in the updated force-push:

  • [cubic P1 / CodeRabbit] OPEN_URL default-off regression — the branch now falls through to the existing NSWorkspace.shared.open switch when the toggle is off, the file URL has a fragment/query/host, the path isn't markdown, or viewer routing fails. PreferredEditorSettings.open is no longer called from the OPEN_URL path so the default-off behavior for local markdown file:// links is preserved.
  • [Greptile P1 ×2 / cubic P2] newMarkdownSplit nil return — both call sites now check the nil return. In the cmd-click fallback (handleCommandClickRelease), failure falls back to PreferredEditorSettings.open. In the OPEN_URL path, it falls through to the existing NSWorkspace.shared.open switch.
  • [cubic P2] Duplicated open-or-focus logic — extracted into a new Workspace.openOrFocusMarkdownSplit(from:filePath:) helper.
  • [CodeRabbit] Path normalization inconsistency — the new helper resolves symlinks on both the incoming path and each existing MarkdownPanel.filePath before comparing, so the same file accessed via different spellings (./README.md, symlink, etc.) now focuses a single viewer.

Please re-review:

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@SeongJaeSong
SeongJaeSong force-pushed the feat/cmd-click-markdown-viewer branch from f4ba1eb to bda43bf Compare April 15, 2026 04:02
@cubic-dev-ai

cubic-dev-ai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Addressed all three bots' review feedback in the updated force-push:

  • [cubic P1 / CodeRabbit] OPEN_URL default-off regression — the branch now falls through to the existing NSWorkspace.shared.open switch when the toggle is off, the file URL has a fragment/query/host, the path isn't markdown, or viewer routing fails. PreferredEditorSettings.open is no longer called from the OPEN_URL path so the default-off behavior for local markdown file:// links is preserved.
  • [Greptile P1 ×2 / cubic P2] newMarkdownSplit nil return — both call sites now check the nil return. In the cmd-click fallback (handleCommandClickRelease), failure falls back to PreferredEditorSettings.open. In the OPEN_URL path, it falls through to the existing NSWorkspace.shared.open switch.
  • [cubic P2] Duplicated open-or-focus logic — extracted into a new Workspace.openOrFocusMarkdownSplit(from:filePath:) helper.
    ...

@SeongJaeSong I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

@SeongJaeSong: Thank you for the detailed summary of all the addressed feedback! The fixes look well-considered — particularly extracting Workspace.openOrFocusMarkdownSplit(from:filePath:) to eliminate the duplicated open-or-focus logic, and resolving symlinks on both sides of the comparison for consistent panel deduplication. I'll kick off a fresh review now.


🧠 Learnings used
Learnt from: tayl0r
Repo: manaflow-ai/cmux PR: 1909
File: Sources/ContentView.swift:2156-2171
Timestamp: 2026-03-23T06:08:14.740Z
Learning: Repo: manaflow-ai/cmux — In Sources/ContentView.swift, openFileInTextEditor(_:) must attempt workspace.newTextEditorSplit(from:orientation:filePath:focus:) and, if that returns nil, fall back to workspace.newTextEditorSurface(inPane:filePath:focus:) using bonsplitController.focusedPaneId. Rationale: avoid dropping file-open requests when the focused panel is not pane-backed.

Learnt from: homanp
Repo: manaflow-ai/cmux PR: 883
File: CLI/cmux.swift:1569-1586
Timestamp: 2026-03-04T22:05:07.913Z
Learning: In manaflow-ai/cmux CLI (CLI/cmux.swift), for parity with existing browser commands, markdown.open intentionally normalizes --surface before resolving --workspace/--window, relying on server-side resolution to disambiguate final routing. Avoid one-off reordering in markdown; consider any change only as a coordinated, cross-command refactor.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2864
File: Sources/Workspace.swift:7311-7320
Timestamp: 2026-04-13T23:27:14.192Z
Learning: Repo: manaflow-ai/cmux — In Sources/Workspace.swift, Workspace.openEditor(filePath:) must fall back to bonsplitController.allPaneIds.first when bonsplitController.focusedPaneId is nil so file-open requests aren’t dropped; it also reuses an existing editor if one is already open for the same file path.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2525
File: Sources/GhosttyTerminalView.swift:481-513
Timestamp: 2026-04-02T10:13:39.235Z
Learning: Repo: manaflow-ai/cmux — In Sources/GhosttyTerminalView.swift, terminal file-link resolution trims trailing unmatched closing delimiters “) ] } >” only when they are dangling (more closers than openers), preserving wrapped tokens like “(file:///tmp/a.png)”. Implemented via terminalFileLinkTrailingClosingDelimiters and count comparison inside trimTrailingTerminalFileLinkPunctuation(_:) and exercised by a regression test (PR `#2525`, commit 3f5c5b6d).

Learnt from: rodchristiansen
Repo: manaflow-ai/cmux PR: 2646
File: Sources/CmuxConfigExecutor.swift:107-118
Timestamp: 2026-04-14T19:56:42.696Z
Learning: Repo: manaflow-ai/cmux — In Sources/CmuxConfigExecutor.swift, executeWorkspaceCommand for wsDef.target == .current intentionally uses closePanel(panelId, force: true) before calling applyCustomLayout. This is by design: soft-closing (force: false) leaves detached panes that applyCustomLayout cannot reconcile. If a non-destructive autoApply variant is needed in the future, it should be opted into explicitly via a separate flag rather than changing the default force: true behavior.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2662
File: Sources/TabManager.swift:1994-1995
Timestamp: 2026-04-07T05:27:49.028Z
Learning: Repo: manaflow-ai/cmux — Sources/TabManager.swift — In applyWorkspacePullRequestRefreshResults(...), resolution .unsupportedRepository must (1) clear any existing workspace.panelPullRequests[panelId] entry and (2) reset lastTerminalState timestamp. scheduleNextWorkspacePullRequestPoll(...) sets nextPollAt to a jittered background interval for .unsupportedRepository, avoiding hot-looping `git remote -v`. Intent: when a panel moves to a non-GitHub or otherwise unsupported repo, clear the sidebar PR badge and back off polling.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2034
File: Sources/AppDelegate.swift:0-0
Timestamp: 2026-03-25T07:14:56.211Z
Learning: Repo: manaflow-ai/cmux — Sources/AppDelegate.swift — Pattern for “Open Folder”: In AppDelegate.showOpenFolderPanel(), seed NSOpenPanel.directoryURL using preferredMainWindowContextForWorkspaceCreation(debugSource: …) rather than NSApp.keyWindow, and on selection delegate to openWorkspaceForExternalDirectory(workingDirectory:…, debugSource: …). Rationale: handles auxiliary-key-window cases, ensures shouldBringToFront = true, and unifies menu/shortcut behavior with a consistent fallback to createMainWindow when workspace creation returns nil.

Learnt from: jt-hsiao
Repo: manaflow-ai/cmux PR: 1423
File: Sources/AppDelegate.swift:11220-11226
Timestamp: 2026-03-14T07:06:01.466Z
Learning: Repo: manaflow-ai/cmux — In Sources/Panels/CmuxWebView.swift, performKeyEquivalent(with:) handles Command-key routing end-to-end: (1) if allowed, route to NSApp.mainMenu.performKeyEquivalent; (2) fall back to AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) for non–menu-backed app shortcuts; (3) fall back to super.performKeyEquivalent. For non-Command keys it calls super directly. Therefore, in NSWindow.cmux_performKeyEquivalent (Sources/AppDelegate.swift), it is correct to call firstResponderWebView.performKeyEquivalent and return its Bool unconditionally to avoid re-entering SwiftUI’s performKeyEquivalent path that can swallow keys after WKWebView focus.

Learnt from: chi-feng
Repo: manaflow-ai/cmux PR: 2821
File: CLI/cmux.swift:2994-2998
Timestamp: 2026-04-11T18:54:44.886Z
Learning: Repo: manaflow-ai/cmux — In Sources/TerminalController.swift, v2 endpoints accept handle refs (e.g., "pane:<n>") for inputs like pane_id and resolve them to UUIDs via v2UUID → v2ResolveHandleRef. CLI commands (including markdown open --pane) can safely forward pane refs without pre-resolving to UUIDs, consistent with surface.create, pane.break, and surface.move.

Learnt from: tayl0r
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-04-08T03:36:30.160Z
Learning: Repo: manaflow-ai/cmux — AppDelegate.FileBrowserDrawerState threading pattern (PR `#1909`, commit e0e57809): FileBrowserDrawerState must be threaded through AppDelegate.configure() as a weak stored property (matching the sidebarState pattern), passed through both configure() call sites, with registerMainWindow parameter made non-optional. The fallback `?? FileBrowserDrawerState()` must NOT be used as it creates detached instances that are not properly owned by the window context.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2864
File: Sources/Workspace.swift:9892-9894
Timestamp: 2026-04-13T23:52:36.538Z
Learning: Repo: manaflow-ai/cmux — EditorPanel: A new method EditorPanel.updateWorkspaceId(_:) exists. In Sources/Workspace.swift, Workspace.attachDetachedSurface(_:inPane:atIndex:focus:) now calls editorPanel.updateWorkspaceId(self.id) when reattaching an EditorPanel, then reinstalls Combine observers via installEditorPanelSubscription(_:). This mirrors the existing TerminalPanel/BrowserPanel reattach pattern to keep workspace-scoped state accurate after moves.

Learnt from: rodchristiansen
Repo: manaflow-ai/cmux PR: 2647
File: Sources/ContentView.swift:2918-2932
Timestamp: 2026-04-14T20:05:27.511Z
Learning: Repo: manaflow-ai/cmux — Sources/ContentView.swift (PR `#2647`): On macOS 26, NavigationSplitView provides a native collapse chevron in the sidebar column header when the sidebar is visible. The code intentionally: (1) shows a custom toolbar toggle only when the sidebar is hidden to reopen it, and (2) uses SystemSidebarToggleStripper to remove the system-injected toolbar toggle to prevent duplication. Do not flag “no collapse affordance” while the sidebar is open.

Learnt from: BillionClaw
Repo: manaflow-ai/cmux PR: 1755
File: Sources/GhosttyTerminalView.swift:4889-4903
Timestamp: 2026-03-18T16:50:14.396Z
Learning: Repo: manaflow-ai/cmux — In Sources/GhosttyTerminalView.swift, GhosttyNSView.performKeyEquivalent(with:) must only route Command key equivalents to NSApp.mainMenu when shouldRouteCommandEquivalentDirectlyToMainMenu(event) returns true; otherwise, handle the key directly via keyDown to forward unbound Cmd+Shift combinations to the terminal and preserve the Cmd+` exclusion.

Learnt from: alumican
Repo: manaflow-ai/cmux PR: 2051
File: Sources/AppDelegate.swift:9270-9276
Timestamp: 2026-03-24T13:50:07.535Z
Learning: Repo: manaflow-ai/cmux — KeyboardShortcutSettings.Action.toggleTextBoxInput defaults to Cmd+Option+B. Rationale: avoid conflict with the existing hard-coded Cmd+Option+T binding that triggers closeOtherTabsInFocusedPaneWithConfirmation() in AppDelegate.handleCustomShortcut(event:).

Learnt from: qkrwpdlr
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-03-23T07:01:33.134Z
Learning: Repo: manaflow-ai/cmux — In Sources/Panels/BrowserPanel.swift, BrowserPickerMessageHandler gates WKScriptMessage delivery via NSEvent.addLocalMonitorForEvents(.leftMouseDown): on Option+click it stamps ProcessInfo.processInfo.systemUptime into lastNativeOptionClickTime; userContentController(_:didReceive:) rejects postMessages where elapsed >= 1.0s and zeroes the timestamp after acceptance (one-shot). The NSEvent monitor is removed in BrowserPickerMessageHandler.deinit. BrowserPanel.bindWebView(_:) removes the old script message handler and nils pickerMessageHandler before re-registering (prevents monitor leaks on profile change/webView replacement). BrowserPanel.deinit also removes the "cmuxPointer" script message handler.

Learnt from: SuperManfred
Repo: manaflow-ai/cmux PR: 1150
File: Sources/AppDelegate.swift:7394-7401
Timestamp: 2026-03-10T10:24:14.017Z
Learning: Repo: manaflow-ai/cmux — For Cmd+W behavior with browser popups: BrowserPopupPanel.performKeyEquivalent is the primary handler to close popups. AppDelegate.handleCustomShortcut(_:), in its Cmd+W fallback, must check both NSApp.keyWindow and event.window for identifier "cmux.browser-popup" and close it if found, before routing to workspace/settings close logic.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@SeongJaeSong

Copy link
Copy Markdown
Author

Re-triggering reviews for commit bda43bf9 — the previous comments referenced line numbers from the prior commit f4ba1ebb before the force-push.

@cubic-dev-ai review
@greptile-apps review
@coderabbitai review

@cubic-dev-ai

cubic-dev-ai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Re-triggering reviews for commit bda43bf9 — the previous comments referenced line numbers from the prior commit f4ba1ebb before the force-push.

@cubic-dev-ai review
@greptile-apps review
@coderabbitai review

@SeongJaeSong I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

@SeongJaeSong: Understood — kicking off a fresh review against commit bda43bf9 now.


🧠 Learnings used
Learnt from: tayl0r
Repo: manaflow-ai/cmux PR: 1909
File: Sources/ContentView.swift:2156-2171
Timestamp: 2026-03-23T06:08:14.740Z
Learning: Repo: manaflow-ai/cmux — In Sources/ContentView.swift, openFileInTextEditor(_:) must attempt workspace.newTextEditorSplit(from:orientation:filePath:focus:) and, if that returns nil, fall back to workspace.newTextEditorSurface(inPane:filePath:focus:) using bonsplitController.focusedPaneId. Rationale: avoid dropping file-open requests when the focused panel is not pane-backed.

Learnt from: rodchristiansen
Repo: manaflow-ai/cmux PR: 2646
File: Sources/CmuxConfigExecutor.swift:107-118
Timestamp: 2026-04-14T19:56:42.696Z
Learning: Repo: manaflow-ai/cmux — In Sources/CmuxConfigExecutor.swift, executeWorkspaceCommand for wsDef.target == .current intentionally uses closePanel(panelId, force: true) before calling applyCustomLayout. This is by design: soft-closing (force: false) leaves detached panes that applyCustomLayout cannot reconcile. If a non-destructive autoApply variant is needed in the future, it should be opted into explicitly via a separate flag rather than changing the default force: true behavior.

Learnt from: homanp
Repo: manaflow-ai/cmux PR: 883
File: CLI/cmux.swift:1569-1586
Timestamp: 2026-03-04T22:05:07.913Z
Learning: In manaflow-ai/cmux CLI (CLI/cmux.swift), for parity with existing browser commands, markdown.open intentionally normalizes --surface before resolving --workspace/--window, relying on server-side resolution to disambiguate final routing. Avoid one-off reordering in markdown; consider any change only as a coordinated, cross-command refactor.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2662
File: Sources/TabManager.swift:1994-1995
Timestamp: 2026-04-07T05:27:49.028Z
Learning: Repo: manaflow-ai/cmux — Sources/TabManager.swift — In applyWorkspacePullRequestRefreshResults(...), resolution .unsupportedRepository must (1) clear any existing workspace.panelPullRequests[panelId] entry and (2) reset lastTerminalState timestamp. scheduleNextWorkspacePullRequestPoll(...) sets nextPollAt to a jittered background interval for .unsupportedRepository, avoiding hot-looping `git remote -v`. Intent: when a panel moves to a non-GitHub or otherwise unsupported repo, clear the sidebar PR badge and back off polling.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2864
File: Sources/Workspace.swift:7311-7320
Timestamp: 2026-04-13T23:27:14.192Z
Learning: Repo: manaflow-ai/cmux — In Sources/Workspace.swift, Workspace.openEditor(filePath:) must fall back to bonsplitController.allPaneIds.first when bonsplitController.focusedPaneId is nil so file-open requests aren’t dropped; it also reuses an existing editor if one is already open for the same file path.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2525
File: Sources/GhosttyTerminalView.swift:481-513
Timestamp: 2026-04-02T10:13:39.235Z
Learning: Repo: manaflow-ai/cmux — In Sources/GhosttyTerminalView.swift, terminal file-link resolution trims trailing unmatched closing delimiters “) ] } >” only when they are dangling (more closers than openers), preserving wrapped tokens like “(file:///tmp/a.png)”. Implemented via terminalFileLinkTrailingClosingDelimiters and count comparison inside trimTrailingTerminalFileLinkPunctuation(_:) and exercised by a regression test (PR `#2525`, commit 3f5c5b6d).

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2864
File: Sources/Workspace.swift:9892-9894
Timestamp: 2026-04-13T23:52:36.538Z
Learning: Repo: manaflow-ai/cmux — EditorPanel: A new method EditorPanel.updateWorkspaceId(_:) exists. In Sources/Workspace.swift, Workspace.attachDetachedSurface(_:inPane:atIndex:focus:) now calls editorPanel.updateWorkspaceId(self.id) when reattaching an EditorPanel, then reinstalls Combine observers via installEditorPanelSubscription(_:). This mirrors the existing TerminalPanel/BrowserPanel reattach pattern to keep workspace-scoped state accurate after moves.

Learnt from: mrosnerr
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-04-05T21:26:10.710Z
Learning: Repo: manaflow-ai/cmux — In Sources/Workspace.swift, applySessionPanelMetadata() must gate listeningPorts restoration on the per-panel snapshot.terminal?.isRemoteBacked flag (not workspace-wide remoteTerminalStartupCommand()), so that local panels are always eligible for port restore regardless of current SSH state. Fixed in commit 4d0fd871 (PR `#2545`).

Learnt from: tayl0r
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-04-08T03:36:30.160Z
Learning: Repo: manaflow-ai/cmux — AppDelegate.FileBrowserDrawerState threading pattern (PR `#1909`, commit e0e57809): FileBrowserDrawerState must be threaded through AppDelegate.configure() as a weak stored property (matching the sidebarState pattern), passed through both configure() call sites, with registerMainWindow parameter made non-optional. The fallback `?? FileBrowserDrawerState()` must NOT be used as it creates detached instances that are not properly owned by the window context.

Learnt from: jt-hsiao
Repo: manaflow-ai/cmux PR: 1423
File: Sources/AppDelegate.swift:11220-11226
Timestamp: 2026-03-14T07:06:01.466Z
Learning: Repo: manaflow-ai/cmux — In Sources/Panels/CmuxWebView.swift, performKeyEquivalent(with:) handles Command-key routing end-to-end: (1) if allowed, route to NSApp.mainMenu.performKeyEquivalent; (2) fall back to AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) for non–menu-backed app shortcuts; (3) fall back to super.performKeyEquivalent. For non-Command keys it calls super directly. Therefore, in NSWindow.cmux_performKeyEquivalent (Sources/AppDelegate.swift), it is correct to call firstResponderWebView.performKeyEquivalent and return its Bool unconditionally to avoid re-entering SwiftUI’s performKeyEquivalent path that can swallow keys after WKWebView focus.

Learnt from: rodchristiansen
Repo: manaflow-ai/cmux PR: 2647
File: Sources/ContentView.swift:2918-2932
Timestamp: 2026-04-14T20:05:27.511Z
Learning: Repo: manaflow-ai/cmux — Sources/ContentView.swift (PR `#2647`): On macOS 26, NavigationSplitView provides a native collapse chevron in the sidebar column header when the sidebar is visible. The code intentionally: (1) shows a custom toolbar toggle only when the sidebar is hidden to reopen it, and (2) uses SystemSidebarToggleStripper to remove the system-injected toolbar toggle to prevent duplication. Do not flag “no collapse affordance” while the sidebar is open.

Learnt from: BillionClaw
Repo: manaflow-ai/cmux PR: 1755
File: Sources/GhosttyTerminalView.swift:4889-4903
Timestamp: 2026-03-18T16:50:14.396Z
Learning: Repo: manaflow-ai/cmux — In Sources/GhosttyTerminalView.swift, GhosttyNSView.performKeyEquivalent(with:) must only route Command key equivalents to NSApp.mainMenu when shouldRouteCommandEquivalentDirectlyToMainMenu(event) returns true; otherwise, handle the key directly via keyDown to forward unbound Cmd+Shift combinations to the terminal and preserve the Cmd+` exclusion.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2034
File: Sources/AppDelegate.swift:0-0
Timestamp: 2026-03-25T07:14:56.211Z
Learning: Repo: manaflow-ai/cmux — Sources/AppDelegate.swift — Pattern for “Open Folder”: In AppDelegate.showOpenFolderPanel(), seed NSOpenPanel.directoryURL using preferredMainWindowContextForWorkspaceCreation(debugSource: …) rather than NSApp.keyWindow, and on selection delegate to openWorkspaceForExternalDirectory(workingDirectory:…, debugSource: …). Rationale: handles auxiliary-key-window cases, ensures shouldBringToFront = true, and unifies menu/shortcut behavior with a consistent fallback to createMainWindow when workspace creation returns nil.

Learnt from: pstanton237
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-04-06T12:03:16.921Z
Learning: Repo: manaflow-ai/cmux — In CLI/cmux.swift, `claudeTeamsLaunchArguments` must use two independent branches: (1) prepend `--teammate-mode auto` only when the caller has NOT already supplied `--teammate-mode`; (2) append `--settings <claudeHooksJSON>` unconditionally (modulo `CMUX_CLAUDE_HOOKS_DISABLED=1` opt-out). These two branches must never be coupled in a single early-return or conditional block — coupling them was the original `#2229` regression (hook JSON silently bypassed when `--teammate-mode auto|manual` was explicit). Mirrors `Resources/bin/claude:208`: `exec "$REAL_CLAUDE" --settings "$HOOKS_JSON" "$@"` where `$@` content never gates hook injection.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 6 files

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 6 files

Adds an opt-in setting that intercepts Cmd-clicked markdown paths
(.md, .markdown, .mkd, .mdx) in the terminal and routes them to the
built-in cmux markdown viewer panel (with live reload) instead of the
preferred editor.

Default: off (opt-in). Toggle available under Settings > App.

Implementation:
- New `CmdClickMarkdownRouteSettings` enum in `cmuxApp.swift` with
  UserDefaults-backed toggle (`openMarkdownInCmuxViewer`) and a path
  extension matcher.
- `GhosttyApp.action(for:)` branches before `NSWorkspace.shared.open`
  in the `.external(url)` case of `GHOSTTY_ACTION_OPEN_URL` when the
  resolved URL is a local markdown file and the toggle is enabled.
  Uses the existing `Workspace.newMarkdownSplit` API (same entry point
  as `cmux markdown open`) to split a viewer panel to the right of the
  source terminal. Reuses an existing viewer panel when one already
  displays the same file (matches browser link reuse behavior).
- `GhosttyNSView.handleCommandClickRelease` mirrors the same branching
  for the fallback path used when Ghostty does not consume the click
  (e.g. snapshot-resolved tokens).
- `CmuxSettingsFileStore` registers the new key in
  `supportedSettingsJSONPaths`, parses `app.openMarkdownInCmuxViewer`
  from settings.json, and includes it in the default settings template.
- Settings UI adds a toggle row under `Open Files With` in the App
  section.

Closes manaflow-ai#1778
@SeongJaeSong
SeongJaeSong force-pushed the feat/cmd-click-markdown-viewer branch from bda43bf to 63180ed Compare April 15, 2026 06:33
@SeongJaeSong

Copy link
Copy Markdown
Author

Rebased onto latest main (02f741c3) to resolve the Resources/Localizable.xcstrings conflict with the new contextMenu.workspaceSettings* entries. New SHA: 63180edc.

Please re-review:

@cubic-dev-ai review
@greptile-apps review
@coderabbitai review

@cubic-dev-ai

cubic-dev-ai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Rebased onto latest main (02f741c3) to resolve the Resources/Localizable.xcstrings conflict with the new contextMenu.workspaceSettings* entries. New SHA: 63180edc.

Please re-review:

@cubic-dev-ai review
...

@SeongJaeSong I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

@SeongJaeSong: Understood — kicking off a fresh review against the rebased commit 63180edc. The rebase-only change (resolving the contextMenu.workspaceSettings* conflict in Localizable.xcstrings) shouldn't affect any of the previously reviewed logic, so this pass will focus on confirming the merge is clean and catching anything new introduced by the rebase.


🧠 Learnings used
Learnt from: tayl0r
Repo: manaflow-ai/cmux PR: 1909
File: Sources/ContentView.swift:2156-2171
Timestamp: 2026-03-23T06:08:14.740Z
Learning: Repo: manaflow-ai/cmux — In Sources/ContentView.swift, openFileInTextEditor(_:) must attempt workspace.newTextEditorSplit(from:orientation:filePath:focus:) and, if that returns nil, fall back to workspace.newTextEditorSurface(inPane:filePath:focus:) using bonsplitController.focusedPaneId. Rationale: avoid dropping file-open requests when the focused panel is not pane-backed.

Learnt from: rodchristiansen
Repo: manaflow-ai/cmux PR: 2646
File: Sources/CmuxConfigExecutor.swift:107-118
Timestamp: 2026-04-14T19:56:42.696Z
Learning: Repo: manaflow-ai/cmux — In Sources/CmuxConfigExecutor.swift, executeWorkspaceCommand for wsDef.target == .current intentionally uses closePanel(panelId, force: true) before calling applyCustomLayout. This is by design: soft-closing (force: false) leaves detached panes that applyCustomLayout cannot reconcile. If a non-destructive autoApply variant is needed in the future, it should be opted into explicitly via a separate flag rather than changing the default force: true behavior.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2662
File: Sources/TabManager.swift:1994-1995
Timestamp: 2026-04-07T05:27:49.028Z
Learning: Repo: manaflow-ai/cmux — Sources/TabManager.swift — In applyWorkspacePullRequestRefreshResults(...), resolution .unsupportedRepository must (1) clear any existing workspace.panelPullRequests[panelId] entry and (2) reset lastTerminalState timestamp. scheduleNextWorkspacePullRequestPoll(...) sets nextPollAt to a jittered background interval for .unsupportedRepository, avoiding hot-looping `git remote -v`. Intent: when a panel moves to a non-GitHub or otherwise unsupported repo, clear the sidebar PR badge and back off polling.

Learnt from: mrosnerr
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-04-05T21:26:10.710Z
Learning: Repo: manaflow-ai/cmux — In Sources/Workspace.swift, applySessionPanelMetadata() must gate listeningPorts restoration on the per-panel snapshot.terminal?.isRemoteBacked flag (not workspace-wide remoteTerminalStartupCommand()), so that local panels are always eligible for port restore regardless of current SSH state. Fixed in commit 4d0fd871 (PR `#2545`).

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2864
File: Sources/Workspace.swift:9892-9894
Timestamp: 2026-04-13T23:52:36.538Z
Learning: Repo: manaflow-ai/cmux — EditorPanel: A new method EditorPanel.updateWorkspaceId(_:) exists. In Sources/Workspace.swift, Workspace.attachDetachedSurface(_:inPane:atIndex:focus:) now calls editorPanel.updateWorkspaceId(self.id) when reattaching an EditorPanel, then reinstalls Combine observers via installEditorPanelSubscription(_:). This mirrors the existing TerminalPanel/BrowserPanel reattach pattern to keep workspace-scoped state accurate after moves.

Learnt from: mrosnerr
Repo: manaflow-ai/cmux PR: 2545
File: Sources/Workspace.swift:0-0
Timestamp: 2026-04-02T21:40:59.098Z
Learning: Repo: manaflow-ai/cmux — In Sources/Workspace.swift session snapshot logic, detected foreground command lines are only recorded if they pass SessionRestoreCommandSettings.isCommandAllowed(...). Commit f887189 moved gating to the SessionForegroundProcessCache so unallowed (potentially sensitive) commands are never written to the session JSON.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2864
File: Sources/Workspace.swift:7311-7320
Timestamp: 2026-04-13T23:27:14.192Z
Learning: Repo: manaflow-ai/cmux — In Sources/Workspace.swift, Workspace.openEditor(filePath:) must fall back to bonsplitController.allPaneIds.first when bonsplitController.focusedPaneId is nil so file-open requests aren’t dropped; it also reuses an existing editor if one is already open for the same file path.

Learnt from: homanp
Repo: manaflow-ai/cmux PR: 883
File: CLI/cmux.swift:1569-1586
Timestamp: 2026-03-04T22:05:07.913Z
Learning: In manaflow-ai/cmux CLI (CLI/cmux.swift), for parity with existing browser commands, markdown.open intentionally normalizes --surface before resolving --workspace/--window, relying on server-side resolution to disambiguate final routing. Avoid one-off reordering in markdown; consider any change only as a coordinated, cross-command refactor.

Learnt from: debgotwired
Repo: manaflow-ai/cmux PR: 1149
File: Sources/ContentView.swift:3977-3978
Timestamp: 2026-03-10T09:33:37.952Z
Learning: In manaflow-ai/cmux (Sources/ContentView.swift), scheduleCommandPaletteResultsRefresh(forceSearchCorpusRefresh:) is shared command‑palette infrastructure across all submenus. Do not change its sync‑seeding behavior within feature‑scoped PRs; treat brief initial flashes as consistent with existing submenus. Any UX improvement (e.g., synchronous seeding on forced corpus refresh) should be implemented and tested globally in a dedicated follow‑up PR.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2034
File: Sources/AppDelegate.swift:0-0
Timestamp: 2026-03-25T07:14:56.211Z
Learning: Repo: manaflow-ai/cmux — Sources/AppDelegate.swift — Pattern for “Open Folder”: In AppDelegate.showOpenFolderPanel(), seed NSOpenPanel.directoryURL using preferredMainWindowContextForWorkspaceCreation(debugSource: …) rather than NSApp.keyWindow, and on selection delegate to openWorkspaceForExternalDirectory(workingDirectory:…, debugSource: …). Rationale: handles auxiliary-key-window cases, ensures shouldBringToFront = true, and unifies menu/shortcut behavior with a consistent fallback to createMainWindow when workspace creation returns nil.

Learnt from: gaelic-ghost
Repo: manaflow-ai/cmux PR: 2262
File: Resources/Localizable.xcstrings:84820-84835
Timestamp: 2026-03-27T22:00:27.420Z
Learning: Repo: manaflow-ai/cmux — In `Resources/Localizable.xcstrings`, it is intentional for lower-confidence locales (e.g., ar, bs, da, pl, th, km, tr) to carry English-language fallback `stringUnit.value` strings with `state: "translated"` for newly added keys. This matches the existing `.xcstrings` catalog convention for the project; do not flag English values with state "translated" in these locales as a localization bug or suggest changing the state to "needs review" / "untranslated".

Learnt from: atani
Repo: manaflow-ai/cmux PR: 819
File: Sources/AppDelegate.swift:3491-3493
Timestamp: 2026-03-04T14:06:16.241Z
Learning: For manaflow-ai/cmux PR `#819` (Japanese i18n), keep scope limited to localization changes; UX enhancements like preferring workspace.customTitle in workspaceDisplayName() or altering move-target labels should be handled in a separate follow-up issue.

Learnt from: tayl0r
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-04-08T03:36:30.160Z
Learning: Repo: manaflow-ai/cmux — AppDelegate.FileBrowserDrawerState threading pattern (PR `#1909`, commit e0e57809): FileBrowserDrawerState must be threaded through AppDelegate.configure() as a weak stored property (matching the sidebarState pattern), passed through both configure() call sites, with registerMainWindow parameter made non-optional. The fallback `?? FileBrowserDrawerState()` must NOT be used as it creates detached instances that are not properly owned by the window context.

Learnt from: Znboston
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-03-26T19:00:12.434Z
Learning: Repo: manaflow-ai/cmux — Sources/GroupHeaderView.swift and Sources/ContentView.swift — Palette color entry labels (`Text(entry.name)`) use dynamic palette data loaded at runtime and cannot be statically keyed with `String(localized:)`. This matches the existing workspace color picker pattern in ContentView.swift. Palette name localization would require restructuring the color palette system and is intentionally deferred; do not flag `entry.name` as a missing localization in this codebase.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2528
File: Sources/AppDelegate.swift:2196-2200
Timestamp: 2026-04-03T03:36:45.112Z
Learning: Repo: manaflow-ai/cmux — In Sources/AppDelegate.swift, when KeyboardShortcutSettings.didChangeNotification fires, AppDelegate must clear configured-chord caches (pendingConfiguredShortcutChord and activeConfiguredShortcutChordPrefixForCurrentEvent) via clearConfiguredShortcutChordState() before refreshing tooltips/UI. Also clear chord state on applicationWillResignActive to avoid cross-activity leakage. Verified by cmuxTests/AppDelegateShortcutRoutingTests.swift::testShortcutChangeClearsPendingConfiguredChord.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2525
File: Sources/GhosttyTerminalView.swift:481-513
Timestamp: 2026-04-02T10:13:39.235Z
Learning: Repo: manaflow-ai/cmux — In Sources/GhosttyTerminalView.swift, terminal file-link resolution trims trailing unmatched closing delimiters “) ] } >” only when they are dangling (more closers than openers), preserving wrapped tokens like “(file:///tmp/a.png)”. Implemented via terminalFileLinkTrailingClosingDelimiters and count comparison inside trimTrailingTerminalFileLinkPunctuation(_:) and exercised by a regression test (PR `#2525`, commit 3f5c5b6d).

Learnt from: jt-hsiao
Repo: manaflow-ai/cmux PR: 1423
File: Sources/AppDelegate.swift:11220-11226
Timestamp: 2026-03-14T07:06:01.466Z
Learning: Repo: manaflow-ai/cmux — In Sources/Panels/CmuxWebView.swift, performKeyEquivalent(with:) handles Command-key routing end-to-end: (1) if allowed, route to NSApp.mainMenu.performKeyEquivalent; (2) fall back to AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) for non–menu-backed app shortcuts; (3) fall back to super.performKeyEquivalent. For non-Command keys it calls super directly. Therefore, in NSWindow.cmux_performKeyEquivalent (Sources/AppDelegate.swift), it is correct to call firstResponderWebView.performKeyEquivalent and return its Bool unconditionally to avoid re-entering SwiftUI’s performKeyEquivalent path that can swallow keys after WKWebView focus.

Learnt from: rodchristiansen
Repo: manaflow-ai/cmux PR: 2647
File: Sources/ContentView.swift:2918-2932
Timestamp: 2026-04-14T20:05:27.511Z
Learning: Repo: manaflow-ai/cmux — Sources/ContentView.swift (PR `#2647`): On macOS 26, NavigationSplitView provides a native collapse chevron in the sidebar column header when the sidebar is visible. The code intentionally: (1) shows a custom toolbar toggle only when the sidebar is hidden to reopen it, and (2) uses SystemSidebarToggleStripper to remove the system-injected toolbar toggle to prevent duplication. Do not flag “no collapse affordance” while the sidebar is open.

Learnt from: BillionClaw
Repo: manaflow-ai/cmux PR: 1755
File: Sources/GhosttyTerminalView.swift:4889-4903
Timestamp: 2026-03-18T16:50:14.396Z
Learning: Repo: manaflow-ai/cmux — In Sources/GhosttyTerminalView.swift, GhosttyNSView.performKeyEquivalent(with:) must only route Command key equivalents to NSApp.mainMenu when shouldRouteCommandEquivalentDirectlyToMainMenu(event) returns true; otherwise, handle the key directly via keyDown to forward unbound Cmd+Shift combinations to the terminal and preserve the Cmd+` exclusion.

Learnt from: MaTriXy
Repo: manaflow-ai/cmux PR: 1460
File: Sources/TerminalController.swift:0-0
Timestamp: 2026-03-16T08:02:13.558Z
Learning: Repo: manaflow-ai/cmux — In Sources/TerminalController.swift, socket v2 methods that accept surface_id/panel_id must handle cross-window routing. For panel background state mutations, v2PanelMarkBackground(params:) and v2PanelMarkForeground(params:) first try v2ResolveTabManager(params:), but only accept it if that manager actually owns the panelId; otherwise they fall back to AppDelegate.shared?.locateSurface(surfaceId:) to find the correct TabManager across windows. This pattern should be used for any panel_id-only routes to avoid active-window bias.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 6 files

@SeongJaeSong

Copy link
Copy Markdown
Author

@austinywang all bots green (Codex / CodeRabbit / Greptile / cubic), ready for review whenever you have a moment.

@vercel

vercel Bot commented Apr 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Apr 15, 2026 6:53pm

This branch was successfully deployed

1 active deployment
Preview — 63180edc Deployed Apr 15, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Route command-clicked .md files to cmux markdown viewer

3 participants