MCPcopy
hub / github.com/claude-code-best/claude-code / cleanupTerminalModes

Function cleanupTerminalModes

src/utils/gracefulShutdown.ts:56–133  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

54 */
55/* eslint-disable custom-rules/no-sync-fs -- must be sync to flush before process.exit */
56function cleanupTerminalModes(): void {
57 if (!process.stdout.isTTY) {
58 return
59 }
60
61 try {
62 // Disable mouse tracking FIRST, before the React unmount tree-walk.
63 // The terminal needs a round-trip to process this and stop sending
64 // events; doing it now (not after unmount) gives that time while
65 // we're busy unmounting. Otherwise events arrive during cooked-mode
66 // cleanup and either echo to the screen or leak to the shell.
67 writeSync(1, DISABLE_MOUSE_TRACKING)
68 // Exit alt screen FIRST so printResumeHint() (and all sequences below)
69 // land on the main buffer.
70 //
71 // Unmount Ink directly rather than writing EXIT_ALT_SCREEN ourselves.
72 // Ink registered its unmount with signal-exit, so it will otherwise run
73 // AGAIN inside forceExit() → process.exit(). Two problems with letting
74 // that happen:
75 // 1. If we write 1049l here and unmount writes it again later, the
76 // second one triggers another DECRC — the cursor jumps back over
77 // the resume hint and the shell prompt lands on the wrong line.
78 // 2. unmount()'s onRender() must run with altScreenActive=true (alt-
79 // screen cursor math) AND on the alt buffer. Exiting alt-screen
80 // here first makes onRender() scribble a REPL frame onto main.
81 // Calling unmount() now does the final render on the alt buffer,
82 // unsubscribes from signal-exit, and writes 1049l exactly once.
83 const inst = instances.get(process.stdout)
84 if (inst?.isAltScreenActive) {
85 try {
86 inst.unmount()
87 } catch {
88 // Reconciler/render threw — fall back to manual alt-screen exit
89 // so printResumeHint still hits the main buffer.
90 writeSync(1, EXIT_ALT_SCREEN)
91 }
92 }
93 // Catches events that arrived during the unmount tree-walk.
94 // detachForShutdown() below also drains.
95 inst?.drainStdin()
96 // Mark the Ink instance unmounted so signal-exit's deferred ink.unmount()
97 // early-returns instead of sending redundant EXIT_ALT_SCREEN sequences
98 // (from its writeSync cleanup block + AlternateScreen's unmount cleanup).
99 // Those redundant sequences land AFTER printResumeHint() and clobber the
100 // resume hint on tmux (and possibly other terminals) by restoring the
101 // saved cursor position. Safe to skip full unmount: this function already
102 // sends all the terminal-reset sequences, and the process is exiting.
103 inst?.detachForShutdown()
104 // Disable extended key reporting — always send both since terminals
105 // silently ignore whichever they don't implement
106 writeSync(1, DISABLE_MODIFY_OTHER_KEYS)
107 writeSync(1, DISABLE_KITTY_KEYBOARD)
108 // Disable focus events (DECSET 1004)
109 writeSync(1, DFE)
110 // Disable bracketed paste mode
111 writeSync(1, DBP)
112 // Show cursor
113 writeSync(1, SHOW_CURSOR)

Callers 2

gracefulShutdownSyncFunction · 0.85
gracefulShutdownFunction · 0.85

Calls 7

supportsTabStatusFunction · 0.90
wrapForMultiplexerFunction · 0.90
unmountMethod · 0.80
drainStdinMethod · 0.80
detachForShutdownMethod · 0.80
isEnvTruthyFunction · 0.70
getMethod · 0.65

Tested by

no test coverage detected