Skip to content

Fix SSH LocalCommand incompatibility with Fish shell (#2706) - #3506

Merged
austinywang merged 8 commits into
mainfrom
fix-2706-ssh-fish-shell
May 5, 2026
Merged

austinywang merged 8 commits into
mainfrom
fix-2706-ssh-fish-shell

Conversation

@austinywang

@austinywang austinywang commented May 4, 2026 •

Copy link
Copy Markdown
Contributor

Builds on community PR #3451 by @zicochaos. Extracts new fish shell SSH support to separate files to satisfy the file-length budget CI check. Closes #2706.


Note

Medium Risk
Changes SSH command generation/escaping for both LocalCommand and RemoteCommand, which can affect all SSH connection flows and bootstrap behavior. Risk is mitigated by adding a dedicated end-to-end fish-shell regression test and keeping changes localized to command construction.

Overview
Fixes OpenSSH LocalCommand/RemoteCommand incompatibility with fish and other non-POSIX login shells by centralizing command construction and always wrapping snippets with /bin/sh -c plus OpenSSH percent escaping.

Refactors SSH helpers in cmux.swift into a new CMUXCLI+SSHCommandSupport.swift (shared posixShellCommand, % escaping, and local script combining), updates SSH argument builders to use these helpers, and hardens the SSH timing local-command to only read the debug-log path if the file exists.

Moves and strengthens the bootstrap SSH command test into a new WorkspaceSSHFishShellTests suite (including fake-ssh handling of %% and fish syntax validation), and updates the Xcode project to include the new source and test files.

Reviewed by Cursor Bugbot for commit c21eee3. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes SSH LocalCommand/RemoteCommand for fish and other non-POSIX shells by centralizing POSIX /bin/sh -c wrapping and OpenSSH percent-escaping, and hardens the fish-shell regression suite. Closes #2706.

  • Bug Fixes

    • Always wrap SSH LocalCommand and RemoteCommand with /bin/sh -c ... and percent-escape % via shared helpers.
    • SSH timing debug-log init now starts empty and reads the path only if the file exists.
  • Refactors

    • Centralized OpenSSH command construction in CMUXCLI+SSHCommandSupport.swift (adds posixShellCommand, exposes shellQuote) and removed ad-hoc escaping/combining.
    • Moved and strengthened tests in WorkspaceSSHFishShellTests (short Unix socket paths; find remote config RPC by method; fake SSH harness collapses OpenSSH percent escapes before running LocalCommand); removed the old bootstrap test from WorkspaceRemoteConnectionTests.

Written for commit c21eee3. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added notification keys for terminal selection background and foreground colors.
  • Tests

    • Added end-to-end tests validating SSH bootstrap command generation across shells (including fish).
    • Improved test utilities for notification payload handling.
  • Refactoring

    • Improved SSH startup/bootstrap command assembly, quoting/escaping, and local-command handling to make SSH workflows more robust.

zicochaos and others added 2 commits May 3, 2026 19:05
Keep the fish-shell SSH invariant in the existing CLI command builder while moving the wrapper helpers and regression coverage out of files that exceeded CI's line-count budget.

Constraint: Do not raise .github/swift-file-length-budget.tsv

Constraint: Preserve POSIX /bin/sh wrapping for OpenSSH LocalCommand and RemoteCommand so fish login shells parse the command line

Rejected: Bump file-length budget | CI failure explicitly requires extraction instead

Confidence: high

Scope-risk: narrow

Tested: python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv

Tested: swiftc -typecheck CLI/cmux.swift CLI/SocketOperationTelemetry.swift CLI/cmux_open.swift CLI/CMUXCLI+MoveTabToNewWorkspace.swift CLI/CMUXCLI+DocsSettings.swift CLI/CMUXCLI+ThemeSupport.swift CLI/CMUXCLI+Themes.swift CLI/CMUXCLI+TopRendering.swift CLI/CMUXFishShellSupport.swift Sources/RemoteRelayZshBootstrap.swift

Not-tested: Local XCTest run, per repository testing policy
@vercel

vercel Bot commented May 4, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 5, 2026 1:37am
cmux-staging Building Building Preview, Comment May 5, 2026 1:37am

@coderabbitai

coderabbitai Bot commented May 4, 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
📝 Walkthrough

Walkthrough

This PR refactors SSH command construction in the CLI by extracting command-building helpers into a new extension, renaming parameters from localCommand to localCommandScript, and consolidating escaping/quoting logic through new functions. It adds a comprehensive end-to-end SSH bootstrap test (fish login shells), updates Xcode project wiring to compile the new file and test, and adds two notification keys with small test adjustments.

Changes

SSH Command Refactoring & Tests

Layer / File(s) Summary
Helper Methods
CLI/CMUXCLI+SSHCommandSupport.swift
Adds openSSHLocalCommandValue, openSSHRemoteCommandValue, posixShellCommand, openSSHCommandOptionValue, and combinedLocalShellScript to centralize wrapping/escaping of local/remote shell scripts.
Data/Call Signature
CLI/cmux.swift
Renames parameter localCommand → localCommandScript across builders (buildSSHCommandText, buildSSHCommandArguments, bootstrap/snippet builders).
Core SSH Command Building
CLI/cmux.swift
Replaces combinedLocalShellCommand with combinedLocalShellScript; removes sshPercentEscapedRemoteCommand; uses openSSHRemoteCommandValue(shellScript:), openSSHLocalCommandValue(shellScript:), and posixShellCommand(...) for remote/local command option construction; baseSSHArguments now derives LocalCommand= via openSSHLocalCommandValue; shellQuote visibility relaxed to module-internal; startup script now initializes cmux_ssh_log_path as "" and conditionally populates it.
Tests: integration → end-to-end
cmuxTests/WorkspaceRemoteConnectionTests.swift, cmuxTests/WorkspaceSSHFishShellTests.swift
Removes old integration test; adds WorkspaceSSHFishShellTests — end-to-end subprocess test that runs bundled cmux, uses a fake ssh to capture LocalCommand=..., validates percent-escaping, POSIX wrapper, remote RemoteCommand= single-argument behavior, and verifies workspace.remote.foreground_auth_ready. Includes helpers for socket binding, subprocess runs, mock JSON-RPC, and response building.
Project Wiring
GhosttyTabs.xcodeproj/project.pbxproj
Registers CMUXCLI+SSHCommandSupport.swift in cmux-cli target and WorkspaceSSHFishShellTests.swift in cmuxTests target (file refs, group children, build phase entries).

Notification & Appearance Updates

Layer / File(s) Summary
API / Keys
Sources/GhosttyTerminalAppearance.swift
Adds GhosttyNotificationKey.selectionBackground and GhosttyNotificationKey.selectionForeground.
Tests / Assertions
cmuxTests/GhosttyNotificationDispatcherTests.swift, cmuxTests/WorkspaceAppearanceConfigResolutionTests.swift
postedOpacity(from:) now accepts Double or NSNumber (uses .doubleValue); adds assertion that resolved appearance uses explicit backgroundOverride ("#272822").

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#2564: Touches the same SSH command-construction surfaces and LocalCommand/RemoteCommand escaping/formatting.
  • manaflow-ai/cmux#2398: Also refactors SSH/bootstrap shell generation and related CLI command-building behavior.

Poem

🐰 I hop through scripts with careful paws and cheer,
I wrap each line in /bin/sh -c so clear,
I double-percent where OpenSSH expects,
Mock sockets sing as tests inspect the specs,
Hooray — the SSH commands now bound and dear!

🚥 Pre-merge checks | ✅ 12 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title directly matches the main fix: SSH LocalCommand incompatibility with Fish shell, clearly summarizing the primary objective.
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 PR introduces no Swift 6 actor isolation issues. Production changes limited to pure helpers, enum constants, and refactoring with no Sendable/Codable/MainActor isolation mistakes.
Cmux Swift Blocking Runtime ✅ Passed No blocking primitives in production code. New SSH helper file contains only string utilities. Test blocking code is allowed.
Cmux Swift Concurrency ✅ Passed PR introduces no legacy Swift concurrency patterns. DispatchQueue usage in WorkspaceSSHFishShellTests.swift is test-only synchronization tied to XCTestExpectation, explicitly allowed by review rules.
Cmux Swift @Concurrent ✅ Passed No async/await or @concurrent issues. All changes are synchronous string helpers with no actor isolation concerns.
Cmux Swift File And Package Boundaries ✅ Passed New CMUXCLI+SSHCommandSupport.swift (33 lines) has single responsibility. Test file (498 lines) is appropriate. CLI/cmux.swift size decreases by 14 lines. No boundary rule violations.
Cmux Swift Logging ✅ Passed Production code complies with swift-logging.md rules. New CMUXCLI+SSHCommandSupport.swift has no logging violations. Existing print/NSLog in cmux.swift are CLI output (allowed exemption).
Cmux Swiftui State Layout ✅ Passed PR introduces no new SwiftUI state violations. Two new AppKit notification files have no SwiftUI imports or state patterns. All remaining changes are CLI refactoring, tests, and build configuration.
Cmux Architecture Rethink ✅ Passed Pure functional SSH command construction consolidation with clear ownership. No timing constructs, mutable state, or lifecycle splits. Legitimate correctness fix using standard test patterns.
Description check ✅ Passed The pull request description covers the required sections from the template: a comprehensive summary (what changed and why), testing details (including new end-to-end test approach), and a completed checklist covering local testing, test updates, and code review bot requests.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-2706-ssh-fish-shell

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 4, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Centralizes SSH LocalCommand and RemoteCommand construction by wrapping every shell script in /bin/sh -c before applying OpenSSH percent-escaping. This fixes the fish-shell incompatibility (#2706) because OpenSSH previously passed the raw POSIX script to the user's configured login shell; with fish that shell would fail to interpret the script. The PR also hardens the timing debug-log init and migrates the bootstrap integration test to a dedicated WorkspaceSSHFishShellTests file that explicitly validates both the POSIX and fish parse paths.

Confidence Score: 5/5

Safe to merge — the change consistently wraps every SSH LocalCommand and RemoteCommand shell script in /bin/sh -c, and the end-to-end test validates both POSIX and fish parse paths plus the foreground-auth round-trip.

The core fix (posixShellCommand + openSSHCommandOptionValue composition) is small, correct, and covers all four call sites in cmux.swift. The percent-escaping interaction with the staged bootstrap template was traced end-to-end and is correct. The test covers LocalCommand /bin/sh prefix, %%s
percent-escaping, POSIX and fish syntax checks, RemoteCommand wrapping, and the foreground-auth signal.

No files require special attention.

Important Files Changed

Filename Overview
CLI/CMUXCLI+SSHCommandSupport.swift New extension file providing centralised OpenSSH command helpers: posixShellCommand, openSSHLocalCommandValue, openSSHRemoteCommandValue, openSSHCommandOptionValue, and combinedLocalShellScript. All helpers are small and logically correct; the posixShellCommand/openSSHCommandOptionValue composition correctly handles single-quote escaping via shellQuote and OpenSSH percent-escaping.
CLI/cmux.swift Replaces ad-hoc sshPercentEscapedRemoteCommand/combinedLocalShellCommand + inline /bin/sh -c with the new helpers; renames localCommand to localCommandScript throughout call chain; hardens debug-log init with a readable-file guard; promotes shellQuote to internal.
cmuxTests/WorkspaceSSHFishShellTests.swift New 499-line end-to-end regression covering LocalCommand POSIX-sh wrapping, percent-escaping, fish syntax compatibility for both local and remote commands, and foreground-auth round-trip.
cmuxTests/WorkspaceRemoteConnectionTests.swift Removes the old testSSHBootstrapStartupCommandPassesRemoteInstallScriptAsSingleSSHCommand test (now superseded by WorkspaceSSHFishShellTests); remaining tests are untouched.
GhosttyTabs.xcodeproj/project.pbxproj Adds CMUXCLI+SSHCommandSupport.swift and WorkspaceSSHFishShellTests.swift to both the file references and Sources build phases; looks correct.

Sequence Diagram

sequenceDiagram
    participant CLI as cmux CLI
    participant Helper as CMUXCLI+SSHCommandSupport
    participant SSH as OpenSSH (local)
    participant RemoteShell as Remote login shell

    CLI->>Helper: combinedLocalShellScript([reconnect, timing])
    Helper-->>CLI: raw POSIX shell script (joined)

    CLI->>Helper: openSSHLocalCommandValue(shellScript: combined)
    Helper->>Helper: posixShellCommand() wraps in /bin/sh -c
    Helper->>Helper: openSSHCommandOptionValue() applies %% escape
    Helper-->>CLI: LocalCommand=/bin/sh -c '...'

    CLI->>Helper: openSSHRemoteCommandValue(shellScript: bootstrap)
    Helper->>Helper: posixShellCommand() wraps in /bin/sh -c
    Helper->>Helper: openSSHCommandOptionValue() applies %% escape
    Helper-->>CLI: RemoteCommand=/bin/sh -c '...'

    CLI->>SSH: ssh -o LocalCommand=... -o RemoteCommand=...
    SSH->>SSH: %% percent-expand to %
    SSH->>RemoteShell: exec /bin/sh -c remote-bootstrap
    Note over SSH,RemoteShell: Works with fish because /bin/sh is explicit
    SSH-->>CLI: LocalCommand fires via user login shell
    Note over CLI: fish executes /bin/sh -c correctly
Loading

Reviews (7): Last reviewed commit: "Retrigger PR checks after review feedbac..." | Re-trigger Greptile

Comment thread CLI/CMUXFishShellSupport.swift Outdated
Comment thread CLI/CMUXFishShellSupport.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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CLI/cmux.swift`:
- Around line 4837-4840: combinedLocalCommandForSSH is wrapping commands for SSH
but currently passes literal percent signs through to OpenSSH LocalCommand,
which will expand % tokens; fix this by applying the same percent-escaping used
for RemoteCommand: after building the combinedLocalCommand (the call to
combinedLocalCommandForSSH with deferredRemoteReconnectCommand and
sshConnectionTimingCommand), wrap its result with
.map(sshPercentEscapedRemoteCommand) so any `%` characters are replaced with
`%%` before being handed to OpenSSH.

In `@cmuxTests/WorkspaceSSHFishShellTests.swift`:
- Around line 119-142: The test embeds a shell script that calls "python3"
(fakeSSHScript) but doesn't verify Python 3 exists, causing confusing failures
if it's absent; add a pre-check (similar to the existing fish detection logic)
that runs a quick availability check for "python3" (e.g., via which/python3
--version) at the start of the test or in setUp, and if not found call XCTSkip
or fail with a clear message; update WorkspaceSSHFishShellTests.swift to perform
this check before using fakeSSHScript so the test is skipped with an explanatory
error when python3 is unavailable.
🪄 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: abf7d9d3-b472-4146-87ef-4ba18fccd05f

📥 Commits

Reviewing files that changed from the base of the PR and between 45432b7 and 74a7689.

📒 Files selected for processing (6)
  • .gitignore
  • CLI/CMUXFishShellSupport.swift
  • CLI/cmux.swift
  • GhosttyTabs.xcodeproj/project.pbxproj
  • cmuxTests/WorkspaceRemoteConnectionTests.swift
  • cmuxTests/WorkspaceSSHFishShellTests.swift
💤 Files with no reviewable changes (1)
  • cmuxTests/WorkspaceRemoteConnectionTests.swift

Comment thread CLI/cmux.swift Outdated
Comment thread cmuxTests/WorkspaceSSHFishShellTests.swift
CircleCI's cimg Python/Node image runs the web jobs as the circleci user, and npm's global prefix is root-owned. The web-typecheck and web-db-migrations jobs failed before reaching project code because npm could not create /usr/local/lib/node_modules/bun. Use sudo for the pinned global Bun install, matching the existing privileged apt usage in this CircleCI config.\n\nConstraint: Keep the pinned Bun version and existing CircleCI job shape unchanged\nRejected: Treat the web failures as test failures | the logs show failure in the shared installer before project commands ran\nConfidence: high\nScope-risk: narrow\nTested: ruby YAML parse for .circleci/config.yml\nTested: git diff --check\nNot-tested: CircleCI rerun before pushing this commit

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 08e7422. Configure here.

Comment thread .gitignore Outdated
Bring origin/main into the PR branch after main gained the non-root CircleCI Bun install fix and the newer CI/review configuration. Resolve the only content conflict by keeping main's user-local npm prefix approach instead of this branch's sudo npm workaround.\n\nConstraint: Preserve the fish-shell SSH helper extraction and file-length budget fix\nConstraint: Push only to origin for PR #3506\nRejected: Keep sudo npm global install | main has the cleaner user-local npm prefix fix and avoids root-owned CircleCI globals\nConfidence: high\nScope-risk: moderate\nTested: git diff --cached --check\nTested: ruby YAML parse for .circleci/config.yml\nTested: python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv\nTested: swiftc -typecheck CLI/cmux.swift CLI/SocketOperationTelemetry.swift CLI/cmux_open.swift CLI/CMUXCLI+MoveTabToNewWorkspace.swift CLI/CMUXCLI+DocsSettings.swift CLI/CMUXCLI+ThemeSupport.swift CLI/CMUXCLI+Themes.swift CLI/CMUXCLI+TopRendering.swift CLI/CMUXFishShellSupport.swift Sources/RemoteRelayZshBootstrap.swift\nNot-tested: local XCTest per repo policy
LocalCommand and RemoteCommand values now flow through one helper that wraps generated scripts with /bin/sh -c and applies OpenSSH percent escaping exactly once. This makes fish compatibility a shell-neutral SSH invariant instead of fish-specific scattered string handling.

Constraint: Do not bump Swift file-length budgets; keep CLI/cmux.swift and WorkspaceRemoteConnectionTests.swift under their existing limits.

Rejected: Escape LocalCommand at the runSSHCommand callsite | baseSSHArguments already owned LocalCommand emission and callsite escaping would double-escape.

Confidence: high

Scope-risk: narrow

Directive: Add future OpenSSH LocalCommand/RemoteCommand construction through CMUXCLI+SSHCommandSupport.swift so shell wrapping and percent escaping stay centralized.

Tested: swiftc -typecheck CLI command files; scripts/swift_file_length_budget.py; fish functional smoke with direct/staged RemoteCommand and LocalCommand through /usr/local/bin/fish

Not-tested: Full XCTest suite locally per repo testing policy

@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: 3

🤖 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`:
- Line 6720: Multiple divergent implementations of shellQuote exist (function
shellQuote in CLI/cmux.swift plus duplicates in cmuxApp.swift and
SessionIndexStore.swift); extract a single canonical shellQuote into a shared
utility (e.g., ShellQuoting or StringUtils) and replace the local
implementations by importing and calling that shared function. Specifically:
move the logic from the current shellQuote into the new shared module, remove
the duplicate shellQuote definitions in cmuxApp and SessionIndexStore, update
those call sites to use the shared ShellQuoting.shellQuote (or chosen symbol),
and run tests to ensure escaping behavior remains identical.

In `@cmuxTests/WorkspaceSSHFishShellTests.swift`:
- Around line 300-304: The makeSocketPath(_:) helper currently builds a temp
path that can exceed sockaddr_un.sun_path causing silent truncation; change it
to use a shorter base (e.g. "/tmp") when composing the socket filename in
makeSocketPath and add a guard that validates the resulting path length against
the platform sockaddr_un.sun_path maximum (reject or fail the test if it would
overflow) before it is copied into sun_path; apply the same
length-check/fallback logic to the other helper used in the 395-403 block so
tests never attempt to bind a path longer than the socket address buffer.
- Around line 106-109: The test currently assumes the configure RPC is at
position 3 by using requests.dropFirst(2).first which is brittle; instead locate
the configure request by scanning requests for an entry whose "method" equals
"workspace.remote.configure", then extract its "params" (use the existing
configureParams and foregroundAuthToken variable names) and continue assertions;
replace the positional lookup with a find/filter on requests (e.g. find the
dictionary where request["method"] as? String == "workspace.remote.configure")
and then unwrap its "params" as [String: Any] to get "foreground_auth_token".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 703c411e-674f-4f20-90a3-11679ea22898

📥 Commits

Reviewing files that changed from the base of the PR and between 8b11f12 and b6c39bc.

📒 Files selected for processing (4)
  • CLI/CMUXCLI+SSHCommandSupport.swift
  • CLI/cmux.swift
  • GhosttyTabs.xcodeproj/project.pbxproj
  • cmuxTests/WorkspaceSSHFishShellTests.swift

Comment thread CLI/cmux.swift
Comment thread cmuxTests/WorkspaceSSHFishShellTests.swift Outdated
Comment thread cmuxTests/WorkspaceSSHFishShellTests.swift Outdated
The regression test now locates the remote configuration RPC by method and keeps Unix socket paths short enough for sockaddr_un before binding. This addresses review feedback without changing production SSH behavior.

Constraint: Do not bump Swift file-length budgets; keep the new fish test below the 500-line untracked-file threshold.

Confidence: high

Scope-risk: narrow

Tested: swift_file_length_budget.py; swiftc -typecheck CLI command files

Not-tested: Full XCTest suite locally per repo testing policy
coderabbitai[bot]
coderabbitai Bot previously requested changes May 5, 2026

@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 `@cmuxTests/WorkspaceSSHFishShellTests.swift`:
- Around line 106-107: The test currently reads the first RPC via requests.first
to extract create params and initial_command, which breaks if RPC order changes;
instead search requests for the workspace.create call by matching the
request["method"] == "workspace.create" (e.g., use requests.first(where: {
$0["method"] as? String == "workspace.create" })), then XCTUnwrap that request,
extract createParams and initialCommand from it, and update the assertions to
use this found request rather than requests.first so the test no longer depends
on RPC ordering.
- Around line 132-139: The fake SSH harness captures LocalCommand into the
local_command variable but executes it raw; update the code that prepares
local_command (the block that sets local_command from args and before
subprocess.run(["/bin/sh", "-c", local_command], ...)) to unescape OpenSSH
percent-escapes by replacing every "%%" with "%" (e.g., local_command =
local_command.replace("%%", "%")) so the harness runs the same command OpenSSH
would; leave the rest of the subprocess.run call and env handling 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

Run ID: 27b94afc-67d0-41d3-990e-35598c714cb2

📥 Commits

Reviewing files that changed from the base of the PR and between b6c39bc and 92eaf3f.

📒 Files selected for processing (1)
  • cmuxTests/WorkspaceSSHFishShellTests.swift

Comment thread cmuxTests/WorkspaceSSHFishShellTests.swift Outdated
Comment thread cmuxTests/WorkspaceSSHFishShellTests.swift
The fake SSH harness now finds both create/configure RPCs by method and collapses OpenSSH percent escapes before executing LocalCommand, so the regression exercises the same command shape production SSH runs.

Constraint: Keep WorkspaceSSHFishShellTests.swift under the untracked 500-line threshold without changing file-length budgets.

Confidence: high

Scope-risk: narrow

Tested: swift_file_length_budget.py; swiftc -typecheck CLI command files

Not-tested: Full XCTest suite locally per repo testing policy
The PR is blocked by external review state and a CircleCI approval gate rather than a failing check. This empty commit refreshes hosted checks without changing source.

Constraint: No code changes are needed for current green GitHub Actions and Vercel checks

Rejected: Modify CircleCI policy in this fix branch | approval-gate policy is outside the SSH fish regression fix

Confidence: high

Scope-risk: narrow

Tested: Inspected PR check rollup and CircleCI workflow state before committing

Not-tested: CircleCI macOS jobs remain blocked until the approval gate is approved
@austinywang
austinywang dismissed coderabbitai[bot]’s stale review May 5, 2026 01:27

Dismissed after all actionable review threads were addressed, resolved, or intentionally deferred as out of scope for the SSH fish regression fix. Latest automatic checks are green; CircleCI remains paused only on the manual approval gate.

@austinywang
austinywang merged commit 2786aac into main May 5, 2026
32 checks passed

This branch was successfully deployed

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

SSH LocalCommand incompatible with Fish shell

2 participants