feat(ssh): rewrite SSH cache system in native Zig

- Eliminates standalone bash dependency
- Consolidates `+list-ssh-cache` and `+clear-ssh-cache` actions into
single `+ssh-cache` action with args
- Structured cache format with timestamps and expiration support
- Memory-safe entry handling with proper file locking
- Comprehensive hostname validation (IPv4/IPv6/domains)
- Atomic updates via temp file + rename
- Updated shell integrations for improved cross-platform support and
reliability
- Cache operations are now unit-testable
This commit is contained in:
Jason Rayne
2025-07-03 20:11:45 -07:00
parent e25aa9f424
commit 75c703071a
9 changed files with 1401 additions and 377 deletions

View File

@@ -97,73 +97,172 @@ fi
# SSH Integration
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
: "${GHOSTTY_SSH_CACHE_TIMEOUT:=5}"
: "${GHOSTTY_SSH_CHECK_TIMEOUT:=3}"
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
readonly _CACHE="${GHOSTTY_RESOURCES_DIR}/shell-integration/shared/ghostty-ssh-cache"
fi
# SSH wrapper
# SSH wrapper that preserves Ghostty features across remote connections
ssh() {
local env=() opts=() ctrl=()
local ssh_env=() ssh_opts=()
# Set up env vars first so terminfo installation inherits them
# Configure environment variables for remote session
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
local vars=(
COLORTERM=truecolor
TERM_PROGRAM=ghostty
${TERM_PROGRAM_VERSION:+TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION}
local -a ssh_env_vars=(
"COLORTERM=truecolor"
"TERM_PROGRAM=ghostty"
)
for v in "${vars[@]}"; do
builtin export "${v?}"
opts+=(-o "SendEnv ${v%=*}" -o "SetEnv $v")
if [[ -n "$TERM_PROGRAM_VERSION" ]]; then
ssh_env_vars+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
fi
# Temporarily export variables for SSH transmission
local -a ssh_exported_vars=()
for ssh_v in "${ssh_env_vars[@]}"; do
local ssh_var_name="${ssh_v%%=*}"
if [[ -n "${!ssh_var_name+x}" ]]; then
ssh_exported_vars+=("$ssh_var_name=${!ssh_var_name}")
else
ssh_exported_vars+=("$ssh_var_name")
fi
builtin export "${ssh_v?}"
# Use both SendEnv and SetEnv for maximum compatibility
ssh_opts+=(-o "SendEnv $ssh_var_name")
ssh_opts+=(-o "SetEnv $ssh_v")
done
ssh_env+=("${ssh_env_vars[@]}")
fi
# Install terminfo if needed, reuse control connection for main session
# Install terminfo on remote host if needed
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
# Get target (only when needed for terminfo)
builtin local target
target=$(builtin command ssh -G "$@" 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
if [[ -n "$target" ]] && "$_CACHE" chk "$target"; then
env+=(TERM=xterm-ghostty)
elif builtin command -v infocmp >/dev/null 2>&1; then
builtin local tinfo
tinfo=$(infocmp -x xterm-ghostty 2>/dev/null) || builtin echo "Warning: xterm-ghostty terminfo not found locally." >&2
if [[ -n "$tinfo" ]]; then
builtin echo "Setting up Ghostty terminfo on remote host..." >&2
builtin local cpath
cpath="/tmp/ghostty-ssh-$USER-$RANDOM-$(date +%s)"
case $(builtin echo "$tinfo" | builtin command ssh "${opts[@]}" -o ControlMaster=yes -o ControlPath="$cpath" -o ControlPersist=60s "$@" '
infocmp xterm-ghostty >/dev/null 2>&1 && echo OK && exit
command -v tic >/dev/null 2>&1 || { echo NO_TIC; exit 1; }
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && echo OK || echo FAIL
') in
OK)
builtin echo "Terminfo setup complete." >&2
[[ -n "$target" ]] && "$_CACHE" add "$target"
env+=(TERM=xterm-ghostty)
ctrl+=(-o "ControlPath=$cpath")
;;
*) builtin echo "Warning: Failed to install terminfo." >&2 ;;
esac
builtin local ssh_config ssh_user ssh_hostname
ssh_config=$(builtin command ssh -G "$@" 2>/dev/null)
ssh_user=$(echo "$ssh_config" | while IFS=' ' read -r ssh_key ssh_value; do
[[ "$ssh_key" == "ssh_user" ]] && echo "$ssh_value" && break
done)
ssh_hostname=$(echo "$ssh_config" | while IFS=' ' read -r ssh_key ssh_value; do
[[ "$ssh_key" == "hostname" ]] && echo "$ssh_value" && break
done)
ssh_target="${ssh_user}@${ssh_hostname}"
if [[ -n "$ssh_hostname" ]]; then
# Detect timeout command (BSD compatibility)
local ssh_timeout_cmd=""
if command -v timeout >/dev/null 2>&1; then
ssh_timeout_cmd="timeout"
elif command -v gtimeout >/dev/null 2>&1; then
ssh_timeout_cmd="gtimeout"
fi
# Check if terminfo is already cached
local ssh_cache_check_success=false
if command -v ghostty >/dev/null 2>&1; then
if [[ -n "$ssh_timeout_cmd" ]]; then
$ssh_timeout_cmd "${GHOSTTY_SSH_CHECK_TIMEOUT}s" ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1 && ssh_cache_check_success=true
else
ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1 && ssh_cache_check_success=true
fi
fi
if [[ "$ssh_cache_check_success" == "true" ]]; then
ssh_env+=(TERM=xterm-ghostty)
elif builtin command -v infocmp >/dev/null 2>&1; then
builtin local ssh_terminfo
# Generate terminfo data (BSD base64 compatibility)
if base64 --help 2>&1 | grep -q GNU; then
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
else
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
fi
if [[ -n "$ssh_terminfo" ]]; then
builtin echo "Setting up Ghostty terminfo on remote host..." >&2
builtin local ssh_cpath_dir ssh_cpath
ssh_cpath_dir=$(mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null) || ssh_cpath_dir="/tmp/ghostty-ssh-$ssh_user.$$"
ssh_cpath="$ssh_cpath_dir/socket"
local ssh_base64_decode_cmd
if base64 --help 2>&1 | grep -q GNU; then
ssh_base64_decode_cmd="base64 -d"
else
ssh_base64_decode_cmd="base64 -D"
fi
if builtin echo "$ssh_terminfo" | $ssh_base64_decode_cmd | builtin command ssh "${ssh_opts[@]}" -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s "$@" '
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
command -v tic >/dev/null 2>&1 || exit 1
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
exit 1
' 2>/dev/null; then
builtin echo "Terminfo setup complete." >&2
ssh_env+=(TERM=xterm-ghostty)
ssh_opts+=(-o "ControlPath=$ssh_cpath")
# Cache successful installation
if [[ -n "$ssh_target" ]] && command -v ghostty >/dev/null 2>&1; then
(
set +m
{
if [[ -n "$ssh_timeout_cmd" ]]; then
$ssh_timeout_cmd "${GHOSTTY_SSH_CACHE_TIMEOUT}s" ghostty +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
else
ghostty +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
fi
} &
)
fi
else
builtin echo "Warning: Failed to install terminfo." >&2
ssh_env+=(TERM=xterm-256color)
fi
else
builtin echo "Warning: Could not generate terminfo data." >&2
ssh_env+=(TERM=xterm-256color)
fi
else
builtin echo "Warning: ghostty command not available for cache management." >&2
ssh_env+=(TERM=xterm-256color)
fi
else
builtin echo "Warning: infocmp not found locally. Terminfo installation unavailable." >&2
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
ssh_env+=(TERM=xterm-256color)
fi
fi
fi
# Fallback TERM only if terminfo didn't set it
# Ensure TERM is set when using ssh-env feature
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
[[ $TERM == xterm-ghostty && ! " ${env[*]} " =~ " TERM=" ]] && env+=(TERM=xterm-256color)
local ssh_term_set=false
for ssh_v in "${ssh_env[@]}"; do
if [[ "$ssh_v" =~ ^TERM= ]]; then
ssh_term_set=true
break
fi
done
if [[ "$ssh_term_set" == "false" && "$TERM" == "xterm-ghostty" ]]; then
ssh_env+=(TERM=xterm-256color)
fi
fi
# Execute
if [[ ${#env[@]} -gt 0 ]]; then
env "${env[@]}" ssh "${opts[@]}" "${ctrl[@]}" "$@"
else
builtin command ssh "${opts[@]}" "${ctrl[@]}" "$@"
builtin command ssh "${ssh_opts[@]}" "$@"
local ssh_ret=$?
# Restore original environment variables
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
for ssh_v in "${ssh_exported_vars[@]}"; do
if [[ "$ssh_v" == *=* ]]; then
builtin export "${ssh_v?}"
else
builtin unset "${ssh_v}"
fi
done
fi
return $ssh_ret
}
fi