Skip to content

Fix: Resolve orphaned processes and keyboard input issues (#422, #423, #424)#458

Open
hyacz wants to merge 1 commit intoslopus:mainfrom
hyacz:fix/input-corruption-simple-approach
Open

Fix: Resolve orphaned processes and keyboard input issues (#422, #423, #424)#458
hyacz wants to merge 1 commit intoslopus:mainfrom
hyacz:fix/input-corruption-simple-approach

Conversation

@hyacz
Copy link
Contributor

@hyacz hyacz commented Jan 23, 2026

Summary

Fixes Issue #422, #423, and #424 (all related to process and terminal management issues during mode switches).

Issue #422: "Bug: Input handler persists after remote-to-local mode switch" ✅

Problem: Input handler persists after switching from Local → Remote, with orphaned processes continuing to read from stdin and blocking subsequent input.

Root Cause: Child processes spawned with signal: opts.abort were not properly terminated when the parent process exited during Local → Remote switches.

Solution:

  • Remove signal: opts.abort from spawn options
  • Add HAPPY_SESSION_ID environment variable to track process groups
  • Implement pkill-based cleanup in claudeLocal.ts (SIGTERM → SIGKILL)
  • Add signal handlers in claude_local_launcher.cjs

Issue #424: "After switching back to local mode, the input is starting to getting incomplete." ✅

Problem: After switching back to local mode, input is incomplete due to orphaned processes competing for stdin.

Root Cause: Same as Issue #422 - orphaned processes from Local mode continue reading from stdin.

Solution: Same fixes as Issue #422.

Issue #423: "Terminal input stuck after exit (raw mode not restored)" ✅

Problem: After exiting happy-cli (via Ctrl+C or normal exit), the terminal input becomes stuck at whitespace. Users need to run stty sane or reset to restore normal terminal behavior.

Root Cause: Manual process.stdin.setRawMode(true) calls bypassed Ink's cleanup mechanism. When SIGINT/SIGTERM was caught, process.exit(0) terminated immediately, skipping the finally block that should restore terminal state.

Solution:

  • Remove manual process.stdin.setRawMode() calls from claudeRemoteLauncher.ts
  • Let Ink handle all stdin management via stdin.ref()/unref()
  • Ink properly restores terminal state on cleanup through its unmount process

Additional Issue: Second Remote Fails to Receive Keyboard Input ✅

Problem: First Remote worked correctly, but after Local → Remote → Local → Remote, the second Remote's keyboard input was buffered (cooked mode behavior).

Root Cause: Orphaned processes (Issues #422/#424) from Local mode modify terminal driver state through stdio: 'inherit'. When Ink calls process.stdin.setRawMode(true), the terminal driver doesn't actually enter raw mode.

Solution:

  • Force raw mode toggle in RemoteModeDisplay.tsx component mount
  • Wait 100ms for Ink to complete setup
  • Toggle sequence: setRawMode(false)setRawMode(true) with 10ms delay
  • Simplify stdin management in claudeRemoteLauncher.ts (let Ink handle everything)

Test Plan

  • Test Remote → Local → Remote keyboard input works
  • Verify no orphaned processes after mode switches (ps aux | grep -i claude)
  • Test multiple mode switches in succession
  • Verify input is complete after switching back to local mode
  • Verify terminal state is properly restored after exit (no need for stty sane)
  • Verify first Remote still works correctly

Files Changed

  • src/ui/ink/RemoteModeDisplay.tsx - Raw mode toggle fix
  • src/claude/claudeRemoteLauncher.ts - Simplified stdin management, removed manual setRawMode
  • src/claude/claudeLocal.ts - Process cleanup logic
  • scripts/claude_local_launcher.cjs - Signal handlers
  • scripts/claude_version_utils.cjs - Session ID tracking

Note: All existing logger.debug() calls from commit 8691991 have been preserved. Only manual stdin management that was causing issues has been removed.

🤖 Generated with Claude Code

…slopus#423, slopus#424)

**Issue slopus#422 & slopus#424: Orphaned Claude Code Processes** ✅ FIXED
- Problem: Local → Remote switching left Claude Code child processes running as orphans
- Orphaned processes continued to read from stdin, blocking subsequent input
- Multiple Claude Code processes competing for stdin

Solution:
- Remove signal: opts.abort from child spawn options
- Add HAPPY_SESSION_ID environment variable for process tracking
- Implement pkill-based cleanup (SIGTERM → SIGKILL) in claudeLocal.ts
- Add signal handlers in claude_local_launcher.cjs

**Issue slopus#423: Terminal input stuck after exit** ✅ FIXED
- Problem: Terminal raw mode not restored after exit, input became stuck
- Root cause: Manual setRawMode(true) calls bypassed Ink's cleanup

Solution:
- Remove manual process.stdin.setRawMode() calls from claudeRemoteLauncher.ts
- Let Ink handle all stdin management via stdin.ref()/unref()
- Ink properly restores terminal state on cleanup

**Additional Issue: Second Remote Keyboard Input** ✅ FIXED
- Problem: Second Remote mode fails to receive keyboard input
- Root cause: Orphaned processes (from slopus#422/slopus#424) modify terminal driver state

Solution:
- Force raw mode toggle in RemoteModeDisplay component mount
- Wait 100ms for Ink to complete setup
- Toggle: setRawMode(false) → setRawMode(true) with 10ms delay
- Simplify stdin management in claudeRemoteLauncher.ts

**Testing:**
- Remote → Local → Remote keyboard input works correctly
- No orphaned Claude processes after mode switches
- Terminal state properly restored on exit
- Multiple mode switches work reliably

**Note:** Preserved all existing logger.debug() calls that were in commit 8691991.
Only removed manual stdin management that was causing issues.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.

2 participants