mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-24 21:10:43 -07:00
fix(cli): prevent terminal escape sequences from leaking on exit (#22682)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -13,12 +13,14 @@ import {
|
||||
disableModifyOtherKeys,
|
||||
enableBracketedPasteMode,
|
||||
disableBracketedPasteMode,
|
||||
disableMouseEvents,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { parseColor } from '../themes/color-utils.js';
|
||||
|
||||
export type TerminalBackgroundColor = string | undefined;
|
||||
|
||||
const TERMINAL_CLEANUP_SEQUENCE = '\x1b[<u\x1b[>4;0m\x1b[?2004l';
|
||||
const TERMINAL_CLEANUP_SEQUENCE =
|
||||
'\x1b[<u\x1b[>4;0m\x1b[?2004l\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l';
|
||||
|
||||
export function cleanupTerminalOnExit() {
|
||||
try {
|
||||
@@ -33,6 +35,7 @@ export function cleanupTerminalOnExit() {
|
||||
disableKittyKeyboardProtocol();
|
||||
disableModifyOtherKeys();
|
||||
disableBracketedPasteMode();
|
||||
disableMouseEvents();
|
||||
}
|
||||
|
||||
export class TerminalCapabilityManager {
|
||||
|
||||
@@ -72,6 +72,46 @@ describe('cleanup', () => {
|
||||
expect(asyncFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should run cleanupFunctions BEFORE draining stdin and BEFORE runSyncCleanup', async () => {
|
||||
const callOrder: string[] = [];
|
||||
|
||||
// Cleanup function
|
||||
registerCleanup(() => {
|
||||
callOrder.push('cleanup');
|
||||
});
|
||||
|
||||
// Sync cleanup function (e.g. setRawMode(false))
|
||||
registerSyncCleanup(() => {
|
||||
callOrder.push('sync');
|
||||
});
|
||||
|
||||
// Mock stdin.resume to track drainStdin
|
||||
const originalResume = process.stdin.resume;
|
||||
process.stdin.resume = vi.fn().mockImplementation(() => {
|
||||
callOrder.push('drain');
|
||||
return process.stdin;
|
||||
});
|
||||
|
||||
// Mock stdin properties for drainStdin
|
||||
const originalIsTTY = process.stdin.isTTY;
|
||||
Object.defineProperty(process.stdin, 'isTTY', {
|
||||
value: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
try {
|
||||
await runExitCleanup();
|
||||
} finally {
|
||||
process.stdin.resume = originalResume;
|
||||
Object.defineProperty(process.stdin, 'isTTY', {
|
||||
value: originalIsTTY,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
expect(callOrder).toEqual(['drain', 'drain', 'sync', 'cleanup']);
|
||||
});
|
||||
|
||||
it('should continue running cleanup functions even if one throws an error', async () => {
|
||||
const errorFn = vi.fn().mockImplementation(() => {
|
||||
throw new Error('test error');
|
||||
|
||||
@@ -59,7 +59,7 @@ export function registerTelemetryConfig(config: Config) {
|
||||
|
||||
export async function runExitCleanup() {
|
||||
// drain stdin to prevent printing garbage on exit
|
||||
// https://github.com/google-gemini/gemini-cli/issues/1680
|
||||
// https://github.com/google-gemini/gemini-cli/issues/16801
|
||||
await drainStdin();
|
||||
|
||||
runSyncCleanup();
|
||||
|
||||
Reference in New Issue
Block a user