Skip to content

Forward CLI subcommands from GUI binary to bundled CLI (fixes #4678) - #4679

Merged
lawrencecchen merged 8 commits into
manaflow-ai:mainfrom
tiffanysun1:fix/forward-cli-subcommands-to-resources-bin
May 26, 2026
Merged

lawrencecchen merged 8 commits into
manaflow-ai:mainfrom
tiffanysun1:fix/forward-cli-subcommands-to-resources-bin

Conversation

@tiffanysun1

@tiffanysun1 tiffanysun1 commented May 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • cmux <subcommand> (e.g. cmux hooks setup) hits the GUI's Contents/MacOS/cmux binary whenever Contents/MacOS is on $PATH — which happens for shells descended from the cmux app process. The GUI ignores the args, fires a few Sentry "SDK is disabled" warnings, and gets SIGTERMed (exit 143). Repro and analysis in cmux <subcommand> hits GUI binary (exit 143) when Contents/MacOS is on PATH #4678.
  • Fix is defensive: at the top of cmuxApp.init(), if argv[1] looks like a CLI subcommand (positional, not a - flag, not a cmux:// URL) and Contents/Resources/bin/cmux exists, execv into it with the same args.
  • -psn_… (Process Serial Number markers that AppKit injects when launched via Finder/open) and other dash-flags are left alone so the GUI still launches normally.

This doesn't address the root question of why Contents/MacOS ends up on subshell $PATH in the first place — that's worth a separate look. But this patch makes the user-visible failure go away regardless of how the bad PATH got introduced.

Test plan

  • Build a tagged debug app and run <app>/Contents/MacOS/cmux hooks setup directly — should now print the CLI's hook diffs instead of SIGTERMing.
  • Launch the app via Finder / open -a / open cmux://… — should still bring up the GUI (the -psn_* and URL paths are not forwarded).
  • Run the existing UI test launches (scripts/run-tests-v*.sh) which invoke Contents/MacOS/cmux DEV with CMUX_TAG=… (env, not argv) — should be unaffected.
  • Spot check: launching with cmux --version-style flags or cmux -psn_0_12345 falls through to the GUI as today.

I authored this in the cmux repo browsing-only (no Xcode toolchain set up locally), so I haven't built the change myself — would appreciate a maintainer compiling/smoke-testing before merge.

Fixes #4678


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.


Summary by cubic

Forwards CLI subcommands from the GUI binary to the bundled CLI to stop accidental GUI launches and SIGTERM when cmux <subcommand> resolves to the app binary. Adds generic, localized error output and stronger path resolution and failure handling. Fixes #4678.

  • Bug Fixes
    • Detect CLI-style invocation at app init and exec the bundled CLI with the same args, resolving via Bundle.resourceURL or process-derived .../Resources/bin/cmux.
    • Do not forward Finder/Open launches (-psn_*), flags, cmux:// URLs, or GUI sentinels (DEV, STAGING, NIGHTLY).
    • Add CMUX_CLI_FORWARDED guard; on missing CLI, exec failure, or arg allocation failure, print generic, localized errors to stderr and exit with 127 or ENOMEM; log detailed paths in DEBUG when CLI is missing.
    • Add unit tests for argument routing and bundled CLI path resolution fallback.

Written for commit cf99c91. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features
    • Startup now detects CLI-style launches and forwards execution to the bundled command‑line tool, preserving normal GUI startup for macOS flags, sentinel modes, and URL schemes. Failures return a non‑zero exit status with localized error messages.
  • Tests
    • Added unit tests verifying which launch-argument patterns trigger the bundled CLI handoff vs. remaining in the GUI.

Review Change Stack

The GUI binary at Contents/MacOS/cmux and the CLI at
Contents/Resources/bin/cmux share the same name. When Contents/MacOS
ends up on $PATH (e.g. in any shell descended from the cmux app
process), bare `cmux <subcommand>` resolves to the GUI binary, which
silently ignores the args and gets SIGTERMed (exit 143) after a
handful of Sentry "SDK is disabled" warnings.

When cmuxApp.init() observes CLI-style argv (a positional first arg
that's not a flag and not a URL), exec the bundled CLI in-place with
the same arguments. macOS-launch markers (-psn_…, other - flags) and
cmux:// URLs are left for the GUI to handle as before.

Fixes manaflow-ai#4678
@vercel

vercel Bot commented May 24, 2026

Copy link
Copy Markdown

Someone 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 May 24, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 856d1ed3-4116-409f-9c80-d780de9868e2

📥 Commits

Reviewing files that changed from the base of the PR and between 06b2d43 and cf99c91.

📒 Files selected for processing (2)
  • Resources/Localizable.xcstrings
  • Sources/App/CLIForwardingLaunchRouter.swift

📝 Walkthrough

Hidden review stack artifact

Walkthrough

cmuxApp.init() now calls CLIForwardingLaunchRouter.forwardToBundledCLIIfNeeded(), which checks CommandLine.arguments for CLI-style invocations, resolves the bundled CLI at Contents/Resources/bin/cmux, sets a recursion guard, and execv's the bundled CLI with the original argv when appropriate.

Changes

CLI Forwarding Delegation

Layer / File(s) Summary
CLI detection, predicate, and exec
Sources/App/CLIForwardingLaunchRouter.swift
Adds CLIForwardingLaunchRouter with forwardToBundledCLIIfNeeded, shouldForwardToBundledCLI, bundledCLIURL, C-argv helpers, processExecutableURL, a recursion guard env var, execv invocation, and failure handling (errno capture, stderr, exit codes).
App startup hook
Sources/cmuxApp.swift
Calls the forwarder early in cmuxApp.init() to intercept CLI-style launches before GUI initialization.
Tests, localization, and Xcode wiring
cmuxTests/CLIForwardingLaunchArgumentTests.swift, Resources/Localizable.xcstrings, cmux.xcodeproj/project.pbxproj
Adds tests (gated by #if canImport(cmux_DEV)) validating forwarding predicate and bundled CLI URL resolution, adds three localization keys for forwarding errors, and wires the new source and test files into the Xcode project targets and groups.

Sequence Diagram

sequenceDiagram
  participant Init as cmuxApp.init()
  participant Predicate as shouldForwardToBundledCLI(arguments)
  participant Forwarder as CLIForwardingLaunchRouter.forwardToBundledCLIIfNeeded()
  participant Bundle as Resources/bin/cmux
  participant Exec as Darwin.execv()

  Init->>Predicate: pass CommandLine.arguments
  Predicate-->>Init: boolean result
  Init->>Forwarder: call when true
  Forwarder->>Bundle: resolve bundled CLI URL
  Forwarder->>Exec: execv(bundle CLI path, constructed argv)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I sniffed the args at morning light,

I hopped and checked each flag and name,
I set a guard and built the argv,
I leapt to exec the bundled game,
Now the right cmux runs without blame.

🚥 Pre-merge checks | ✅ 16 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (16 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: forwarding CLI subcommands from the GUI binary to the bundled CLI, and references the fixed issue #4678.
Description check ✅ Passed The description covers the summary of changes, reasoning, test plan, and includes references to issue #4678. All required template sections are present or adequately addressed.
Linked Issues check ✅ Passed All coding requirements from issue #4678 are met: CLI detection and forwarding to bundled CLI [#4678], GUI launch preservation for -psn_* and flags [#4678], path resolution fallback [#4678], and unit tests [#4678].
Out of Scope Changes check ✅ Passed All changes directly support CLI forwarding: routing logic, bundled CLI resolution, error localization, and unit tests. No unrelated or out-of-scope modifications detected.
Cmux Swift Actor Isolation ✅ Passed Logger marked nonisolated, CLIForwardingLaunchRouter enum uses static methods only with no mutable state, bootstrap code runs synchronously at app init before async contexts.
Cmux Swift Blocking Runtime ✅ Passed No blocking patterns found. CLIForwardingLaunchRouter uses synchronous logic with Darwin.execv() (non-blocking) and basic file/environment checks. Tests use deterministic scaffolding only.
Cmux No Hacky Sleeps ✅ Passed PR modifies only Swift files, Xcode project file, and localization strings. Check scope (TypeScript, JavaScript, shell, build/runtime) does not apply; Swift changes covered separately.
Cmux Swift Concurrency ✅ Passed New CLIForwardingLaunchRouter is entirely synchronous: uses Logger (OS API), Darwin.execv (POSIX boundary), FileManager. No DispatchQueue, Task, Combine, or @escaping handlers added.
Cmux Swift @Concurrent ✅ Passed No async/await functions introduced in this PR; all code is synchronous with no @concurrent annotation requirements or violations.
Cmux Swift File And Package Boundaries ✅ Passed CLIForwardingLaunchRouter.swift is 149 lines with single responsibility; cmuxApp.swift adds 8 lines; test file is 45 lines. No mixed responsibilities or oversized files. All within thresholds.
Cmux Swift Logging ✅ Passed Code uses proper os.log unified logging with nonisolated private Logger, no print/NSLog/debugPrint violations, debug logs guarded by #if DEBUG, stderr for CLI error output is allowed.
Cmux User-Facing Error Privacy ✅ Passed All three new user-facing error messages contain no prohibited content. Messages describe problems in user terms and suggest concrete recovery actions without exposing implementation details.
Cmux Full Internationalization ✅ Passed All user-facing Swift strings use String(localized:defaultValue:) with matching xcstrings entries containing complete translations for all 19 supported locales; test file properly guarded.
Cmux Swiftui State Layout ✅ Passed No SwiftUI state violations detected. PR adds CLI routing logic at app startup via a static enum with no @Observable, @State, @Published, ObservableObject, or render-time mutation patterns.
Cmux Architecture Rethink ✅ Passed Uses required platform bridge (execv) with clear owner, documented invariant, guard mechanism, and test coverage. No timing repairs, mutable state, split lifecycle, or duplicate wiring.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only adds CLI forwarding logic via execv, with no NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGroup code changes.

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

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

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.

@greptile-apps

greptile-apps Bot commented May 24, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes #4678 by detecting CLI-style invocations at the top of cmuxApp.init() and using execv to hand off execution to the bundled CLI at Contents/Resources/bin/cmux, preventing the GUI binary from silently absorbing subcommands like cmux hooks setup when Contents/MacOS leaks onto $PATH in shells descended from the app process.

  • CLIForwardingLaunchRouter performs the routing: it checks argv[1] against dash-flags, :// URLs, and GUI sentinels (DEV/STAGING/NIGHTLY), sets a CMUX_CLI_FORWARDED environment guard to prevent re-entry, then calls execv; all error paths write a localized message to stderr and exit with an appropriate code.
  • Localization adds three new keys for the three error conditions, covering all 19 existing catalog locales with proper Japanese translations and English placeholders for other locales, consistent with the existing catalog pattern.
  • Tests cover the core routing decisions (shouldForwardToBundledCLI) and the executable-path fallback for bundledCLIURL.

Confidence Score: 5/5

Safe to merge; the change is confined to a new pre-init routing step that either replaces the process via execv or returns without side effects, leaving the normal GUI path entirely untouched.

The forwarding logic is narrowly scoped: it activates only when argv[1] is a positional non-flag non-URL non-sentinel token, and it exits or execs before any app state is initialised. All three failure branches (missing CLI, alloc failure, execv failure) produce user-facing output and clean exits. Logging follows the unified logging convention, localisation covers the full catalog locale set, and the CMUX_CLI_FORWARDED guard closes the re-entry loop. The only finding is a cosmetic unused-variable compiler warning in release builds.

No files require special attention.

Important Files Changed

Filename Overview
Sources/App/CLIForwardingLaunchRouter.swift New file implementing CLI forwarding via POSIX execv; routing logic, error handling, and logging all look sound. One minor unused-variable warning in release builds (errorText outside #if DEBUG).
Sources/cmuxApp.swift One-line addition calling CLIForwardingLaunchRouter.forwardToBundledCLIIfNeeded() at the very top of init(), before any app state is initialized — correct placement.
Resources/Localizable.xcstrings Three new localization keys added with all 19 supported locales; Japanese has proper translations, other locales use English placeholders consistent with the existing catalog pattern.
cmuxTests/CLIForwardingLaunchArgumentTests.swift Tests cover the key forward/no-forward routing decisions and the executable-path fallback for bundledCLIURL; all meaningful code paths exercised.
cmux.xcodeproj/project.pbxproj Adds CLIForwardingLaunchRouter.swift to the app target and CLIForwardingLaunchArgumentTests.swift to the test target; references look correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[cmuxApp.init] --> B{CMUX_CLI_FORWARDED set?}
    B -- yes --> Z[Continue GUI launch]
    B -- no --> C{shouldForwardToBundledCLI?}
    C -- "no: -flag / URL / sentinel / no argv" --> Z
    C -- yes --> D{bundledCLIURL found?}
    D -- no --> E[writeStderr: missingBundledCLI\nexit 127]
    D -- yes --> F{makeCStringArguments ok?}
    F -- no --> G[writeStderr: allocateArguments\nexit ENOMEM]
    F -- yes --> H[setenv CMUX_CLI_FORWARDED=1]
    H --> I[execv bundled CLI]
    I -- success --> J[Process replaced — GUI never runs]
    I -- failure --> K[freeCStringArguments / unsetenv guard / log warning]
    K --> L[writeStderr: execFailed\nexit 127]
Loading

Reviews (7): Last reviewed commit: "Use generic CLI forwarding error copy" | Re-trigger Greptile

Comment thread Sources/cmuxApp.swift Outdated
// quiet on the fall-through path, then continue into the GUI.
for ptr in cArgs where ptr != nil { free(ptr) }
let err = String(cString: strerror(errno))
NSLog("cmux: failed to exec bundled CLI at %@: %@", cliURL.path, err)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 NSLog bypasses unified logging

The error-path diagnostic on execv failure uses NSLog, which bypasses os_log / the unified logging system. Per the project's swift-logging rule, production app code must use Logger (from os.log) instead. The fix is to add nonisolated private let logger = Logger(subsystem: Logging.subsystem, category: "CLIForwarding") at file or struct scope, then replace this call with logger.warning("failed to exec bundled CLI at \(cliURL.path, privacy: .public): \(err, privacy: .public)").

Rule Used: Flag production Swift diagnostics that bypass unif... (source)

Comment thread Sources/cmuxApp.swift Outdated
Comment on lines +103 to +147
/// If `argv` looks like a CLI invocation, exec the bundled CLI at
/// `Contents/Resources/bin/cmux` and never return. macOS-launch arguments
/// (`-psn_…`, other `-` flags) and `cmux://` URLs are left to the GUI.
private static func forwardToBundledCLIIfNeeded() {
// Re-entry guard so the exec'd CLI (which is a different binary, but
// belt-and-suspenders) can't loop back through here.
let guardKey = "CMUX_CLI_FORWARDED"
if getenv(guardKey) != nil { return }

let argv = CommandLine.arguments
guard argv.count > 1 else { return }

// Forward only if the first arg is a positional, non-flag, non-URL token.
let first = argv[1]
if first.isEmpty || first.hasPrefix("-") { return }
if first.contains("://") { return }

guard let cliURL = Bundle.main.resourceURL?.appendingPathComponent("bin/cmux"),
FileManager.default.isExecutableFile(atPath: cliURL.path) else {
return
}

setenv(guardKey, "1", 1)

// Build argv for execv: replace argv[0] with the CLI path so $0 inside
// the CLI is sensible, keep the rest verbatim.
var cArgs: [UnsafeMutablePointer<CChar>?] = []
cArgs.append(strdup(cliURL.path))
for arg in argv.dropFirst() {
cArgs.append(strdup(arg))
}
cArgs.append(nil)

_ = cliURL.path.withCString { execPath in
cArgs.withUnsafeMutableBufferPointer { buffer in
Darwin.execv(execPath, buffer.baseAddress)
}
}

// execv only returns on error. Free the dups so leak detectors stay
// quiet on the fall-through path, then continue into the GUI.
for ptr in cArgs where ptr != nil { free(ptr) }
let err = String(cString: strerror(errno))
NSLog("cmux: failed to exec bundled CLI at %@: %@", cliURL.path, err)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Symptom fix without naming the invariant

forwardToBundledCLIIfNeeded patches the observable failure (GUI binary intercepting CLI subcommands) without closing the root cause: Contents/MacOS appearing on $PATH in shells descended from the app. If the PATH-contamination path is never fixed, any future binary placed at Contents/MacOS/ risks the same ambiguity. The architectural rethink rule asks for the single source of truth and a first migration cut: the right owner for the environment passed to child shells is wherever cmux builds the shell-integration PATH (likely the shell-integration bootstrap or the env-propagation layer). A concrete first step would be an explicit PATH filter that strips Contents/MacOS before handing the environment to any child shell, making the bad state unrepresentable. The PR description acknowledges this, so this is a flag for the follow-up, not a block.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

@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: 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 `@Sources/cmuxApp.swift`:
- Around line 25-31: The forwarding call Self.forwardToBundledCLIIfNeeded() is
executing too early and incorrectly treats the GUI/UI-test launch token "DEV" as
a CLI subcommand; either move the call so it runs after
UITestLaunchManifest.applyIfPresent() and
SocketControlSettings.shouldBlockUntaggedDebugLaunch(), or modify
forwardToBundledCLIIfNeeded() to early-return when the launch is a GUI/test
launch (e.g., detect the positional token "DEV" or query
UITestLaunchManifest/SocketControlSettings) so Contents/MacOS/cmux DEV boots the
GUI instead of exec-ing the bundled CLI.
🪄 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: b589bf26-45c8-49ad-95b1-561b229bebf9

📥 Commits

Reviewing files that changed from the base of the PR and between 8627dc9 and d7a48a6.

📒 Files selected for processing (1)
  • Sources/cmuxApp.swift

Comment thread Sources/cmuxApp.swift Outdated

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Sources/cmuxApp.swift (2)

106-160: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Extract this launch-routing helper out of Sources/cmuxApp.swift.

shouldForwardToBundledCLI and the execv wrapper are lifecycle-independent logic, but this diff adds them directly to the app target’s root Sources/ file. Please move this into a dedicated helper/type and keep cmuxApp.init() as the call site only.

As per coding guidelines Sources/**/*.swift: Do not implement feature logic directly in the app target/module's root Sources/ path when the logic is independent of cmux app lifecycle and can compile/test without AppKit, SwiftUI view state, Ghostty globals, or process-wide singletons.


131-143: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Exit instead of starting the GUI when Darwin.execv fails in forwardToBundledCLIIfNeeded()

execv returns on error, but the current code only frees cArgs (and DEBUG logs) and then continues into GUI startup, so a CLI launch can still be misrouted on this failure path.

Suggested fix
-        // execv only returns on error. Free the dups so leak detectors stay
-        // quiet on the fall-through path, then continue into the GUI.
+        // execv only returns on error. Free the dups, report the failure, and
+        // terminate so a CLI invocation never falls through into GUI startup.
         for ptr in cArgs where ptr != nil { free(ptr) }
 `#if` DEBUG
         let err = String(cString: strerror(errno))
         NSLog("cmux: failed to exec bundled CLI at %@: %@", cliURL.path, err)
 `#endif`
+        fputs("error: failed to launch bundled cmux CLI\n", stderr)
+        fflush(stderr)
+        Darwin.exit(1)
     }
🤖 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 `@Sources/cmuxApp.swift` around lines 131 - 143, The failure path after
Darwin.execv in forwardToBundledCLIIfNeeded currently frees cArgs and logs only
in DEBUG but then continues into the GUI; change this to terminate the process
on execv failure: after freeing the duplicated C strings (the for ptr in cArgs
where ptr != nil { free(ptr) } loop) and the DEBUG NSLog block, call an
immediate exit with a non-zero status (e.g. exit(EXIT_FAILURE) or abort()) so
the app does not proceed into the GUI when execv fails.
🤖 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.

Outside diff comments:
In `@Sources/cmuxApp.swift`:
- Around line 131-143: The failure path after Darwin.execv in
forwardToBundledCLIIfNeeded currently frees cArgs and logs only in DEBUG but
then continues into the GUI; change this to terminate the process on execv
failure: after freeing the duplicated C strings (the for ptr in cArgs where ptr
!= nil { free(ptr) } loop) and the DEBUG NSLog block, call an immediate exit
with a non-zero status (e.g. exit(EXIT_FAILURE) or abort()) so the app does not
proceed into the GUI when execv fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0d0fa0c5-e41b-4636-abc1-e0abab36e7be

📥 Commits

Reviewing files that changed from the base of the PR and between d7a48a6 and 631e1cd.

📒 Files selected for processing (3)
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/CLIForwardingLaunchArgumentTests.swift

@socket-security

socket-security Bot commented May 26, 2026 •

Copy link
Copy Markdown

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

@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: 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 `@Sources/App/CLIForwardingLaunchRouter.swift`:
- Around line 7-47: The early-return when bundledCLIURL(...) is nil in
forwardToBundledCLIIfNeeded currently fails silently; add a DEBUG-only
diagnostic just before the guard-let's else return to log that the bundled CLI
was not found (including context like the bundle identifier/path and the
resource path you attempted), e.g. wrap an NSLog call in `#if` DEBUG ... `#endif` so
it only appears in debug builds and then keep the existing return; reference
forwardToBundledCLIIfNeeded and bundledCLIURL to locate the insertion point.
🪄 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: 1169bfde-a3d3-480c-9590-2bc458a1db4d

📥 Commits

Reviewing files that changed from the base of the PR and between 631e1cd and a3098ed.

📒 Files selected for processing (4)
  • Sources/App/CLIForwardingLaunchRouter.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/CLIForwardingLaunchArgumentTests.swift

Comment thread Sources/App/CLIForwardingLaunchRouter.swift

@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: 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 `@Sources/App/CLIForwardingLaunchRouter.swift`:
- Around line 18-29: The guard branch that handles a missing bundled CLI in
CLIForwardingLaunchRouter (the bundledCLIURL(...) check) must exit non-zero and
print a localized, sanitized stderr message instead of returning to allow the
app to continue booting into the GUI; update the failure path in the guard to
call exit(EXIT_FAILURE) after writing a localized string fetched via the project
localization API (use the new key cli.forwarding.missingBundledCLI) to STDERR
(not NSLog), and ensure you add matching cli.forwarding.missingBundledCLI
entries into Resources/Localizable.xcstrings for all supported locales with 1–2
safe next actions described in cmux/product terms.
🪄 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: bb814124-70aa-4c66-8571-70059a46ed3b

📥 Commits

Reviewing files that changed from the base of the PR and between a3098ed and 06b2d43.

📒 Files selected for processing (1)
  • Sources/App/CLIForwardingLaunchRouter.swift

Comment thread Sources/App/CLIForwardingLaunchRouter.swift Outdated
@lawrencecchen

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@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.

♻️ Duplicate comments (1)
Sources/App/CLIForwardingLaunchRouter.swift (1)

21-33: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep stderr errors product-level and stop echoing raw system text.

These failure messages still expose implementation details (bundled cmux CLI, argument allocation) and Line 137 includes raw strerror output in user-facing stderr. Keep the OS detail in the DEBUG log only, and make the localized stderr copy generic and actionable in cmux terms.

🛠️ Suggested copy change
-        writeStderr(localizedExecFailureError(errorText))
+        writeStderr(localizedExecFailureError())
         Darwin.exit(127)
@@
     private static func localizedMissingBundledCLIError() -> String {
         String(
             localized: "cli.forwarding.error.missingBundledCLI",
-            defaultValue: "error: bundled cmux CLI was not found"
+            defaultValue: "cmux couldn’t run this command from the app bundle. Reinstall cmux or run the command from a standard cmux CLI installation."
         )
     }
@@
     private static func localizedArgumentAllocationError() -> String {
         String(
             localized: "cli.forwarding.error.allocateArguments",
-            defaultValue: "error: failed to allocate launch arguments for bundled cmux CLI"
+            defaultValue: "cmux couldn’t start this command. Try again, or reinstall cmux if the problem continues."
         )
     }
@@
-    private static func localizedExecFailureError(_ errorText: String) -> String {
-        let format = String(
+    private static func localizedExecFailureError() -> String {
+        String(
             localized: "cli.forwarding.error.execFailed",
-            defaultValue: "error: failed to launch bundled cmux CLI: %@"
+            defaultValue: "cmux couldn’t start the command-line tool from the app bundle. Reinstall cmux or run the command from a standard cmux CLI installation."
         )
-        return String(format: format, errorText)
     }

As per coding guidelines, “user-facing errors, alerts, command output, API error bodies, or recovery copy must not expose … raw upstream messages” and “All user-facing strings must be localized. Use String(localized: "key.name", defaultValue: "English text") for every string shown in the UI.”

Also applies to: 48-52, 118-138

🤖 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 `@Sources/App/CLIForwardingLaunchRouter.swift` around lines 21 - 33, The
user-facing stderr messages currently leak implementation/OS details; update the
code paths around bundledCLIURL and makeCStringArguments (and any places that
call writeStderr or localized* error helpers such as
localizedMissingBundledCLIError and localizedArgumentAllocationError) so that
stderr receives only generic, localized cmux-friendly copy created with
String(localized:..., defaultValue:...), while moving low-level details
(resourcePath, executablePath, strerror or other system text) into debug logs
via cliForwardingLogger.debug or processLogger.debug; ensure no raw strerror
output is written to stderr and adapt the localized* helper implementations to
return the new generic localized strings.
🤖 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.

Duplicate comments:
In `@Sources/App/CLIForwardingLaunchRouter.swift`:
- Around line 21-33: The user-facing stderr messages currently leak
implementation/OS details; update the code paths around bundledCLIURL and
makeCStringArguments (and any places that call writeStderr or localized* error
helpers such as localizedMissingBundledCLIError and
localizedArgumentAllocationError) so that stderr receives only generic,
localized cmux-friendly copy created with String(localized:...,
defaultValue:...), while moving low-level details (resourcePath, executablePath,
strerror or other system text) into debug logs via cliForwardingLogger.debug or
processLogger.debug; ensure no raw strerror output is written to stderr and
adapt the localized* helper implementations to return the new generic localized
strings.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bf05a6e7-86a3-4586-a4ae-d79e5a3277a7

📥 Commits

Reviewing files that changed from the base of the PR and between 06b2d43 and 067f364.

📒 Files selected for processing (2)
  • Resources/Localizable.xcstrings
  • Sources/App/CLIForwardingLaunchRouter.swift

@lawrencecchen

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
✅ 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.

This branch was successfully deployed

1 active deployment
Preview – cmux — cf99c91b Deployed May 26, 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.

cmux <subcommand> hits GUI binary (exit 143) when Contents/MacOS is on PATH

3 participants