Fix ssh terminfo spew by using RemoteCommand bootstrap

This commit is contained in:
Lawrence Chen 2026-02-24 21:53:35 -08:00
parent 4e5b5c8ee8
commit 2b7928aa60
3 changed files with 18 additions and 3 deletions

View file

@ -2121,13 +2121,19 @@ struct CMUXCLI {
}
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.
// No explicit remote command provided: keep destination-only argv so Ghostty's
// ssh-terminfo bootstrap can safely append its own remote install command.
// Use RemoteCommand for session-local PATH bootstrap to make `cmux` available.
if !hasSSHOptionKey(options.sshOptions, key: "RequestTTY") {
parts.append("-tt")
}
if !hasSSHOptionKey(options.sshOptions, key: "RemoteCommand") {
parts += [
"-o",
"RemoteCommand=export PATH=\"$HOME/.cmux/bin:$PATH\"; exec \"${SHELL:-/bin/zsh}\" -l",
]
}
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)

View file

@ -116,6 +116,10 @@ def main() -> int:
_must("-o ControlMaster=auto" in ssh_command, f"ssh command should opt into connection reuse: {ssh_command!r}")
_must("-o ControlPersist=600" in ssh_command, f"ssh command should keep master alive for reuse: {ssh_command!r}")
_must("ControlPath=/tmp/cmux-ssh-" in ssh_command, f"ssh command should use shared control path template: {ssh_command!r}")
_must(
"RemoteCommand=export PATH=\"$HOME/.cmux/bin:$PATH\"; exec \"${SHELL:-/bin/zsh}\" -l" in ssh_command,
f"cmux ssh should use -o RemoteCommand for PATH bootstrap (not positional command): {ssh_command!r}",
)
listed_row = None
deadline = time.time() + 8.0

View file

@ -246,6 +246,11 @@ def main() -> int:
surfaces = client.list_surfaces(workspace_id)
_must(bool(surfaces), f"workspace should have at least one surface: {workspace_id}")
surface_id = surfaces[0][1]
terminal_text = client.read_terminal_text(surface_id)
_must(
"Reconstructed via infocmp" not in terminal_text,
"ssh-terminfo bootstrap should not leak raw infocmp output into the interactive shell",
)
term_value = _read_probe_payload(client, surface_id, "printf '%s' \"$TERM\"")
terminfo_state = _read_probe_value(client, surface_id, "infocmp xterm-ghostty >/dev/null 2>&1")