Repository navigation
Description
Bug Description
After switching from remote mode to local mode using double-space, the input handling is broken:
- Typed input doesn't get captured entirely
- Pressing space in local mode triggers an unintended switch back to remote mode
Root Cause Analysis
The cleanup sequence in claudeRemoteLauncher.ts (lines 444-451) has three issues:
Issue 1: Dead Code (Line 445)
process.stdin.off('data', abort);The abort function was never registered as a stdin data listener. Line 97 explicitly states:
// Removed catch-all stdin handler - now handled by RemoteModeDisplay keyboard handlersThis line is a no-op and should be removed.
Issue 2: Wrong Cleanup Order (Lines 446-450)
if (process.stdin.isTTY) {
process.stdin.setRawMode(false); // Raw mode disabled BEFORE Ink unmounts
}
if (inkInstance) {
inkInstance.unmount(); // Ink unmount AFTER raw mode change
}Raw mode is disabled before Ink unmounts. This can interfere with Ink's internal cleanup because Ink expects stdin to be in the state it was configured with.
Issue 3: Orphaned Ink Listener
Ink's useInput hook (in RemoteModeDisplay.tsx line 54) registers internal stdin data listeners. When inkInstance.unmount() is called, Ink may not completely remove these listeners. The orphaned listener remains attached to process.stdin.
How the Bug Manifests
- Remote mode sets stdin to raw mode and renders Ink UI with
useInputfor space key handling - User double-spaces to switch to local mode
- Cleanup runs with incorrect order - Ink listener persists
- Local mode starts, inherits stdin with orphaned Ink listener still attached
- When user types a space, the orphaned listener fires and triggers mode switch
Proposed Fix
Reorder and enhance the cleanup sequence:
} finally {
// Clean up permission handler
permissionHandler.reset();
// Reset Terminal - Order matters!
// 1. Unmount Ink first while stdin is still in expected state
if (inkInstance) {
inkInstance.unmount();
}
// 2. Force remove any orphaned stdin listeners (Ink may not clean up completely)
process.stdin.removeAllListeners('data');
// 3. Now reset raw mode
if (process.stdin.isTTY) {
process.stdin.setRawMode(false);
}
messageBuffer.clear();
// Resolve abort future
if (abortFuture) {
abortFuture.resolve(undefined);
}
}Files Affected
src/claude/claudeRemoteLauncher.ts- Cleanup sequence (lines 444-451)
Verification Steps
- Start happy-cli and enter remote mode
- Double-space to switch to local mode
- Type a sentence containing spaces (e.g., "hello world this is a test")
- Verify all characters are captured and spaces don't trigger mode switch
🤖 Generated with Claude Code
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
Fix: Resolve orphaned processes and keyboard input issues (slopus#422, …
Fix: Resolve orphaned processes and keyboard input issues (slopus#422, …
fix: restore terminal state after remote→local mode switch
fix: restore terminal state after remote→local mode switch
fix: restore terminal state after remote→local mode switch
bra1nDump commentedon Apr 14, 2026
tracking this in #613 - same root cause (input handler persists after remote→local switch). closing here to keep discussion in one place.
fix: restore terminal state after remote→local mode switch
fix: restore terminal state after remote→local mode switch