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

Function cleanupTerminalModes

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

Source from the content-addressed store, hash-verified

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

Callers 2

gracefulShutdownSyncFunction · 0.85
gracefulShutdownFunction · 0.85

Calls 7

supportsTabStatusFunction · 0.85
wrapForMultiplexerFunction · 0.85
isEnvTruthyFunction · 0.85
unmountMethod · 0.80
drainStdinMethod · 0.80
detachForShutdownMethod · 0.80
getMethod · 0.65

Tested by

no test coverage detected