Skip to content

Conversation

@ozten
Copy link

@ozten ozten commented Jan 23, 2026

Fix for issue #464.

The StopOrchestrator hook was causing keyboard unresponsiveness for 10-220 seconds after Claude Code sessions ended. This was most severe for users not running Kitty terminal.

Root cause: The tab-state handler executed kitten @ set-tab-color commands that hung indefinitely when no Kitty socket was available. While Promise.race() timeouts were in place, they only abandoned the promise - the subprocess continued running in the background, blocking terminal I/O until it eventually timed out on its own.

Changes:

  • Add subprocess.ts utility with explicit process control using Bun.spawn() instead of Bun.$``. This enables killing hung processes with SIGTERM followed by SIGKILL fallback after 2 seconds.

  • Refactor tab-state.ts with terminal detection (matching the existing pattern in UpdateTabTitle.hook.ts). Kitty terminals use remote control API with subprocess timeout protection. Other terminals fall back to escape codes for basic title support.

  • Apply same terminal detection pattern to SetQuestionTab.hook.ts for consistency across all tab-related hooks.

  • Add AbortController timeout protection to voice.ts and SystemIntegrity.ts handlers for defense in depth.

The fix provides three layers of protection:

  1. Terminal detection - skip Kitty-specific code entirely for non-Kitty
  2. Escape code fallback - basic functionality for all terminals
  3. Subprocess control - kill hung processes after 2s timeout (Kitty)

The StopOrchestrator hook was causing keyboard unresponsiveness for
10-220 seconds after Claude Code sessions ended. This was most severe
for users not running Kitty terminal.

Root cause: The tab-state handler executed `kitten @ set-tab-color`
commands that hung indefinitely when no Kitty socket was available.
While Promise.race() timeouts were in place, they only abandoned the
promise - the subprocess continued running in the background, blocking
terminal I/O until it eventually timed out on its own.

Changes:

- Add subprocess.ts utility with explicit process control using
  Bun.spawn() instead of Bun.$``. This enables killing hung processes
  with SIGTERM followed by SIGKILL fallback after 2 seconds.

- Refactor tab-state.ts with terminal detection (matching the existing
  pattern in UpdateTabTitle.hook.ts). Kitty terminals use remote control
  API with subprocess timeout protection. Other terminals fall back to
  escape codes for basic title support.

- Apply same terminal detection pattern to SetQuestionTab.hook.ts for
  consistency across all tab-related hooks.

- Add AbortController timeout protection to voice.ts and
  SystemIntegrity.ts handlers for defense in depth.

The fix provides three layers of protection:
1. Terminal detection - skip Kitty-specific code entirely for non-Kitty
2. Escape code fallback - basic functionality for all terminals
3. Subprocess control - kill hung processes after 2s timeout (Kitty)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ozten
Copy link
Author

ozten commented Jan 23, 2026

I don't think this PR fixes the garbled screen issue, but it does eliminate the unresponsiveness that reproduced 100% of the time when using PAI without Kitty.

@ozten
Copy link
Author

ozten commented Jan 26, 2026

Please restart the checks. This one failed because Error: Failed to setup GitHub token: Error: Could not fetch an OIDC token. Did you remember to add id-token: write to your workflow permissions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant