Repository navigation
Conversation
|
@guanbear is attempting to deploy a commit to the Manaflow Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughAdds ChangesOMO Slim integration
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant CLI
participant Launcher
participant OpenCode
CLI->>Launcher: dispatch omo-slim or omos
Launcher->>Launcher: configure cmux context and select port
Launcher->>OpenCode: execute with forwarded arguments
Suggested reviewers: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (3 errors, 1 warning)
✅ Passed checks (21 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryAdds first-class
Confidence Score: 5/5Safe to merge; the changes are well-scoped launcher additions with no mutations to the user's opencode or OMO Slim configuration. All correctness-critical paths — session resume, fork, trust checks, agent detection — are updated consistently via the new
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant U as User
participant CLI as cmux CLI (Swift)
participant RD as cmuxd-remote (Go)
participant OCS as OpenCode + OMO Slim 2.2+
participant CM as cmux daemon
U->>CLI: cmux omo-slim [args]
CLI->>CLI: resolveOpenCodeExecutable()
CLI->>CM: tmuxCompatFocusedContext() if WORKSPACE/SURFACE absent
CM-->>CLI: workspaceId, surfaceId
CLI->>CLI: omoResolvedPort() pick free port
CLI->>CLI: exportAgentLaunchCommandEnvironment()
CLI->>OCS: execv(opencode, [--port P, ...args])
OCS->>CM: connect via CMUX_SOCKET_PATH
OCS->>CM: create native agent panes
CM-->>OCS: pane handles
Note over U,CM: Remote path (cmuxd-remote)
U->>RD: cmuxd-remote omo-slim [args]
RD->>CM: getFocusedContext() via RPC
CM-->>RD: workspaceId, surfaceId
RD->>RD: openCodeNativeEffectivePort() free port
RD->>OCS: syscall.Exec(opencode, [--port P, ...args])
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant U as User
participant CLI as cmux CLI (Swift)
participant RD as cmuxd-remote (Go)
participant OCS as OpenCode + OMO Slim 2.2+
participant CM as cmux daemon
U->>CLI: cmux omo-slim [args]
CLI->>CLI: resolveOpenCodeExecutable()
CLI->>CM: tmuxCompatFocusedContext() if WORKSPACE/SURFACE absent
CM-->>CLI: workspaceId, surfaceId
CLI->>CLI: omoResolvedPort() pick free port
CLI->>CLI: exportAgentLaunchCommandEnvironment()
CLI->>OCS: execv(opencode, [--port P, ...args])
OCS->>CM: connect via CMUX_SOCKET_PATH
OCS->>CM: create native agent panes
CM-->>OCS: pane handles
Note over U,CM: Remote path (cmuxd-remote)
U->>RD: cmuxd-remote omo-slim [args]
RD->>CM: getFocusedContext() via RPC
CM-->>RD: workspaceId, surfaceId
RD->>RD: openCodeNativeEffectivePort() free port
RD->>OCS: syscall.Exec(opencode, [--port P, ...args])
Reviews (2): Last reviewed commit: "Satisfy OMO Slim launcher review checks" | Re-trigger Greptile |
| public static func launcherIsOpenCodeSessionWrapper(_ launcher: String?) -> Bool { | ||
| guard let launcher = launcher?.trimmingCharacters(in: .whitespacesAndNewlines), | ||
| !launcher.isEmpty else { return false } | ||
| return ["omo", "omo-slim", "omos"].contains(launcher.lowercased()) | ||
| } |
There was a problem hiding this comment.
Two independent lists for the same session-wrapper subset
launcherIsOpenCodeSessionWrapper hardcodes ["omo", "omo-slim", "omos"] inline, independently of wrapperLaunchersByKind["opencode"] (which already contains exactly this subset plus "omx" and "omc"). When the next session-aware launcher is added, both the dict and the inline literal must be updated by hand — if one is missed, callers in ContentView, AgentForkSupport, and CMUXCLI+SessionsListForkDiagnostics that rely on this function will silently disagree with the trust-table. Deriving the answer from wrapperLaunchersByKind (e.g. by filtering out "omx" and "omc") would give one authoritative source.
Rule Used: Flag correctness-critical detection/identity deriv... (source)
| case "omo", "omo-slim", "omos": | ||
| let launcherName = launcher ?? "omo" | ||
| let parts = commandParts(executablePath: executablePath, arguments: arguments, fallbackExecutable: "cmux") | ||
| var tail = parts.tail | ||
| if tail.first == "omo" { tail.removeFirst() } | ||
| if tail.first == launcherName { tail.removeFirst() } | ||
| guard let preserved = AgentLaunchSanitizer.preservedArguments(kind: "opencode", args: tail) else { | ||
| return .resolved(nil) | ||
| } | ||
| return .resolved([parts.executable, "omo", "--session", sessionId, "--fork"] + preserved) | ||
| return .resolved([parts.executable, launcherName, "--session", sessionId, "--fork"] + preserved) |
There was a problem hiding this comment.
The
?? "omo" fallback is unreachable: Swift only enters this case branch when launcher is one of the three non-nil matched strings, so launcher is always non-optional here. The dead fallback is misleading — a future reader may assume nil can arrive here, and if the switch is ever refactored incorrectly a silent "omo" would be used instead of the real launcher name. The same pattern is repeated in AgentResumeArgv.swift and AgentLaunchSanitizer.swift.
| case "omo", "omo-slim", "omos": | |
| let launcherName = launcher ?? "omo" | |
| let parts = commandParts(executablePath: executablePath, arguments: arguments, fallbackExecutable: "cmux") | |
| var tail = parts.tail | |
| if tail.first == "omo" { tail.removeFirst() } | |
| if tail.first == launcherName { tail.removeFirst() } | |
| guard let preserved = AgentLaunchSanitizer.preservedArguments(kind: "opencode", args: tail) else { | |
| return .resolved(nil) | |
| } | |
| return .resolved([parts.executable, "omo", "--session", sessionId, "--fork"] + preserved) | |
| return .resolved([parts.executable, launcherName, "--session", sessionId, "--fork"] + preserved) | |
| case "omo", "omo-slim", "omos": | |
| let launcherName = launcher! // non-nil: matched by this case | |
| let parts = commandParts(executablePath: executablePath, arguments: arguments, fallbackExecutable: "cmux") | |
| var tail = parts.tail | |
| if tail.first == launcherName { tail.removeFirst() } | |
| guard let preserved = AgentLaunchSanitizer.preservedArguments(kind: "opencode", args: tail) else { | |
| return .resolved(nil) | |
| } | |
| return .resolved([parts.executable, launcherName, "--session", sessionId, "--fork"] + preserved) |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift (1)
51-53: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick winFix the invalid nil-coalescing in
AgentLaunchSanitizer
launcheris declared as a non-optionalString, solauncher ?? "omo"does not compile. Uselet launcherName = launcherhere, or make the parameter optional if that fallback is actually needed.🤖 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 `@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift` around lines 51 - 53, Update the launcher-name initialization in AgentLaunchSanitizer to stop applying nil-coalescing to the non-optional launcher parameter; assign launcher directly to launcherName, unless the surrounding API requires an optional parameter and fallback behavior.
🤖 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 `@CLI/cmux.swift`:
- Around line 15425-15443: Add `cli.omoSlim.usage` locale entries in
`Resources/Localizable.xcstrings` for ar, bs, da, de, es, fr, it, km, nb, pl,
pt-BR, ru, th, tr, and zh-Hant, matching the existing `omo-slim`/`omos` usage
text and localization format used by other CLI keys.
In `@Sources/RestorableAgentSession.swift`:
- Around line 440-441: Replace the raw launcher-value switch in the relevant
session-detection logic with the shared launcherIsOpenCodeSessionWrapper(_:)
matcher, preserving the nil suppression behavior for wrapper aliases while
gaining its trimming and case-insensitive handling.
---
Outside diff comments:
In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift`:
- Around line 51-53: Update the launcher-name initialization in
AgentLaunchSanitizer to stop applying nil-coalescing to the non-optional
launcher parameter; assign launcher directly to launcherName, unless the
surrounding API requires an optional parameter and fallback behavior.
🪄 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: 79c4e6a7-40e3-46bf-8443-4eb164225e41
📒 Files selected for processing (19)
CLI/CMUXCLI+CommandSuggestions.swiftCLI/CMUXCLI+SessionsListForkDiagnostics.swiftCLI/cmux.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentForkArgv.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentForkArgvTests.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchCaptureTrustTests.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swiftResources/Localizable.xcstringsSources/AgentForkSupport.swiftSources/CmuxTaskManagerCodingAgentDefinition+BuiltIns.swiftSources/ContentView.swiftSources/RestorableAgentSession.swiftSources/TextBoxAgentDetection.swiftdaemon/remote/cmd/cmuxd-remote/agent_launch.godaemon/remote/cmd/cmuxd-remote/agent_launch_test.godaemon/remote/cmd/cmuxd-remote/cli.go
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swift`:
- Around line 61-65: Normalize the launcher once by trimming whitespace/newlines
and lowercasing it, then reuse that canonical token across
AgentLaunchCaptureTrust.launcherDescribesKind(_:kind:),
AgentLaunchSanitizer.sanitizedLaunchArguments(_:launcher:fallbackKind:),
AgentForkArgv.launcherResolution(...), and
AgentResumeArgv.launcherResolution(...). Apply the corresponding changes in
AgentLaunchSanitizer.swift lines 71-77, AgentForkArgv.swift lines 43-51, and
AgentResumeArgv.swift lines 283-291; the trust check in
AgentLaunchCaptureTrust.swift lines 61-65 already performs normalization and
should remain consistent.
🪄 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: 9f2b1d1e-f70e-47a6-9e02-af5c2f8f74a6
📒 Files selected for processing (8)
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentForkArgv.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchCaptureTrustTests.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swiftResources/Localizable.xcstringsSources/RestorableAgentSession.swift
Add regression coverage for both public launcher spellings before wiring the native Slim path.\n\nConstraint: SwiftPM manifest linking is broken in the installed CommandLineTools, so local execution cannot reach the expected compile failure.\nConfidence: high\nScope-risk: narrow\nTested: swift test attempted; blocked by PackageDescription linker failure\nNot-tested: Test assertions cannot execute until the local Swift toolchain is repaired
OMO Slim 2.2.x now manages cmux panes directly, so expose lightweight omo-slim and omos launchers that provide cmux context without synthesizing tmux state or shadowing the user's OpenCode configuration. Constraint: OMO Slim 2.2+ owns child-pane creation and lifecycle through its native cmux adapter Rejected: Reuse the existing OMO tmux shim | duplicates Slim's native integration and risks configuration drift Confidence: high Scope-risk: moderate Tested: Go remote launcher tests, Swift syntax parsing, localization JSON validation, diff whitespace checks Not-tested: Full Swift package and tagged app build unavailable because the installed Command Line Tools SDK does not match its compiler and full Xcode is absent
Complete the new CLI usage key across the catalog and keep session-wrapper handling consistent with the launcher trust contract, so the native OMO Slim path compiles cleanly and does not probe wrapper sessions as plain OpenCode processes. Constraint: The catalog requires every new user-facing key to cover all supported locales Rejected: Treat OMO Slim wrapper aliases as a separate raw switch | loses the shared matcher normalization and duplicates alias ownership Confidence: high Scope-risk: narrow Tested: Localization coverage equality check, Swift syntax parsing, Go remote launcher tests, diff whitespace checks Not-tested: SwiftPM tests cannot start because the local CommandLineTools PackageDescription linker is incompatible
- Rebase native OMO Slim launchers onto current main - Use agentLaunchContextForInvocation instead of removed getFocusedContext - Keep nativeProcessAliasesByKind aligned with openCodeSessionWrapperLaunchers
Refresh: rebased onto current
|
50b66ef to
bf20bef
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bf20bef. Configure here.
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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 `@CLI/cmux.swift`:
- Around line 23123-23134: Update the focused-context initialization around
tmuxCompatFocusedContext so each environment variable is filled only when its
corresponding launcherEnvironment value is missing. Preserve existing
CMUX_WORKSPACE_ID and CMUX_SURFACE_ID values, and likewise gate each matching
setenv call independently while still applying focusedContext values for missing
entries.
- Around line 23145-23148: Update the effective argument construction around
omoRequestedPort so the default --port option is placed after the opencode run
subcommand, producing opencode run --port <n> before the remaining commandArgs;
preserve existing behavior when a port was explicitly requested.
In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go`:
- Around line 171-178: Clear CMUX_WORKSPACE_ID and CMUX_SURFACE_ID before the
launchContext check in the environment setup block. Then apply non-empty values
from launchContext as currently done, ensuring nil or empty context cannot
inherit stale identity values.
- Around line 216-221: Update openCodeNativeEffectivePort so it does not close
and release the selected listener before OpenCode binds the port. Replace the
current ephemeral-port probe with an OpenCode-supported discovery handshake or
pass the live listener reservation to the process that performs the OpenCode
bind, preserving correct port reporting for concurrent launches. Add regression
coverage that exercises concurrent launches and verifies they do not select the
same released port.
- Around line 187-189: Update the syscall.Exec error handling in the agent
launch flow to replace the raw err formatting in the user-facing fmt.Fprintf
message with a stable, action-oriented failure message. Preserve the command
context, and route the raw error only through the project’s existing redacted
internal diagnostics mechanism.
In `@Sources/AgentForkSupport.swift`:
- Around line 137-139: Replace the literal "omo" launcher comparisons in
requiresForkValidationExecutableIdentity and
forkValidationExecutableResolutionPlan with
AgentLaunchCaptureTrust.launcherIsOpenCodeSessionWrapper, matching supportsFork
so all wrapper aliases use the same fork-validation behavior.
🪄 Autofix
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: 0e32feaf-4e8b-4fbf-af45-2922dbdf583a
📒 Files selected for processing (20)
CLI/CMUXCLI+CommandSuggestions.swiftCLI/CMUXCLI+SessionsListForkDiagnostics.swiftCLI/cmux.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentForkArgv.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchCaptureTrust.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swiftPackages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentForkArgvTests.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchCaptureTrustTests.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swiftPackages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swiftResources/Localizable.xcstringsSources/AgentForkSupport.swiftSources/CmuxTaskManagerCodingAgentDefinition+BuiltIns.swiftSources/ContentView.swiftSources/RestorableAgentSession.swiftSources/TextBoxAgentDetection.swiftdaemon/remote/cmd/cmuxd-remote/agent_launch.godaemon/remote/cmd/cmuxd-remote/agent_launch_test.godaemon/remote/cmd/cmuxd-remote/cli.go
| if launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil, | ||
| let focusedContext = try tmuxCompatFocusedContext( | ||
| processEnvironment: launcherEnvironment, | ||
| explicitPassword: explicitPassword | ||
| ) { | ||
| launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId | ||
| setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1) | ||
| if let surfaceId = focusedContext.surfaceId { | ||
| launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId | ||
| setenv("CMUX_SURFACE_ID", surfaceId, 1) | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fix the combined-OR guard that lets a valid CMUX_WORKSPACE_ID get overwritten.
The condition at line 23123 uses OR: launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil. If CMUX_SURFACE_ID is missing but CMUX_WORKSPACE_ID is already set to the correct terminal's workspace, this condition still evaluates true. When tmuxCompatFocusedContext then resolves, line 23128 unconditionally overwrites launcherEnvironment["CMUX_WORKSPACE_ID"] with focusedContext.workspaceId, regardless of whether the existing value was already correct. focusedContext represents whatever window/surface is currently focused in the app, which is not guaranteed to match the pane that invoked cmux omo-slim. This can route the OMO Slim launch to the wrong workspace.
Gate each assignment on its own missing-ness instead of the combined condition.
🐛 Proposed fix to scope each overwrite to its own missing value
- if launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil,
- let focusedContext = try tmuxCompatFocusedContext(
- processEnvironment: launcherEnvironment,
- explicitPassword: explicitPassword
- ) {
- launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId
- setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1)
- if let surfaceId = focusedContext.surfaceId {
- launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId
- setenv("CMUX_SURFACE_ID", surfaceId, 1)
- }
- }
+ let missingWorkspaceId = launcherEnvironment["CMUX_WORKSPACE_ID"] == nil
+ let missingSurfaceId = launcherEnvironment["CMUX_SURFACE_ID"] == nil
+ if missingWorkspaceId || missingSurfaceId,
+ let focusedContext = try tmuxCompatFocusedContext(
+ processEnvironment: launcherEnvironment,
+ explicitPassword: explicitPassword
+ ) {
+ if missingWorkspaceId {
+ launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId
+ setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1)
+ }
+ if missingSurfaceId, let surfaceId = focusedContext.surfaceId {
+ launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId
+ setenv("CMUX_SURFACE_ID", surfaceId, 1)
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if launcherEnvironment["CMUX_WORKSPACE_ID"] == nil || launcherEnvironment["CMUX_SURFACE_ID"] == nil, | |
| let focusedContext = try tmuxCompatFocusedContext( | |
| processEnvironment: launcherEnvironment, | |
| explicitPassword: explicitPassword | |
| ) { | |
| launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId | |
| setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1) | |
| if let surfaceId = focusedContext.surfaceId { | |
| launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId | |
| setenv("CMUX_SURFACE_ID", surfaceId, 1) | |
| } | |
| } | |
| let missingWorkspaceId = launcherEnvironment["CMUX_WORKSPACE_ID"] == nil | |
| let missingSurfaceId = launcherEnvironment["CMUX_SURFACE_ID"] == nil | |
| if missingWorkspaceId || missingSurfaceId, | |
| let focusedContext = try tmuxCompatFocusedContext( | |
| processEnvironment: launcherEnvironment, | |
| explicitPassword: explicitPassword | |
| ) { | |
| if missingWorkspaceId { | |
| launcherEnvironment["CMUX_WORKSPACE_ID"] = focusedContext.workspaceId | |
| setenv("CMUX_WORKSPACE_ID", focusedContext.workspaceId, 1) | |
| } | |
| if missingSurfaceId, let surfaceId = focusedContext.surfaceId { | |
| launcherEnvironment["CMUX_SURFACE_ID"] = surfaceId | |
| setenv("CMUX_SURFACE_ID", surfaceId, 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 `@CLI/cmux.swift` around lines 23123 - 23134, Update the focused-context
initialization around tmuxCompatFocusedContext so each environment variable is
filled only when its corresponding launcherEnvironment value is missing.
Preserve existing CMUX_WORKSPACE_ID and CMUX_SURFACE_ID values, and likewise
gate each matching setenv call independently while still applying focusedContext
values for missing entries.
| var effectiveArgs = commandArgs | ||
| if omoRequestedPort(from: commandArgs) == nil { | ||
| effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: 0) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
opencode CLI global flags before or after subcommand
💡 Result:
For the OpenCode CLI, global flags must be placed before any subcommand [1]. When using the OpenCode CLI, you should provide global flags (such as --debug, --cwd, --version, or --help) directly after the root command, preceding any specific command or subcommand [1][2]. For example: opencode --debug [subcommand] [arguments] opencode -c /path/to/project [subcommand] [arguments] The CLI follows standard command-line conventions where global flags are parsed at the root level [1][2]. Placing them after a subcommand may result in the CLI incorrectly identifying the flags as arguments belonging to that specific subcommand, or the flags may simply be ignored [1][3]. Always prioritize placing them before the subcommand to ensure they are correctly interpreted as global configuration settings [1][2].
Citations:
- 1: https://mintlify.wiki/opencode-ai/opencode/reference/commands
- 2: https://mintlify.wiki/opencode-ai/opencode/reference/flags
- 3: Can we use Commands *and* (global) Flags? What about a 'default' command? urfave/cli#1974
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate and inspect the referenced code and the matching runOMO logic.
wc -l CLI/cmux.swift
sed -n '23120,23170p' CLI/cmux.swift
printf '\n--- runOMO occurrences ---\n'
rg -n "func runOMO|omoRequestedPort|int \\(\"--port\"|append contentsOf: \\(\"--port\"" CLI/cmux.swift
printf '\n--- relevant omo request/port handling ---\n'
sed -n '22700,23100p' CLI/cmux.swiftRepository: manaflow-ai/cmux
Length of output: 1918
🌐 Web query:
site:github.com OpenCode OpenCode CLI global flags before subcommand --port
💡 Result:
In the OpenCode CLI, the --port flag is not a global flag; it is a command-specific option [1][2][3]. Because it is specific to commands such as run or serve, it must be placed after the subcommand, not before it [4][5]. Global flags in the OpenCode CLI are limited to options that apply to every command, such as --help, --version, --print-logs, --log-level, and --pure [1][6][4]. Since --port is associated with the configuration of the underlying server or local listener for specific operations, it is defined within the builder for those subcommands (e.g., in the run or serve command definitions) rather than at the root level [7][5][8]. Therefore, you should use the structure: opencode --port For example: opencode run --port 4096 opencode serve --port 4096
Citations:
- 1: https://github.com/anomalyco/opencode/blob/dev/packages/web/src/content/docs/cli.mdx
- 2: https://github.com/sst/opencode/blob/9ad6588f/packages/web/src/content/docs/cli.mdx
- 3: https://github.com/anomalyco/opencode/blob/7daea69e/packages/web/src/content/docs/cli.mdx
- 4: https://gist.github.com/n-at-han-k/e36a7754f1eb73182e953efa5ac8010e
- 5: https://github.com/sst/opencode/blob/9ad6588f/packages/web/src/content/docs/server.mdx
- 6: https://github.com/mseep-ai/OpenCode-Everything-You-Need-to-Know/blob/main/docs/reference/cli.md
- 7: https://github.com/anomalyco/opencode/blob/HEAD/packages/opencode/src/cli/cmd/run.ts
- 8: https://github.com/anomalyco/opencode/blob/721ff512/packages/opencode/src/cli/cmd/run.ts
Move --port into the opencode subcommand.
opencode defines --port as a command-level option, so this becomes cmux omo-slim run "prompt" → opencode --port <n> run "prompt" and --port can be parsed as an unexpected argument instead of a run command option. Build the call as opencode run --port <n> "prompt" before inserting the rest of commandArgs.
🤖 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 `@CLI/cmux.swift` around lines 23145 - 23148, Update the effective argument
construction around omoRequestedPort so the default --port option is placed
after the opencode run subcommand, producing opencode run --port <n> before the
remaining commandArgs; preserve existing behavior when a port was explicitly
requested.
| listener, err := net.Listen("tcp", "127.0.0.1:0") | ||
| if err != nil { | ||
| return "4097" | ||
| } | ||
| defer listener.Close() | ||
| return strconv.Itoa(listener.Addr().(*net.TCPAddr).Port) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Do not release the selected port before OpenCode binds it.
openCodeNativeEffectivePort closes the listener when it returns. Another process can bind that port before syscall.Exec starts OpenCode. Concurrent launches can then fail intermittently.
Use an OpenCode-supported port discovery handshake, or make the process that binds OpenCode own the reservation. Add concurrent-launch regression coverage.
🧰 Tools
🪛 golangci-lint (2.12.2)
[error] 220-220: Error return value of listener.Close is not checked
(errcheck)
[error] 221-221: type assertion must be checked
(forcetypeassert)
[error] 216-216: net.Listen must not be called. use (*net.ListenConfig).Listen
(noctx)
🤖 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 `@daemon/remote/cmd/cmuxd-remote/agent_launch.go` around lines 216 - 221,
Update openCodeNativeEffectivePort so it does not close and release the selected
listener before OpenCode binds the port. Replace the current ephemeral-port
probe with an OpenCode-supported discovery handshake or pass the live listener
reservation to the process that performs the OpenCode bind, preserving correct
port reporting for concurrent launches. Add regression coverage that exercises
concurrent launches and verifies they do not select the same released port.
runOMOSlim still called tmuxCompatFocusedContext after the inherited-identity redesign removed it. Native OMO Slim now relies only on the caller's CMUX_WORKSPACE_ID / CMUX_SURFACE_ID, matching tmuxCompatLaunchContext fail-closed behavior. Also: - treat omo-slim/omos like omo in fork validation executable probes - clear ambient CMUX identity before applying remote launch context - avoid printing raw syscall.Exec errors from the remote launcher
Review follow-upHead refreshes with:
Not changed in this push:
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
CLI/cmux.swift (1)
23096-23158: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFail closed before launching
omo-slimwithout an inherited cmux surface.
runOMOSlimonly readsCMUX_WORKSPACE_ID/CMUX_SURFACE_IDfromProcessInfo.processInfo.environment, so it canexecvopencodeoutside a cmux terminal. CalltmuxCompatLaunchContextand throwmanagedTerminalRequiredMessage(displayName: "cmux \(launcher)")whennormalizedTmuxTarget(launchContext?.surfaceId)is absent, mirroringrunOMO,runOMX, andrunOMC.🤖 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 `@CLI/cmux.swift` around lines 23096 - 23158, Update runOMOSlim to obtain the inherited context via tmuxCompatLaunchContext and validate normalizedTmuxTarget(launchContext?.surfaceId) before resolving or launching OpenCode. If no inherited surface is available, throw managedTerminalRequiredMessage(displayName: "cmux \(launcher)"), matching the fail-closed behavior in runOMO, runOMX, and runOMC.Source: Path instructions
♻️ Duplicate comments (3)
CLI/cmux.swift (1)
23127-23139: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFix the
--portplacement so it does not break opencode subcommand invocations.
effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: 0)always inserts--port <n>at index 0, before any positional subcommand. Forcmux omo-slim run "prompt", this producescommandArgs = ["run", "prompt"]andeffectiveArgs = ["--port", "<port>", "run", "prompt"], which execs asopencode --port <port> run "prompt".A previous review on this same function already flagged this exact pattern and verified through web search that opencode's
--portflag is a per-subcommand option (for examplerunorserve), not a global flag, so it must come after the subcommand:opencode run --port <n> "prompt". Placing--portbefore the subcommand risks opencode treating it as an unexpected positional argument. That past comment has no "Addressed" marker, and the code still exhibits the same behavior.🐛 Proposed fix to place `--port` after any leading subcommand
var effectiveArgs = commandArgs if omoRequestedPort(from: commandArgs) == nil { - effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: 0) + let insertionIndex = effectiveArgs.first?.hasPrefix("-") == false ? 1 : 0 + effectiveArgs.insert(contentsOf: ["--port", openCodePort], at: insertionIndex) }Since this depends on opencode's actual CLI flag parsing rules, please confirm the exact accepted syntax for the installed opencode version before merging the fix.
opencode CLI --port flag global or subcommand🤖 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 `@CLI/cmux.swift` around lines 23127 - 23139, Update the effectiveArgs construction in the omo launcher flow so the generated --port value is inserted after the leading opencode subcommand rather than always at index 0. Preserve existing arguments and support invocations such as run or serve, while confirming the installed opencode version’s accepted option syntax before finalizing the change.daemon/remote/cmd/cmuxd-remote/agent_launch.go (2)
206-226:⚠️ Potential issue | 🟠 MajorKeep the selected port reserved until OpenCode binds it.
The effective-port helper releases the ephemeral listener before
syscall.Execstarts OpenCode. Another process can claim the port during this gap, so concurrent launches can fail intermittently. Use an OpenCode-supported discovery handshake or preserve the reservation through the bind. Add concurrent-launch regression coverage.The previous review already identified this unresolved port-reservation race, and the supplied change details show that it remains unchanged.
🤖 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 `@daemon/remote/cmd/cmuxd-remote/agent_launch.go` around lines 206 - 226, Update openCodeNativeEffectivePort so an automatically selected ephemeral port remains reserved until OpenCode successfully binds it, using an OpenCode-supported discovery handshake or equivalent reservation-preserving flow instead of closing the listener before syscall.Exec. Keep explicit --port and OPENCODE_PORT behavior unchanged, and add regression coverage that exercises concurrent launches.
173-176:⚠️ Potential issue | 🟠 MajorFail closed when clearing inherited identity fails.
Lines 175-176 ignore the errors from
os.Unsetenv. If either call fails, staleCMUX_WORKSPACE_IDorCMUX_SURFACE_IDcan reach the exec'd process. Check both results and abort beforesyscall.Execon failure. Keep the user-facing message stable.As per coding guidelines, correctness-critical launch identity must fail closed instead of continuing with ambient state.
🤖 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 `@daemon/remote/cmd/cmuxd-remote/agent_launch.go` around lines 173 - 176, Update the environment-clearing logic in the launch flow around os.Unsetenv so both CMUX_WORKSPACE_ID and CMUX_SURFACE_ID errors are checked. If either unset operation fails, abort before syscall.Exec using the existing stable user-facing error message, ensuring stale inherited identity cannot reach the exec'd process.Sources: Coding guidelines, Linters/SAST tools
🤖 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 `@CLI/cmux.swift`:
- Around line 23096-23158: Update runOMOSlim to obtain the inherited context via
tmuxCompatLaunchContext and validate
normalizedTmuxTarget(launchContext?.surfaceId) before resolving or launching
OpenCode. If no inherited surface is available, throw
managedTerminalRequiredMessage(displayName: "cmux \(launcher)"), matching the
fail-closed behavior in runOMO, runOMX, and runOMC.
---
Duplicate comments:
In `@CLI/cmux.swift`:
- Around line 23127-23139: Update the effectiveArgs construction in the omo
launcher flow so the generated --port value is inserted after the leading
opencode subcommand rather than always at index 0. Preserve existing arguments
and support invocations such as run or serve, while confirming the installed
opencode version’s accepted option syntax before finalizing the change.
In `@daemon/remote/cmd/cmuxd-remote/agent_launch.go`:
- Around line 206-226: Update openCodeNativeEffectivePort so an automatically
selected ephemeral port remains reserved until OpenCode successfully binds it,
using an OpenCode-supported discovery handshake or equivalent
reservation-preserving flow instead of closing the listener before syscall.Exec.
Keep explicit --port and OPENCODE_PORT behavior unchanged, and add regression
coverage that exercises concurrent launches.
- Around line 173-176: Update the environment-clearing logic in the launch flow
around os.Unsetenv so both CMUX_WORKSPACE_ID and CMUX_SURFACE_ID errors are
checked. If either unset operation fails, abort before syscall.Exec using the
existing stable user-facing error message, ensuring stale inherited identity
cannot reach the exec'd process.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: c6a12d06-78e2-488d-93be-5cd862de755b
📒 Files selected for processing (3)
CLI/cmux.swiftSources/AgentForkSupport.swiftdaemon/remote/cmd/cmuxd-remote/agent_launch.go
|
Closing this PR for now. There has not been maintainer merge traction, so I’m withdrawing it to reduce noise rather than keep the branch open indefinitely. Thanks for the automated review feedback. Happy to revisit with a fresher PR if native OMO Slim launchers are still wanted. |

Background
PR #7712 introduced OMO Slim support through the same tmux shim and shadow-config path used by the existing
cmux omolauncher.Since then, OMO Slim 2.2.x has added native cmux multiplexer support. It detects the cmux socket/workspace/surface context and owns child-pane creation and lifecycle itself. Keeping a second tmux compatibility layer in cmux would duplicate that behavior, override user configuration, and make the integration more fragile.
This PR supersedes #7712 with a smaller first-class launcher integration.
What changed
cmux omo-slimand the shortercmux omosalias locally and throughcmuxd-remote.CMUX_SOCKET_PATH, focused workspace/surface IDs, an available OpenCode API port, and the background-subagent feature flag.Non-goals
Validation
go test ./cmd/cmuxd-remoteswiftc -parsefor all touched Swift sourcesjq empty Resources/Localizable.xcstringsgit diff --check upstream/main...HEADThe full Swift package test and tagged app build could not run on this machine because only Command Line Tools are installed, its Swift compiler/SDK versions are mismatched, and full Xcode is unavailable.
Closes and supersedes #7712.
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Adds native OMO Slim launchers to
cmuxso OMO Slim 2.2+ owns cmux panes directly, replacing the tmux shim and preserving useropencode/OMO Slim config. Remote relay now clears ambient cmux identity and relies on inherited workspace/surface; wrapper sessions are handled uniformly to avoid plainopencodeprobes.New Features
cmux omo-slimand aliascmux omosincmuxandcmuxd-remote.--port(otherwise picks a freeOPENCODE_PORT); enables background subagents; all args pass through toopencode.Bug Fixes
CMUX_WORKSPACE_ID/CMUX_SURFACE_ID.CMUX_WORKSPACE_ID/CMUX_SURFACE_IDbefore applying the resolved context.omo-slim/omoslikeomoin fork/resume and version probes; wrapper sessions aren’t probed as plainopencode.syscall.Execerrors in the remote path; added tests for explicit and auto--porthandling.Written for commit 45aba72. Summary will update on new commits.
Summary by CodeRabbit
omo-slimcommand andomosalias for launching OpenCode through cmux.Note
Medium Risk
Introduces a new agent launch and remote relay path with port and workspace identity wiring; session fork/resume behavior changes for wrapper launchers but follows existing
omopatterns and adds test coverage.Overview
Adds
cmux omo-slimand theomosalias as a first-class launch path for OpenCode with oh-my-opencode-slim 2.2+, using OMO Slim’s native cmux multiplexer instead of the legacyomotmux shim and shadow-config flow.The new launcher (local
runOMOSlimand remoterunOMOSlimRelay) sets socket/workspace/surface context, picks or honors an OpenCode API port, enables background subagents, and execsopencodewithout installing plugins or mutating user config.omo,omo-slim, andomosare treated uniformly as OpenCode session wrappers across launch capture trust, fork/resume argv replay, sanitization, agent detection, fork diagnostics, and session-list availability—wrapper sessions skip plainopencodeversion probing where appropriate. CLI suggestions, built-in agent metadata, and localized usage text cover the new commands.Reviewed by Cursor Bugbot for commit 45aba72. Bugbot is set up for automated code reviews on this repo. Configure here.