diff --git a/.gitignore b/.gitignore index dcdfe4f..136e23d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ flake.lock.bak .sidecar-base .td-root .pi-lens +.cache diff --git a/modules/nixos/pi-agent-runner.nix b/modules/nixos/pi-agent-runner.nix index 287fee1..9e98cff 100644 --- a/modules/nixos/pi-agent-runner.nix +++ b/modules/nixos/pi-agent-runner.nix @@ -397,5 +397,34 @@ in ${concatStringsSep "\n" (map (arg: ''cmd+=( ${escapeShellArg arg} )'') cfg.wrapper.extraRunArgs)} cmd+=( "$@" ) - exec "''${cmd[@]}" + # Reset terminal keyboard protocol modes that pi's TUI may have enabled. + # If pi crashes or is killed (OOM, SIGKILL, etc.), its cleanup handler + # never runs and the host terminal stays in Kitty keyboard protocol or + # xterm modifyOtherKeys mode. This causes all keystrokes to appear as + # raw escape sequences like ^[[99;5u (ctrl+c in CSI-u encoding). + # + # Try /dev/tty first (controlling terminal), fall back to stdout + # (connected through sudo to the user's Ghostty terminal). + cleanup_terminal() { + local output_dev="" + if [ -w /dev/tty ]; then + output_dev=/dev/tty + elif [ -w /dev/stdout ]; then + output_dev=/dev/stdout + fi + if [ -n "$output_dev" ]; then + # Disable Kitty keyboard protocol (pop all flags) + printf '\033[ "$output_dev" 2>/dev/null || true + # Disable xterm modifyOtherKeys + printf '\033[>4;0m' > "$output_dev" 2>/dev/null || true + # Disable bracketed paste mode + printf '\033[?2004l' > "$output_dev" 2>/dev/null || true + # Restore cursor visibility + printf '\033[?25h' > "$output_dev" 2>/dev/null || true + fi + } + trap cleanup_terminal EXIT + + # Run without exec so the EXIT trap fires after pi exits (normal or crash). + "''${cmd[@]}" ''