Skip to content

Fail closed when CLI forwarding loops back to the GUI binary - #8788

Merged
teamleaderleo merged 8 commits into
manaflow-ai:mainfrom
kunsanglee:fix/cli-forwarding-loop-fail-closed
Sep 25, 2026
Merged

teamleaderleo merged 8 commits into
manaflow-ai:mainfrom
kunsanglee:fix/cli-forwarding-loop-fail-closed

Conversation

@kunsanglee

@kunsanglee kunsanglee commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Problem

When a CLI-style invocation reaches the GUI binary while CMUX_CLI_FORWARDED is already set, CLIForwardingLaunchRouter.forwardToBundledCLIIfNeeded() returns early and the process falls through into the normal SwiftUI app launch. The process then sits in the AppKit event loop indefinitely as a faceless GUI instance.

This is worst for agent hook commands (cmux claude-hook pre-tool-use etc.): each hook event leaves one idle full GUI app process (Sparkle, Sentry, event loop and all) behind, and they accumulate into dozens of lingering cmux claude-hook … processes under headless agent sessions. Field forensics from an affected machine: sample of a lingering hook process showed the main thread parked in NSApplicationMain → -[NSApplication run] with no CLI work on any thread, 11+ minutes after launch, parented to a headless claude worker.

#4678 / #4679 fixed the primary path (forwarding CLI argv to the bundled CLI), but the guard fall-through remains: if forwarding ever resolves back to the GUI binary (mispackaged bundle, or the guard value leaking into a caller's environment), the second pass silently boots the GUI instead of failing.

Fix

Route the launch through an explicit ForwardingDecision:

  • GUI-style argv (no subcommand, -psn_.../- flags, cmux:// URLs, launch sentinels) still launches the app, guard set or not.
  • First-pass CLI argv still execs the bundled CLI.
  • CLI argv with the guard already set now writes a localized error to stderr and exits 127 instead of booting the GUI. The exec loop stays broken, and hook invocations can never linger as faceless GUI instances.

Verification

  • swiftc -typecheck passes on the modified router file.
  • Added unit tests for the new decision function (fail-closed with guard set, forwarding without it, GUI launches unaffected either way) in CLIForwardingLaunchArgumentTests.
  • New cli.forwarding.error.forwardingLoop string seeded across locales in Localizable.xcstrings following the existing cli.forwarding.error.* entries.
  • I could not run the full app build locally (no GhosttyKit toolchain set up), so CI should be the authority on the build.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fails closed when CLI forwarding resolves back to the GUI binary to stop lingering faceless app processes from agent hooks. Adds an explicit routing decision and exits with a localized error (code 127) when CMUX_CLI_FORWARDED is already set, including the RC launch sentinel still routing to the GUI.

  • Bug Fixes

    • When the guard is set, print a localized error to stderr and exit 127 instead of launching the GUI.
    • GUI-style launches unchanged; first-pass CLI still execs the bundled CLI.
    • Added tests for the decision policy; added cli.forwarding.error.forwardingLoop with real translations across 20 locales (including km).
  • Refactors

    • Moved pure argv/guard classification into CMUXAgentLaunch as CLIForwardingDecision; the app router now delegates and keeps only the exec/exit and stderr glue.

Written for commit 731cffd. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Improved command-line launching to distinguish CLI commands from normal graphical launches.
    • Added protection against forwarding loops, with a clear localized error message and a controlled failure status.
    • Preserved expected handling for macOS launch arguments, URLs, and other GUI-style invocations.
  • Localization

    • Added translated forwarding-loop error messages across supported languages.

A CLI-style invocation (e.g. an agent hook command like `cmux
claude-hook pre-tool-use`) that reaches the GUI binary with
CMUX_CLI_FORWARDED already set used to fall through into the normal
SwiftUI app launch. The process then sat in the AppKit event loop
forever as a faceless GUI instance, and hook-driven invocations
accumulated one idle app process per hook event.

Route the launch through an explicit ForwardingDecision: GUI-style
argv still launches the app, first-pass CLI argv still execs the
bundled CLI, and a CLI invocation with the guard already set now
exits 127 with a localized error instead of booting the GUI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds a shared CLI forwarding policy, integrates explicit loop detection into the launch router, reports forwarding loops with localized stderr text, exits with status 127, and adds policy tests for CLI and GUI argument patterns.

Changes

CLI forwarding behavior

Layer / File(s) Summary
Forwarding policy and coverage
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CLIForwardingLaunchPolicy.swift, Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/CLIForwardingLaunchPolicyTests.swift
The policy classifies GUI-style and CLI-style argv values, combines classification with the forwarding guard, and tests all three routing outcomes.
Router integration and loop error
Sources/App/CLIForwardingLaunchRouter.swift, Resources/Localizable.xcstrings
The router delegates classification, forwards bundled CLI invocations, preserves GUI launches, and emits a localized forwarding-loop error before exiting with status 127.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLIInvocation
  participant CLIForwardingLaunchRouter
  participant CLIForwardingLaunchPolicy
  participant BundledCLI
  participant stderr
  participant Process
  CLIInvocation->>CLIForwardingLaunchRouter: evaluate argv and forwarding guard
  CLIForwardingLaunchRouter->>CLIForwardingLaunchPolicy: request forwarding decision
  CLIForwardingLaunchPolicy-->>CLIForwardingLaunchRouter: return launchGUI, forwardToBundledCLI, or failForwardingLoop
  CLIForwardingLaunchRouter->>BundledCLI: forward CLI invocation
  CLIForwardingLaunchRouter->>stderr: write localized loop error
  CLIForwardingLaunchRouter->>Process: exit with status 127
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux No Ambient Global State ❌ Error FAIL: CLIForwardingLaunchPolicy at Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CLIForwardingLaunchPolicy.swift:21 is a new caseless static-helper namespace. Move the routing logic onto a constructable, injectable owning type with instance methods, and inject it at the app seam instead of exposing static-only policy APIs.
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (23 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed The diff adds only pure static routing logic and a nonisolated logger; no new MainActor, Sendable, or UI-store isolation regressions appear.
Cmux Swift Blocking Runtime ✅ Passed The diff adds routing/exit logic and tests only; no semaphores, waits, sleeps, syncs, polling, or manual locks appear in changed non-test Swift files.
Cmux Browser Automation Off-Main ✅ Passed PR only changes CLI forwarding/localization files; no browser.* routing, socket-worker policy, or WebKit/AppKit browser automation paths were touched.
Cmux Expensive Synchronous Load ✅ Passed The diff only adds argv classification, exec/error handling, tests, and localization; no synchronous agent-history/JSON loads or MainActor interactive work were introduced.
Cmux Cache Substitution Correctness ✅ Passed The diff only changes CLI launch routing and localization; it does not replace any fresh authoritative read with a cached value in a persistence/history/snapshot path.
Cmux No Hacky Sleeps ✅ Passed Diff only changes Swift sources and localization; no TypeScript, JavaScript, shell, or build/runtime scripts to which this sleeps rule applies.
Cmux Algorithmic Complexity ✅ Passed The diff only adds O(1)/O(n argv) routing with a 3-item sentinel Set and test-only checks; no nested scans or scalable rescans were introduced.
Cmux Swift Concurrency ✅ Passed The diff only adds synchronous launch-policy routing and tests; no DispatchQueue, Combine, completion handlers, or fire-and-forget Tasks were introduced.
Cmux Swift @Concurrent ✅ Passed The diff only adds synchronous, pure routing helpers and tests; no new async/nonisolated code or @concurrent misannotation appears.
Cmux Swift Package Boundaries ✅ Passed PASS: CLI forwarding classification moved into the CMUXAgentLaunch package; the app target keeps only guard/env, exec, stderr, and exit glue.
Cmux Swiftpm Lockfiles ✅ Passed PR only changes Swift sources and localization; no Package.swift, Package.resolved, .gitignore, or workflow files were touched.
Cmux Swift Logging ✅ Passed PASS: The diff adds no new print/debugPrint/NSLog; the existing nonisolated Logger and stderr writes in CLIForwardingLaunchRouter were pre-existing, and the new code is pure policy/tests.
Cmux User-Facing Error Privacy ✅ Passed The new stderr/localized error is generic cmux wording and exposes no upstream vendor names, env vars, secrets, or raw upstream messages.
Cmux Full Internationalization ✅ Passed The new Swift error uses String(localized:defaultValue:), and the new xcstrings key has translated values for all 20 supported locales with no placeholders.
Cmux Swiftui State Layout ✅ Passed The PR only changes CLI routing, policy, tests, and localization; no SwiftUI state/layout code or prohibited patterns were introduced.
Cmux Architecture Rethink ✅ Passed PASS: The change centralizes argv classification in a pure policy and keeps exec/exit glue in one app router; no sleeps, polling, locks, or split lifecycle ownership.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR only changes CLI forwarding logic, tests, and localization; no NSWindow/WindowGroup code or cmuxAuxiliaryWindowIdentifiers changes are introduced.
Cmux Source Artifacts ✅ Passed All changed paths are source/tests/localization; none match artifact or scratch directory patterns from the rule.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No production test/debug seam was added; the new API is used by app routing, and test observation lives in Tests/ only.
Title check ✅ Passed The title is concise, specific, and accurately summarizes the main change: failing closed on CLI forwarding loops.
Description check ✅ Passed The description covers Summary and Testing well; non-critical template sections like Demo Video, Review Trigger, and Checklist are omitted.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@kunsanglee
kunsanglee marked this pull request as ready for review July 24, 2026 00:31
@greptile-apps

greptile-apps Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a silent fall-through in CLIForwardingLaunchRouter where CLI-style argv reaching the GUI binary with CMUX_CLI_FORWARDED already set would boot a faceless GUI instance instead of failing — each agent hook invocation could leave one idle app process (Sparkle, Sentry, event loop) lingering indefinitely. The fix introduces an explicit CLIForwardingDecision enum and a pure CLIForwardingLaunchPolicy classifier extracted into the CMUXAgentLaunch package, and routes the failForwardingLoop case to a localized stderr error + exit(127).

  • New CLIForwardingDecision enum replaces the boolean guard check with three explicit cases (launchGUI, forwardToBundledCLI, failForwardingLoop), making the routing exhaustive and impossible to silently extend.
  • Pure policy in CMUXAgentLaunch package keeps argv classification testable independently of the exec/exit glue in the app target; new unit tests cover loop detection, first-pass forwarding, and GUI passthrough with the guard set.
  • Localization adds cli.forwarding.error.forwardingLoop with correct translations across all 20 supported locales.

Confidence Score: 5/5

Safe to merge — the change is a targeted fail-closed fix with no effect on normal GUI or first-pass CLI launches.

The routing logic is exhaustive via an explicit enum switch, the pure policy is independently tested, all 20 locales get correct translations, and the fallback exit path was the only behavior change. No correctness, data, or security issues were found.

No files require special attention.

Important Files Changed

Filename Overview
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CLIForwardingLaunchPolicy.swift New file introducing CLIForwardingDecision enum and pure CLIForwardingLaunchPolicy classifier; logic is correct and stateless
Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/CLIForwardingLaunchPolicyTests.swift New tests covering fail-closed loop detection, GUI passthrough with guard set, and first-pass CLI forwarding
Sources/App/CLIForwardingLaunchRouter.swift Router updated to switch on CLIForwardingDecision; failForwardingLoop now writes localized error to stderr and exits 127 instead of falling through to the GUI
Resources/Localizable.xcstrings Adds cli.forwarding.error.forwardingLoop with proper translations across all 20 supported locales

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[GUI binary launched] --> B{forwardToBundledCLIIfNeeded}
    B --> C[CLIForwardingLaunchPolicy.decision]
    C --> D{shouldForwardToBundledCLI?}
    D -- No: no subcommand / -flag / URL / sentinel --> E[.launchGUI]
    E --> F[Normal SwiftUI app launch]
    D -- Yes: CLI-style argv --> G{CMUX_CLI_FORWARDED set?}
    G -- No: first pass --> H[.forwardToBundledCLI]
    H --> I[setenv guard + execv bundled CLI]
    G -- Yes: already forwarded --> J[.failForwardingLoop]
    J --> K[Write localized error to stderr]
    K --> L[exit 127]
    style J fill:#ff6b6b,color:#fff
    style L fill:#ff6b6b,color:#fff
    style F fill:#51cf66,color:#fff
    style I fill:#339af0,color:#fff
Loading

Reviews (3): Last reviewed commit: "Address review: move forwarding policy i..." | Re-trigger Greptile

Comment on lines +33390 to +33396
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"pt-BR": {
"stringUnit": {

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.

P1 Japanese translation is a copy of the wrong error message

The Japanese value added for cli.forwarding.error.forwardingLoop is identical to cli.forwarding.error.execFailed's Japanese translation ("cmux はアプリバンドルからコマンドラインツールを開始できませんでした…"). That describes an exec failure ("could not start the command-line tool from the app bundle"), not a forwarding loop. A Japanese user who hits the loop condition — mispackaged bundle, guard leaked into the caller's environment — receives a message about a completely different error, with no mention of the forwarding-back-to-app root cause that distinguishes this code path from execFailed.

Rule Used: Flag production user-facing text that is not fully... (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: 2

🤖 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 `@Resources/Localizable.xcstrings`:
- Around line 33371-33374: Update the Japanese localized value in the affected
string entry so it explicitly states that CLI forwarding resolved back to the
cmux app itself, while retaining the existing bundled-CLI failure context and
remediation guidance. Keep the translation natural and consistent with the
English diagnostic.
- Around line 33322-33434: Limit this new localization key to the supported
locales by retaining only the en and ja entries under localizations. Remove the
entries for all other locales, including the unaudited English fallback values,
without changing the English or Japanese translations.
🪄 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 Plus

Run ID: fb5acfbb-4967-4cdd-80ed-bfa472a6e6e9

📥 Commits

Reviewing files that changed from the base of the PR and between 2c38c06 and 07f9fc1.

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

Comment thread Resources/Localizable.xcstrings Outdated
Comment on lines +33322 to +33434
"localizations": {
"ar": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"bs": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"da": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"it": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "cmux はアプリバンドルからコマンドラインツールを開始できませんでした。cmux を再インストールするか、通常の cmux CLI インストールからコマンドを実行してください。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"nb": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"pl": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"pt-BR": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"ru": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"th": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"uk": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
}
},
"zh-Hant": {
"stringUnit": {
"state": "translated",
"value": "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Limit this new key to supported locales.

This adds new entries for legacy locales even though cmux currently supports only English (en) and Japanese (ja). Keep this key limited to those locales instead of expanding coverage with unaudited English fallback values.

Based on learnings, only English and Japanese are supported app locales for new localization keys.

🤖 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 `@Resources/Localizable.xcstrings` around lines 33322 - 33434, Limit this new
localization key to the supported locales by retaining only the en and ja
entries under localizations. Remove the entries for all other locales, including
the unaudited English fallback values, without changing the English or Japanese
translations.

Source: Learnings

Comment thread Resources/Localizable.xcstrings Outdated
The full-internationalization check rejects copied-English values, so
cli.forwarding.error.forwardingLoop now carries real translations for
all 19 locales. Also documents the new decision function, the loop
error helper, and the new tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

ghost 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 `@Resources/Localizable.xcstrings`:
- Around line 33326-33344: Restrict the new localization entry to the supported
app locales, English (en) and Japanese (ja). In the affected entry and the
additionally referenced range, remove all legacy locale blocks while preserving
the key and its en/ja translations unchanged.
🪄 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 Plus

Run ID: 0dea1862-7200-41d8-8da4-d19c9e6c66d2

📥 Commits

Reviewing files that changed from the base of the PR and between 07f9fc1 and 30b10a2.

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

Comment thread Resources/Localizable.xcstrings Outdated
Comment on lines +33326 to +33344
"value": "تعذّر على cmux تمرير هذا الأمر إلى أداة سطر الأوامر المضمّنة لأن إعادة التوجيه عادت إلى التطبيق نفسه. أعد تثبيت cmux أو شغّل الأمر من تثبيت قياسي لواجهة cmux لسطر الأوامر."
}
},
"bs": {
"stringUnit": {
"state": "translated",
"value": "cmux nije mogao proslijediti ovu komandu svom ugrađenom alatu komandne linije jer je prosljeđivanje vratilo na samu aplikaciju. Ponovo instalirajte cmux ili pokrenite komandu iz standardne cmux CLI instalacije."
}
},
"da": {
"stringUnit": {
"state": "translated",
"value": "cmux kunne ikke videregive denne kommando til det medfølgende kommandolinjeværktøj, fordi videresendelsen pegede tilbage på selve appen. Geninstallér cmux, eller kør kommandoen fra en standard cmux CLI-installation."
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "cmux konnte diesen Befehl nicht an das mitgelieferte Kommandozeilenwerkzeug übergeben, weil die Weiterleitung zurück zur App selbst führte. Installieren Sie cmux neu oder führen Sie den Befehl aus einer standardmäßigen cmux-CLI-Installation aus."

ghost Jul 24, 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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Limit this new key to supported locales.

This new entry adds translations for legacy locales even though cmux currently supports only English (en) and Japanese (ja) for new localization keys. Retain only those supported locales to avoid expanding coverage with unaudited translations.

Based on learnings, only English and Japanese are supported app locales for new localization keys.

Also applies to: 33356-33434

🤖 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 `@Resources/Localizable.xcstrings` around lines 33326 - 33344, Restrict the new
localization entry to the supported app locales, English (en) and Japanese (ja).
In the affected entry and the additionally referenced range, remove all legacy
locale blocks while preserving the key and its en/ja translations unchanged.

Source: Learnings

The package-boundaries check wants pure launch-routing logic in the
CMUXAgentLaunch SwiftPM package, so the argv classification and the
forwarding decision now live there as CLIForwardingLaunchPolicy with
swift-testing coverage; the app-side router keeps only the guard read,
exec, stderr, and exit glue. The full-internationalization check also
flagged the missing km slot on the new key, so the Khmer translation
is added alongside the existing 19 locales.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

ghost 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 (1)
Sources/App/CLIForwardingLaunchRouter.swift (1)

151-159: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep forwarding-loop details out of the user-facing error.

Line 156 exposes internal routing mechanics (“forwarding resolved back to the app itself”). Replace it with product-level wording while retaining the reinstall/CLI-installation recovery guidance.

Proposed wording
-            defaultValue: "cmux could not hand this command to its bundled command-line tool because forwarding resolved back to the app itself. Reinstall cmux or run the command from a standard cmux CLI installation."
+            defaultValue: "cmux could not start this command-line request. Reinstall cmux or run the command from a standard cmux CLI installation."

As per coding guidelines, user-facing errors must state what happened in product terms and must not expose implementation details.
As per path instructions, production user-facing error copy must avoid internal routing details and provide safe recovery actions.

🤖 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 151 - 159, Update
localizedForwardingLoopError() to remove the internal routing explanation about
forwarding resolving to the app itself, replacing it with product-level wording
that explains the command could not be handled. Preserve the existing recovery
guidance to reinstall cmux or use a standard cmux CLI installation.

Sources: Coding guidelines, Path instructions

🤖 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/App/CLIForwardingLaunchRouter.swift`:
- Around line 151-159: Update localizedForwardingLoopError() to remove the
internal routing explanation about forwarding resolving to the app itself,
replacing it with product-level wording that explains the command could not be
handled. Preserve the existing recovery guidance to reinstall cmux or use a
standard cmux CLI installation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 84b05cba-813f-4f21-871d-63fd974f9254

📥 Commits

Reviewing files that changed from the base of the PR and between 30b10a2 and 2ff6c2b.

📒 Files selected for processing (4)
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/CLIForwardingLaunchPolicy.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/CLIForwardingLaunchPolicyTests.swift
  • Resources/Localizable.xcstrings
  • Sources/App/CLIForwardingLaunchRouter.swift

…licy

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

ghost commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@teamleaderleo

ghost commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Thank you for this, @kunsanglee! Failing closed instead of leaving a hidden app process behind on every hook call is a great fix. I merged main in and kept the new RC launch sentinel in your policy list (with a test), so it's up to date and CI is running. The one thing left is the CLA: just comment the line below and we'll land it :D

I have read the CLA Document v2.2 and I hereby sign the CLA

@kunsanglee
kunsanglee force-pushed the fix/cli-forwarding-loop-fail-closed branch from a976c4b to 8ff2fa0 Compare September 25, 2026 12:26
@kunsanglee

ghost commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document v2.2 and I hereby sign the CLA

@kunsanglee

ghost commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @teamleaderleo for merging main and adding the RC sentinel test! Heads-up: I rewrote my 3 commits to use my main GitHub account as author so the CLA check could pass, which changed your merge commit's SHA. Its contents are unchanged.

teamleaderleo and others added 4 commits September 25, 2026 15:55
The branch copy had reordered existing keys, producing a ~4,400-line diff
against main. Rebuild it from main and insert only the new
cli.forwarding.error.forwardingLoop entry (content unchanged).

Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The iOS/package conventions lint rejects a public caseless enum with only
static members. Move the classification onto the decision it produces:
`CLIForwardingDecision(arguments:forwardingGuardIsSet:)` plus
`CLIForwardingDecision.shouldForwardToBundledCLI(arguments:)`. No behavior
change.

Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit b436c92 into manaflow-ai:main Sep 25, 2026
@teamleaderleo

ghost commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Merged, thank you @kunsanglee! CLI forwarding now fails closed instead of leaving hidden app processes behind :D

@github-actions

ghost commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Merge receipt for 731cffd2a9: every check was green at merge (20 verified; 15 skipped by policy). Full suite runs on main after merge.

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.

2 participants