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

@@ -245,78 +245,166 @@ _ghostty_deferred_init() {
fi
# SSH Integration
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
if [[ "$GHOSTTY_SHELL_FEATURES" =~ (ssh-env|ssh-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 -a env opts ctrl
env=()
opts=()
ctrl=()
emulate -L zsh
setopt local_options no_glob_subst
local -a 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 -a vars
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
export "${v?}"
opts+=(-o "SendEnv ${v%=*}" -o "SetEnv $v")
[[ -n "$TERM_PROGRAM_VERSION" ]] && ssh_env_vars+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
# Temporarily export variables for SSH transmission
local -a ssh_exported_vars=()
local ssh_v ssh_var_name
for ssh_v in "${ssh_env_vars[@]}"; do
ssh_var_name="${ssh_v%%=*}"
if [[ -n "${(P)ssh_var_name+x}" ]]; then
ssh_exported_vars+=("$ssh_var_name=${(P)ssh_var_name}")
else
ssh_exported_vars+=("$ssh_var_name")
fi
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)
local target
target=$(command ssh -G "$@" 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
local ssh_config ssh_user ssh_hostname ssh_target
ssh_config=$(command ssh -G "$@" 2>/dev/null)
ssh_user=$(printf '%s\n' "${(@f)ssh_config}" | while IFS=' ' read -r ssh_key ssh_value; do
[[ "$ssh_key" == "user" ]] && printf '%s\n' "$ssh_value" && break
done)
ssh_hostname=$(printf '%s\n' "${(@f)ssh_config}" | while IFS=' ' read -r ssh_key ssh_value; do
[[ "$ssh_key" == "hostname" ]] && printf '%s\n' "$ssh_value" && break
done)
ssh_target="${ssh_user}@${ssh_hostname}"
if [[ -n "$target" ]] && "$_CACHE" chk "$target"; then
env+=(TERM=xterm-ghostty)
elif command -v infocmp >/dev/null 2>&1; then
local tinfo
tinfo=$(infocmp -x xterm-ghostty 2>/dev/null) || echo "Warning: xterm-ghostty terminfo not found locally." >&2
if [[ -n "$tinfo" ]]; then
echo "Setting up Ghostty terminfo on remote host..." >&2
local cpath
cpath="/tmp/ghostty-ssh-$USER-$RANDOM-$(date +%s)"
case $(echo "$tinfo" | 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)
echo "Terminfo setup complete." >&2
[[ -n "$target" ]] && "$_CACHE" add "$target"
env+=(TERM=xterm-ghostty)
ctrl+=(-o "ControlPath=$cpath")
;;
*) echo "Warning: Failed to install terminfo." >&2 ;;
esac
if [[ -n "$ssh_hostname" ]]; then
# Detect timeout command (BSD compatibility)
local ssh_timeout_cmd=""
if (( $+commands[timeout] )); then
ssh_timeout_cmd="timeout"
elif (( $+commands[gtimeout] )); then
ssh_timeout_cmd="gtimeout"
fi
# Check if terminfo is already cached
local ssh_cache_check_success=false
if (( $+commands[ghostty] )); 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 (( $+commands[infocmp] )); then
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
print "Setting up Ghostty terminfo on remote host..." >&2
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 print "$ssh_terminfo" | $ssh_base64_decode_cmd | 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
print "Terminfo setup complete." >&2
ssh_env+=(TERM=xterm-ghostty)
ssh_opts+=(-o "ControlPath=$ssh_cpath")
# Cache successful installation
if [[ -n "$ssh_target" ]] && (( $+commands[ghostty] )); then
{
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
print "Warning: Failed to install terminfo." >&2
ssh_env+=(TERM=xterm-256color)
fi
else
print "Warning: Could not generate terminfo data." >&2
ssh_env+=(TERM=xterm-256color)
fi
else
print "Warning: ghostty command not available for cache management." >&2
ssh_env+=(TERM=xterm-256color)
fi
else
echo "Warning: infocmp not found locally. Terminfo installation unavailable." >&2
[[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]] && ssh_env+=(TERM=xterm-256color)
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 ssh_v
for ssh_v in "${ssh_env[@]}"; do
[[ "$ssh_v" =~ ^TERM= ]] && ssh_term_set=true && break
done
[[ "$ssh_term_set" == "false" && "$TERM" == "xterm-ghostty" ]] && ssh_env+=(TERM=xterm-256color)
fi
# Execute
if [[ ${#env[@]} -gt 0 ]]; then
env "${env[@]}" command ssh "${opts[@]}" "${ctrl[@]}" "$@"
else
command ssh "${opts[@]}" "${ctrl[@]}" "$@"
command ssh "${ssh_opts[@]}" "$@"
local ssh_ret=$?
# Restore original environment variables
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
local ssh_v
for ssh_v in "${ssh_exported_vars[@]}"; do
if [[ "$ssh_v" == *=* ]]; then
export "${ssh_v}"
else
unset "${ssh_v}"
fi
done
fi
return $ssh_ret
}
fi