Repository navigation
fix(resume): clean terminal exit from session picker - #24
Merged
Merged
Conversation
Esc from the --resume picker left a stale frame: Ink unmount erases inline rows via an async stdout write, which process.exit drops. onCancel now unmounts via useApp exit, then exits 1 in a stdout-drain callback (500ms failsafe). Exit code and no-hint/no-hooks cancel behavior preserved. CrossProjectMessage untouched (its post-exit message must persist). Verified: tsc clean for file (12 pre-existing ink reconciler errors), eslint clean, build ok, live PTY Esc test erases frame with EXIT 1, laya gate: ship/low-risk. Plan: thoughts/shared/plans/2026-10-12-resume-picker-esc-exit-cleanup.md
Ink deliberately persists the last inline frame on exit (getRenderOpsForDone returns empty unless cursor hidden), so no flush trick can clean an inline picker cancel. Render the LogSelector branch inside AlternateScreen instead: cancelling exits back to the main buffer via the existing writeSync alt-exit path. Gated off under tmux -CC where alt-screen corrupts state; mouseTracking follows isMouseTrackingEnabled. Keeps exitPicker flush-then-exit(1) so code and no-hint/no-hooks cancel behavior are unchanged. Verified live: alt enter on mount, 1049l plus full mode cleanup and EXIT 1 on Esc.
1 task done
1 task done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--resumesession picker list now renders inside Ink's<AlternateScreen>(same component the REPL uses), andonCancelunmounts viauseApp().exit()before exiting 1 in a stdout-drain callback (500 ms failsafe). Two commits, single file (src/screens/ResumeConversation.tsx, +41/−3).getRenderOpsForDoneinsrc/ink/log-update.tsreturns an empty diff when the cursor is visible), so no flush-based cleanup can ever erase it — only leaving the alternate buffer restores the main screen. An earlier flush-only attempt was verified to fail on a real terminal, which is what motivated this approach.Impact
-CC(where alt-screen corrupts terminal state) the picker stays inline, exactly as before — no regression there.CrossProjectMessage/NoConversationsMessageexits intentionally untouched (their post-exit text must persist).Testing
checkcould not complete on this machine).bun install --frozen-lockfile— okbunx eslint src/screens/ResumeConversation.tsx— cleanbun run build— green (dist/cli.mjs, SDK bundle, externals valid)bun run typecheck:type-tests— pass (10 files)node bin/openclaude --version—0.31.0 (OpenClaude); compile-cache-disabled launcher check — passbun run test:provider-recommendation— 165 pass / 0 fail--resume+ Esc emits?1049hon mount and?1049l+ full terminal-mode cleanup +EXIT:1, fast, no hint noise$LASTEXITCODE1bun run check→test:fulldoes not complete on this machine: process-spawning tests stall (5 s timeouts) — launcher compile-cache/heap suites and bughunter git-context tests. Reproduced the launcher files (21 pass / 9 fail) identically on a pristineorigin/mainworktree (C:\Users\reini\openclaude-base, detached02ac9901, samenode_modulestree) — not PR-owned (PR touches no launcher/git/bughunter surface).bun run typecheck— 12 errors, reproduced byte-identically on pristineorigin/main(react-reconciler type skew in untouchedsrc/ink/{ink,reconciler,render-to-screen}.tsx; zero errors in the changed file).bun run test:provider— 1748 pass / 3 fail; all 3 are network/timing environmental (stream-watchdog temp-file race, API timeout clamp, Copilot error-type mismatch), none on the PR surface.bun run security:pr-scan -- --base FETCH_HEAD --head HEAD— 1 medium finding inscripts/prepare.mjs;git log origin/main..HEAD -- scripts/prepare.mjsis empty (PR never touches it — upstream rebrand churn between our base and upstream tip). Not PR-owned.Notes
1049h/1049l).-CCkeeps the old inline behavior by design.