Skip to content
8 changes: 8 additions & 0 deletions CLI/CMUXCLI+MoshTerminalTransport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ extension CMUXCLI {
remoteMoshProbeFailedMessage: String(
localized: "cli.ssh.mosh.probeFailed",
defaultValue: "[cmux] Could not verify remote Mosh support; continuing over SSH."
),
remoteBootstrapInstallFailedMessage: String(
localized: "cli.ssh.mosh.bootstrapInstallFailed",
defaultValue: "[cmux] Remote bootstrap install failed; continuing over SSH."
),
remoteMoshAddressFallbackMessage: String(
localized: "cli.ssh.mosh.addressFallback",
defaultValue: "[cmux] Remote SSH advertised an unusable address; resolving the Mosh address through the SSH connection."
)
).command()
}
Expand Down
5 changes: 4 additions & 1 deletion Packages/macOS/CmuxFoundation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ so call sites read naturally (`value.javaScriptStringLiteral`, not `f(value)`).
- `String.javaScriptStringLiteral` — the string encoded as a quoted JavaScript string literal.
- `SSHAgentSocketResolver` — OpenSSH option parsing and SSH agent socket path normalization.
- `MoshTerminalCommandBuilder` — a pure Mosh startup-command builder with explicit SSH fallback.
- `MoshRemoteIPMode` — the address-discovery mode selected for a Mosh connection.
- `RemoteTmuxCommandBuilder` — shared remote `tmux` resolution and argv preservation.
- `WorkspaceRemoteTerminalProfile` — durable shell-or-named-tmux terminal intent.
- `WorkspaceRemoteTerminalTransport` — the persisted SSH-or-Mosh interactive terminal preference.
Expand Down Expand Up @@ -51,7 +52,9 @@ let command = MoshTerminalCommandBuilder(
localMoshMissingMessage: "Mosh is unavailable locally; using SSH.",
localMoshUnsupportedMessage: "Mosh is too old for shared SSH setup; using SSH.",
remoteMoshMissingMessage: "mosh-server is unavailable remotely; using SSH.",
remoteMoshProbeFailedMessage: "Mosh capability check failed; using SSH."
remoteMoshProbeFailedMessage: "Mosh capability check failed; using SSH.",
remoteBootstrapInstallFailedMessage: "Remote bootstrap install failed; using SSH.",
remoteMoshAddressFallbackMessage: "Remote SSH address is unusable; using local Mosh resolution."
).command()
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
internal import Foundation

/// Selects how Mosh discovers the address used for its UDP session.
public enum MoshRemoteIPMode: String, Codable, Equatable, Sendable {
/// Derive the address from the remote SSH connection when possible.
case remote

/// Resolve the destination locally before starting the Mosh server.
case local

/// Resolve the address through Mosh's local proxy path.
case proxy

/// Parses a case-insensitive command-line value.
///
/// - Parameter value: The value supplied for a Mosh remote-IP mode.
/// - Returns: The matching mode, or `nil` for an unsupported value.
public init?(cliValue value: String) {
self.init(rawValue: value.trimmingCharacters(in: .whitespacesAndNewlines).lowercased())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ public struct MoshTerminalCommandBuilder: Sendable {
private let destination: String
private let remoteCommandArguments: [String]
private let remoteRelayPort: Int?
private let remoteIPMode: MoshRemoteIPMode
private let preparationShellScript: String?
private let managementReadyShellScript: String?
private let sshFallbackCommand: String
private let localMoshMissingMessage: String
private let localMoshUnsupportedMessage: String
private let remoteMoshMissingMessage: String
private let remoteMoshProbeFailedMessage: String
private let remoteBootstrapInstallFailedMessage: String
private let remoteMoshAddressFallbackMessage: String
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/// Creates a Mosh terminal command builder.
///
Expand All @@ -29,41 +32,50 @@ public struct MoshTerminalCommandBuilder: Sendable {
/// - destination: SSH destination or host alias.
/// - remoteCommandArguments: Optional command argv launched by `mosh-server`.
/// - remoteRelayPort: Optional remote relay whose presence enables authoritative lifecycle attempt registration.
/// - preparationShellScript: Optional local preparation run after capability checks.
/// - remoteIPMode: Address-discovery mode passed to Mosh; remote mode falls back to SSH proxy resolution when SSH advertises an unusable address.
/// - preparationShellScript: Optional local preparation run before capability checks.
/// - managementReadyShellScript: Optional local callback run after SSH preparation succeeds and before Mosh starts.
/// - sshFallbackCommand: Complete local SSH terminal command used when Mosh is unavailable.
/// - localMoshMissingMessage: User-facing message printed when no local `mosh` executable exists.
/// - localMoshUnsupportedMessage: User-facing message printed when local Mosh lacks the required remote-IP mode.
/// - remoteMoshMissingMessage: User-facing message printed when `mosh-server` is absent remotely.
/// - remoteMoshProbeFailedMessage: User-facing message printed when the remote capability probe fails.
/// - remoteBootstrapInstallFailedMessage: User-facing message printed when bootstrap staging fails.
/// - remoteMoshAddressFallbackMessage: User-facing message printed when SSH proxy address resolution is selected automatically.
public init(
capabilityProbeSSHArguments: [String],
sessionSSHArguments: [String],
localMoshExecutableName: String = "mosh",
destination: String,
remoteCommandArguments: [String],
remoteRelayPort: Int? = nil,
remoteIPMode: MoshRemoteIPMode = .remote,
preparationShellScript: String? = nil,
managementReadyShellScript: String? = nil,
sshFallbackCommand: String,
localMoshMissingMessage: String,
localMoshUnsupportedMessage: String,
remoteMoshMissingMessage: String,
remoteMoshProbeFailedMessage: String
remoteMoshProbeFailedMessage: String,
remoteBootstrapInstallFailedMessage: String,
remoteMoshAddressFallbackMessage: String
) {
self.capabilityProbeSSHArguments = capabilityProbeSSHArguments
self.sessionSSHArguments = sessionSSHArguments
self.localMoshExecutableName = localMoshExecutableName
self.destination = destination
self.remoteCommandArguments = remoteCommandArguments
self.remoteRelayPort = remoteRelayPort
self.remoteIPMode = remoteIPMode
self.preparationShellScript = preparationShellScript
self.managementReadyShellScript = managementReadyShellScript
self.sshFallbackCommand = sshFallbackCommand
self.localMoshMissingMessage = localMoshMissingMessage
self.localMoshUnsupportedMessage = localMoshUnsupportedMessage
self.remoteMoshMissingMessage = remoteMoshMissingMessage
self.remoteMoshProbeFailedMessage = remoteMoshProbeFailedMessage
self.remoteBootstrapInstallFailedMessage = remoteBootstrapInstallFailedMessage
self.remoteMoshAddressFallbackMessage = remoteMoshAddressFallbackMessage
}

/// Returns a shell command that launches Mosh or falls back to SSH.
Expand Down Expand Up @@ -93,11 +105,19 @@ public struct MoshTerminalCommandBuilder: Sendable {
])
.map(\.remoteCommandShellQuoted)
.joined(separator: " ")
let remoteSSHConnectionScript = "printf '%s\\n' \"__CMUX_SSH_CONNECTION__${SSH_CONNECTION:-}\""
let remoteSSHConnectionCommand = "/bin/sh -c \(remoteSSHConnectionScript.remoteCommandShellQuoted)"
let remoteSSHConnectionProbe = (capabilityProbeSSHArguments + [
"-T",
destination,
remoteSSHConnectionCommand,
])
.map(\.remoteCommandShellQuoted)
.joined(separator: " ")
let moshSSHCommand = sessionSSHArguments
.map(\.remoteCommandShellQuoted)
.joined(separator: " ")
let moshArguments = ([
"--experimental-remote-ip=remote",
"--ssh=\(moshSSHCommand)",
"--server=\(remoteMoshServerResolver.remoteExecPrefixShellCommand)",
"--",
Expand All @@ -123,17 +143,6 @@ public struct MoshTerminalCommandBuilder: Sendable {
" ;;",
"esac",
"unset cmux_mosh_help",
capabilityProbe,
"cmux_mosh_probe_status=$?",
"if [ \"$cmux_mosh_probe_status\" -eq 127 ]; then",
" printf '%s\\n' \(remoteMoshMissingMessage.remoteCommandShellQuoted) >&2",
" cmux_mosh_fallback",
"fi",
"if [ \"$cmux_mosh_probe_status\" -ne 0 ]; then",
" printf '%s\\n' \(remoteMoshProbeFailedMessage.remoteCommandShellQuoted) >&2",
" cmux_mosh_fallback",
"fi",
"unset cmux_mosh_probe_status",
]
let reportsTerminalLifecycle = remoteRelayPort.map { (1...65_535).contains($0) } ?? false
if reportsTerminalLifecycle {
Expand All @@ -146,12 +155,68 @@ public struct MoshTerminalCommandBuilder: Sendable {
preparationShellScript,
"cmux_mosh_prepare_status=$?",
"if [ \"$cmux_mosh_prepare_status\" -ne 0 ]; then",
" printf '%s\\n' \(remoteMoshProbeFailedMessage.remoteCommandShellQuoted) >&2",
" printf '%s\\n' \(remoteBootstrapInstallFailedMessage.remoteCommandShellQuoted) >&2",
" cmux_mosh_fallback",
"fi",
"unset cmux_mosh_prepare_status cmux_remote_install_status",
]
}
script += [
"cmux_mosh_remote_ip_mode=\(remoteIPMode.rawValue.remoteCommandShellQuoted)",
"cmux_mosh_address_fallback=0",
]
script += [
capabilityProbe,
"cmux_mosh_probe_status=$?",
"if [ \"$cmux_mosh_probe_status\" -eq 127 ]; then",
" printf '%s\\n' \(remoteMoshMissingMessage.remoteCommandShellQuoted) >&2",
" cmux_mosh_fallback",
"fi",
"if [ \"$cmux_mosh_probe_status\" -ne 0 ]; then",
" printf '%s\\n' \(remoteMoshProbeFailedMessage.remoteCommandShellQuoted) >&2",
" cmux_mosh_fallback",
"fi",
]
if remoteIPMode == .remote {
// Mosh parses SSH_CONNECTION as four space-separated fields with
// numeric ports and uses only the server address for its UDP
// session, so validate exactly that shape and no more. When the
// advertised address is unusable (empty, malformed, wildcard, or
// loopback, which is what a port-forwarded SSH alias reports),
// fall back to Mosh's proxy resolution: unlike local mode it
// honors SSH aliases without requiring DNS on the destination.
script += [
"cmux_mosh_ssh_connection_probe_status=0",
"cmux_mosh_ssh_connection_probe=\"$(\(remoteSSHConnectionProbe) 2>/dev/null)\" || cmux_mosh_ssh_connection_probe_status=$?",
"case \"$cmux_mosh_ssh_connection_probe\" in *__CMUX_SSH_CONNECTION__*) cmux_mosh_ssh_connection=\"${cmux_mosh_ssh_connection_probe##*__CMUX_SSH_CONNECTION__}\" ;; *) cmux_mosh_ssh_connection= ;; esac",
"if [ \"$cmux_mosh_ssh_connection_probe_status\" -ne 0 ] || [ -z \"$cmux_mosh_ssh_connection\" ]; then",
" cmux_mosh_address_fallback=1",
"else",
" case \"$cmux_mosh_ssh_connection\" in",
" *' '*' '*' '*)",
" cmux_mosh_ssh_connection_tail=\"${cmux_mosh_ssh_connection#* }\"",
" cmux_mosh_ssh_peer_port=\"${cmux_mosh_ssh_connection_tail%% *}\"",
" cmux_mosh_ssh_connection_tail=\"${cmux_mosh_ssh_connection_tail#* }\"",
" cmux_mosh_ssh_server_ip=\"${cmux_mosh_ssh_connection_tail%% *}\"",
" cmux_mosh_ssh_connection_tail=\"${cmux_mosh_ssh_connection_tail#* }\"",
" cmux_mosh_ssh_server_port=\"${cmux_mosh_ssh_connection_tail%% *}\"",
" case \"$cmux_mosh_ssh_peer_port\" in ''|*[!0-9]*) cmux_mosh_address_fallback=1 ;; esac",
" case \"$cmux_mosh_ssh_server_port\" in ''|*[!0-9]*) cmux_mosh_address_fallback=1 ;; esac",
" case \"$cmux_mosh_ssh_server_ip\" in ''|0.0.0.0|::|::0|::1|127.*) cmux_mosh_address_fallback=1 ;; *[!0-9A-Fa-f:.]*) cmux_mosh_address_fallback=1 ;; esac",
" ;;",
" *) cmux_mosh_address_fallback=1 ;;",
" esac",
"fi",
"if [ \"$cmux_mosh_address_fallback\" -eq 1 ]; then cmux_mosh_remote_ip_mode=proxy; fi",
"unset cmux_mosh_ssh_connection_probe_status cmux_mosh_ssh_connection_probe cmux_mosh_ssh_connection cmux_mosh_ssh_peer_port cmux_mosh_ssh_connection_tail cmux_mosh_ssh_server_ip cmux_mosh_ssh_server_port",
]
}
script += [
"if [ \"$cmux_mosh_address_fallback\" -eq 1 ]; then",
" printf '%s\\n' \(remoteMoshAddressFallbackMessage.remoteCommandShellQuoted) >&2",
"fi",
"unset cmux_mosh_probe_status cmux_mosh_address_fallback",
]
if let managementReadyShellScript = managementReadyShellScript?
.trimmingCharacters(in: .whitespacesAndNewlines),
!managementReadyShellScript.isEmpty {
Expand All @@ -162,7 +227,7 @@ public struct MoshTerminalCommandBuilder: Sendable {
}
// Mosh exposes no reliable post-UDP-handshake callback, so this
// pre-exec launcher must not claim authoritative connected readiness.
script.append("exec \"$cmux_mosh\" \(moshArguments)")
script.append("exec \"$cmux_mosh\" \"--experimental-remote-ip=$cmux_mosh_remote_ip_mode\" \(moshArguments)")
return "/bin/sh -c \(script.joined(separator: "\n").remoteCommandShellQuoted)"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,12 @@ public struct RemoteBootstrapStagingCommandBuilder: Sendable {
}

/// Local shell code that substitutes runtime IDs and streams the bootstrap over SSH.
///
/// The SSH command is one `/bin/sh -c` remote-command string so an account's
/// configured login shell cannot parse the POSIX installer itself.
public var preparationShellScript: String {
let encodedBootstrapScript = Data(bootstrapScript.utf8).base64EncodedString()
let installCommand = ([
"/bin/sh",
"-c",
remoteInstallShellScript,
])
.map(\.remoteCommandShellQuoted)
.joined(separator: " ")
let installCommand = "/bin/sh -c \(remoteInstallShellScript.remoteCommandShellQuoted)"
let sshPrefix = installerSSHArguments
.map(\.remoteCommandShellQuoted)
.joined(separator: " ")
Expand All @@ -61,21 +58,45 @@ public struct RemoteBootstrapStagingCommandBuilder: Sendable {
"cmux_terminal_lifecycle_id_escaped=\"$(cmux_sed_escape \"$cmux_terminal_lifecycle_id\")\"",
"cmux_ssh_attempt_id_escaped=\"$(cmux_sed_escape \"$cmux_ssh_attempt_id\")\"",
"cmux_remote_bootstrap=\"$(printf '%s' \"$cmux_remote_bootstrap\" | sed \"s/__CMUX_WORKSPACE_ID__/$cmux_workspace_id_escaped/g; s/__CMUX_SURFACE_ID__/$cmux_surface_id_escaped/g; s/__CMUX_TERMINAL_LIFECYCLE_ID__/$cmux_terminal_lifecycle_id_escaped/g; s/__CMUX_SSH_ATTEMPT_ID__/$cmux_ssh_attempt_id_escaped/g\")\"",
"printf '%s' \"$cmux_remote_bootstrap\" | command \(sshPrefix) -T \(destination.remoteCommandShellQuoted) \(installCommand.remoteCommandShellQuoted)",
"cmux_remote_install_status=$?",
"unset cmux_remote_bootstrap cmux_remote_bootstrap_b64 cmux_workspace_id cmux_surface_id cmux_terminal_lifecycle_id cmux_ssh_attempt_id cmux_workspace_id_escaped cmux_surface_id_escaped cmux_terminal_lifecycle_id_escaped cmux_ssh_attempt_id_escaped",
"cmux_remote_install_stderr_file=\"$(mktemp \"${TMPDIR:-/tmp}/cmux-remote-bootstrap-install.XXXXXX\" 2>/dev/null || true)\"",
"if [ -n \"$cmux_remote_install_stderr_file\" ]; then",
" printf '%s' \"$cmux_remote_bootstrap\" | command \(sshPrefix) -T \(destination.remoteCommandShellQuoted) \(installCommand.remoteCommandShellQuoted) 2>\"$cmux_remote_install_stderr_file\"",
" cmux_remote_install_status=$?",
"else",
" printf '%s' \"$cmux_remote_bootstrap\" | command \(sshPrefix) -T \(destination.remoteCommandShellQuoted) \(installCommand.remoteCommandShellQuoted)",
" cmux_remote_install_status=$?",
"fi",
"if [ \"$cmux_remote_install_status\" -ne 0 ] && [ -n \"$cmux_remote_install_stderr_file\" ] && [ -s \"$cmux_remote_install_stderr_file\" ]; then",
" cat \"$cmux_remote_install_stderr_file\" >&2",
"fi",
"rm -f -- \"${cmux_remote_install_stderr_file:-}\" 2>/dev/null || true",
"unset cmux_remote_bootstrap cmux_remote_bootstrap_b64 cmux_workspace_id cmux_surface_id cmux_terminal_lifecycle_id cmux_ssh_attempt_id cmux_workspace_id_escaped cmux_surface_id_escaped cmux_terminal_lifecycle_id_escaped cmux_ssh_attempt_id_escaped cmux_remote_install_stderr_file",
"(exit \"$cmux_remote_install_status\")",
].joined(separator: "\n")
}

/// Small remote shell command that replaces the process with the staged bootstrap.
///
/// OpenSSH hands its remote command to the account's configured login
/// shell first. Quote the POSIX launcher as the argument to an explicit
/// `/bin/sh -c` so fish/csh/nushell never parse the staged bootstrap
/// command themselves.
public var remoteExecutionShellScript: String {
"exec /bin/sh \"$HOME/.cmux/relay/\(remoteRelayPort).bootstrap.sh\""
"/bin/sh -c \(stagedBootstrapLauncherScript.remoteCommandShellQuoted)"
}

/// Remote argv that executes the staged bootstrap.
/// Remote command argv that executes the staged bootstrap.
///
/// Mosh forwards this argv to `mosh-server`, which executes it with
/// `execvp` and no shell parsing, so the launcher must be real argv
/// elements: a single command string would be treated as a literal
/// executable pathname and fail.
public var remoteExecutionCommandArguments: [String] {
["/bin/sh", "-c", remoteExecutionShellScript]
["/bin/sh", "-c", stagedBootstrapLauncherScript]
}

private var stagedBootstrapLauncherScript: String {
"exec /bin/sh \"$HOME/.cmux/relay/\(remoteRelayPort).bootstrap.sh\""
}

private var remoteInstallShellScript: String {
Expand Down
Loading