* Clean up the terminal and reconnect when SSH connections drop A remote tmux, herdr, or editor arms terminal modes over the SSH pipe (mouse tracking, focus reporting, the alternate screen) that only it can disarm. When the connection dies instead of exiting cleanly, those modes stay armed on the local terminal, and every mouse move floods the prompt with escape-sequence junk. Wrap ssh in a shell function that disarms those modes after every exit, and automatically reconnects when an established interactive session drops. Remote commands, configured RemoteCommands, and redirected stdin never reconnect, so their side effects cannot replay, and the retry loop runs in a subshell so Ctrl-C cancels both the in-flight attempt and the loop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Detect dead SSH connections within a minute Without keepalives, ssh does not notice a dead peer until TCP gives up, which can take hours of sitting on a hung terminal with remote-armed terminal modes stuck on. Ship a client keepalive default so drops are detected in about 45 seconds, letting the shell's ssh wrapper clean up and reconnect. ~/.ssh/config is read first and wins, so per-host overrides still apply. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fail closed when ssh -G cannot resolve the effective config An unresolvable configuration could hide a RemoteCommand, so treat it as non-interactive rather than reconnectable. Also strengthen the tests from Copilot review: assert the complete disarm sequence, and verify on a real interactive pty that Ctrl-C during a retry attempt kills the reconnect loop itself, not just the in-flight attempt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Tolerate the explicit RemoteCommand none when probing ssh -G The literal "none" is how ssh_config cancels a configured RemoteCommand, and some OpenSSH versions emit it even when unset, which would have silently disabled reconnecting entirely. Treat it as no remote command while still failing closed on real ones and unresolvable configs, and make the fake ssh -G emit the "none" form so the behavior tests cover it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
18 lines
831 B
Bash
18 lines
831 B
Bash
# Without keepalives, ssh does not notice a dead connection until TCP gives up,
|
|
# which can take hours of sitting on a hung terminal with any remote-armed
|
|
# terminal modes stuck on. Detect the drop within a minute so the shell's ssh
|
|
# wrapper can clean up and reconnect. ~/.ssh/config is read first and wins, so
|
|
# users can still override these defaults per host.
|
|
if [[ ! -f /etc/ssh/ssh_config.d/20-omarchy-keepalive.conf ]]; then
|
|
install -d -m 755 /etc/ssh/ssh_config.d
|
|
cat >/etc/ssh/ssh_config.d/20-omarchy-keepalive.conf <<'EOF'
|
|
# Omarchy: notice dropped connections quickly instead of hanging until TCP
|
|
# times out. Settings in ~/.ssh/config take precedence over these defaults.
|
|
Host *
|
|
ServerAliveInterval 15
|
|
ServerAliveCountMax 3
|
|
ConnectTimeout 10
|
|
EOF
|
|
chmod 644 /etc/ssh/ssh_config.d/20-omarchy-keepalive.conf
|
|
fi
|