diff --git a/CLI/cmux.swift b/CLI/cmux.swift index 50f225a7..690020cd 100644 --- a/CLI/cmux.swift +++ b/CLI/cmux.swift @@ -2120,8 +2120,18 @@ struct CMUXCLI { parts += ["-o", trimmed] } - parts.append(options.destination) - parts.append(contentsOf: options.extraArguments) + if options.extraArguments.isEmpty { + // No explicit remote command provided: launch an interactive shell while prepending + // ~/.cmux/bin so `cmux` works in this SSH session without touching remote dotfiles. + if !hasSSHOptionKey(options.sshOptions, key: "RequestTTY") { + parts.append("-tt") + } + parts.append(options.destination) + parts.append("export PATH=\"$HOME/.cmux/bin:$PATH\"; exec \"${SHELL:-/bin/zsh}\" -l") + } else { + parts.append(options.destination) + parts.append(contentsOf: options.extraArguments) + } return parts.map(shellQuote).joined(separator: " ") } diff --git a/tests_v2/test_ssh_remote_cli_relay.py b/tests_v2/test_ssh_remote_cli_relay.py index 2e189f04..89853d15 100644 --- a/tests_v2/test_ssh_remote_cli_relay.py +++ b/tests_v2/test_ssh_remote_cli_relay.py @@ -204,6 +204,11 @@ def main() -> int: workspace_id = str(row.get("id") or "") break _must(bool(workspace_id), f"cmux ssh output missing workspace_id: {payload}") + startup_cmd = str(payload.get("ssh_startup_command") or "") + _must( + 'PATH="$HOME/.cmux/bin:$PATH"' in startup_cmd, + f"ssh startup command should prepend ~/.cmux/bin for remote cmux CLI: {startup_cmd!r}", + ) workspace_window_id = payload.get("window_id") current_params = {"window_id": workspace_window_id} if isinstance(workspace_window_id, str) and workspace_window_id else {} current = client._call("workspace.current", current_params) or {}