Skip to content

fix: restore terminal state after remote→local mode switch (rebased) - #647

Open
Haknt wants to merge 2 commits into
slopus:mainfrom
Haknt:fix/stdin-corruption-mode-switch
Open

Haknt wants to merge 2 commits into
slopus:mainfrom
Haknt:fix/stdin-corruption-mode-switch

Conversation

@Haknt

@Haknt Haknt commented Feb 16, 2026

Copy link
Copy Markdown

Rebased version of #570 by @tomstetson — resolved merge conflicts with recent sandbox/permission mode changes on main.

The only changes from the original PR are conflict resolutions in import statements:

  • claudeLocal.ts: Added restoreStdin import alongside new SandboxConfig/initializeSandbox imports
  • runClaude.ts: Added restoreStdin import alongside new applySandboxPermissionPolicy/resolveInitialClaudePermissionMode imports

All fix logic is identical to #570. See that PR for the full root cause analysis and approach.

Fixes #301, #422, #423, #424, #430, #443, #527, #613

tomstetson and others added 2 commits February 16, 2026 22:34
Fix terminal input corruption (dropped characters, phantom mode switches,
unresponsive Claude) when switching from remote mode back to local mode
via double-space.

Root causes addressed:
- Wrong cleanup order: raw mode was disabled BEFORE Ink unmounted, but Ink
  expects raw mode during teardown. Now Ink unmounts first.
- setEncoding("utf8") was never reset: poisons stdin for subsequent
  Buffer-mode consumers. Now reset via _readableState.
- process.exit() in signal handlers bypasses finally blocks: terminal
  left in raw mode. Now restoreStdin() runs before exit.
- No signal forwarding to binary children: orphan Claude processes
  compete for stdin. Now SIGINT/SIGTERM/SIGHUP forwarded.
- stdin left in flowing mode: no pause() after remote cleanup. Now
  restoreStdin() pauses stdin.

Fixes slopus#301, slopus#422, slopus#423, slopus#424, slopus#430, slopus#443, slopus#527

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
child.killed becomes true after the first kill() call, not when the
child actually exits. This means if the child traps the first signal
(e.g., SIGINT for graceful shutdown), subsequent signals from mode
switches would be silently dropped, leaving the launcher waiting
indefinitely.

Track exit state with a boolean instead, and wrap kill() in try-catch
for the race where the child exits between our check and the kill call.

Addresses review feedback from Codex on PR slopus#570.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

@ryuan-cw ryuan-cw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, please get it merged.

bbaldino added a commit to bbaldino/happy that referenced this pull request Feb 25, 2026
Cherry-picked from upstream PR slopus#647 (by Haknt, rebased from PR slopus#570 by
tomstetson).  Fixes stdin corruption when switching from remote back to
local mode by addressing five root causes: cleanup sequencing, encoding
persistence, signal handler bypass, missing signal forwarding, and
flowing mode not being paused.

Fixes: slopus#301, slopus#422, slopus#423, slopus#424, slopus#430, slopus#443, slopus#527, slopus#613

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bbaldino added a commit to bbaldino/happy that referenced this pull request Feb 28, 2026
Cherry-picked from upstream PR slopus#647 (by Haknt, rebased from PR slopus#570 by
tomstetson).  Fixes stdin corruption when switching from remote back to
local mode by addressing five root causes: cleanup sequencing, encoding
persistence, signal handler bypass, missing signal forwarding, and
flowing mode not being paused.

Fixes: slopus#301, slopus#422, slopus#423, slopus#424, slopus#430, slopus#443, slopus#527, slopus#613

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

Bug Report: Terminal input corruption after switching from remote to local mode

3 participants