diff --git a/packages/cli/index.ts b/packages/cli/index.ts index 29a83b2337..dbcff0f169 100644 --- a/packages/cli/index.ts +++ b/packages/cli/index.ts @@ -32,7 +32,9 @@ process.on('uncaughtException', (error) => { } else { writeToStderr(String(error) + '\n'); } - process.exit(1); + void runExitCleanup().finally(() => { + process.exit(1); + }); }); main().catch(async (error) => { diff --git a/packages/cli/src/gemini.tsx b/packages/cli/src/gemini.tsx index 7b092d2d5a..5de617bb88 100644 --- a/packages/cli/src/gemini.tsx +++ b/packages/cli/src/gemini.tsx @@ -641,16 +641,27 @@ export async function main() { const wasRaw = process.stdin.isRaw; if (config.isInteractive() && !wasRaw && process.stdin.isTTY) { + const restoreRawMode = () => { + if ( + process.stdin.isTTY && + process.stdin.isRaw !== wasRaw && + typeof process.stdin.setRawMode === 'function' + ) { + process.stdin.setRawMode(wasRaw); + } + }; + // Set this as early as possible to avoid spurious characters from // input showing up in the output. process.stdin.setRawMode(true); + registerCleanup(restoreRawMode); - // This cleanup isn't strictly needed but may help in certain situations. - process.on('SIGTERM', () => { - process.stdin.setRawMode(wasRaw); - }); - process.on('SIGINT', () => { - process.stdin.setRawMode(wasRaw); + // Best-effort terminal restoration if terminated by signals. + process.on('SIGTERM', restoreRawMode); + process.on('SIGINT', restoreRawMode); + registerCleanup(() => { + process.off('SIGTERM', restoreRawMode); + process.off('SIGINT', restoreRawMode); }); }