mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-03 00:14:28 -07:00
Protect stdout and stderr so JavaScript code can't accidentally write to stdout corrupting ink rendering (#13247)
Bypassing rules as link checker failure is spurious.
This commit is contained in:
@@ -68,7 +68,7 @@ import { useVimMode } from './contexts/VimModeContext.js';
|
||||
import { useConsoleMessages } from './hooks/useConsoleMessages.js';
|
||||
import { useTerminalSize } from './hooks/useTerminalSize.js';
|
||||
import { calculatePromptWidths } from './components/InputPrompt.js';
|
||||
import { useStdout, useStdin } from 'ink';
|
||||
import { useApp, useStdout, useStdin } from 'ink';
|
||||
import { calculateMainAreaWidth } from './utils/ui-sizing.js';
|
||||
import ansiEscapes from 'ansi-escapes';
|
||||
import * as fs from 'node:fs';
|
||||
@@ -91,7 +91,6 @@ import { type IdeIntegrationNudgeResult } from './IdeIntegrationNudge.js';
|
||||
import { appEvents, AppEvent } from '../utils/events.js';
|
||||
import { type UpdateObject } from './utils/updateCheck.js';
|
||||
import { setUpdateHandler } from '../utils/handleAutoUpdate.js';
|
||||
import { ConsolePatcher } from './utils/ConsolePatcher.js';
|
||||
import { registerCleanup, runExitCleanup } from '../utils/cleanup.js';
|
||||
import { useMessageQueue } from './hooks/useMessageQueue.js';
|
||||
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
|
||||
@@ -111,6 +110,7 @@ import { disableMouseEvents, enableMouseEvents } from './utils/mouse.js';
|
||||
import { useAlternateBuffer } from './hooks/useAlternateBuffer.js';
|
||||
import { useSettings } from './contexts/SettingsContext.js';
|
||||
import { enableSupportedProtocol } from './utils/kittyProtocolDetector.js';
|
||||
import { writeToStdout } from '../utils/stdio.js';
|
||||
|
||||
const WARNING_PROMPT_DURATION_MS = 1000;
|
||||
const QUEUE_ERROR_DISPLAY_DURATION_MS = 3000;
|
||||
@@ -250,6 +250,7 @@ export const AppContainer = (props: AppContainerProps) => {
|
||||
const { columns: terminalWidth, rows: terminalHeight } = useTerminalSize();
|
||||
const { stdin, setRawMode } = useStdin();
|
||||
const { stdout } = useStdout();
|
||||
const app = useApp();
|
||||
|
||||
// Additional hooks moved from App.tsx
|
||||
const { stats: sessionStats } = useSessionStats();
|
||||
@@ -304,20 +305,8 @@ export const AppContainer = (props: AppContainerProps) => {
|
||||
};
|
||||
}, [getEffectiveModel]);
|
||||
|
||||
const {
|
||||
consoleMessages,
|
||||
handleNewMessage,
|
||||
clearConsoleMessages: clearConsoleMessagesState,
|
||||
} = useConsoleMessages();
|
||||
|
||||
useEffect(() => {
|
||||
const consolePatcher = new ConsolePatcher({
|
||||
onNewMessage: handleNewMessage,
|
||||
debugMode: config.getDebugMode(),
|
||||
});
|
||||
consolePatcher.patch();
|
||||
registerCleanup(consolePatcher.cleanup);
|
||||
}, [handleNewMessage, config]);
|
||||
const { consoleMessages, clearConsoleMessages: clearConsoleMessagesState } =
|
||||
useConsoleMessages();
|
||||
|
||||
const mainAreaWidth = calculateMainAreaWidth(terminalWidth, settings);
|
||||
// Derive widths for InputPrompt using shared helper
|
||||
@@ -381,12 +370,25 @@ export const AppContainer = (props: AppContainerProps) => {
|
||||
stdout.write(ansiEscapes.clearTerminal);
|
||||
}
|
||||
setHistoryRemountKey((prev) => prev + 1);
|
||||
}, [setHistoryRemountKey, stdout, isAlternateBuffer]);
|
||||
|
||||
}, [setHistoryRemountKey, isAlternateBuffer, stdout]);
|
||||
const handleEditorClose = useCallback(() => {
|
||||
if (isAlternateBuffer) {
|
||||
// The editor may have exited alternate buffer mode so we need to
|
||||
// enter it again to be safe.
|
||||
writeToStdout(ansiEscapes.enterAlternativeScreen);
|
||||
enableMouseEvents();
|
||||
app.rerender();
|
||||
}
|
||||
enableSupportedProtocol();
|
||||
refreshStatic();
|
||||
}, [refreshStatic]);
|
||||
}, [refreshStatic, isAlternateBuffer, app]);
|
||||
|
||||
useEffect(() => {
|
||||
coreEvents.on(CoreEvent.ExternalEditorClosed, handleEditorClose);
|
||||
return () => {
|
||||
coreEvents.off(CoreEvent.ExternalEditorClosed, handleEditorClose);
|
||||
};
|
||||
}, [handleEditorClose]);
|
||||
|
||||
const {
|
||||
isThemeDialogOpen,
|
||||
@@ -717,7 +719,6 @@ Logging in with Google... Please restart Gemini CLI to continue.
|
||||
performMemoryRefresh,
|
||||
modelSwitchedFromQuotaError,
|
||||
setModelSwitchedFromQuotaError,
|
||||
handleEditorClose,
|
||||
onCancelSubmit,
|
||||
setEmbeddedShellFocused,
|
||||
terminalWidth,
|
||||
@@ -1034,20 +1035,10 @@ Logging in with Google... Please restart Gemini CLI to continue.
|
||||
};
|
||||
appEvents.on(AppEvent.OpenDebugConsole, openDebugConsole);
|
||||
|
||||
const logErrorHandler = (errorMessage: unknown) => {
|
||||
handleNewMessage({
|
||||
type: 'error',
|
||||
content: String(errorMessage),
|
||||
count: 1,
|
||||
});
|
||||
};
|
||||
appEvents.on(AppEvent.LogError, logErrorHandler);
|
||||
|
||||
return () => {
|
||||
appEvents.off(AppEvent.OpenDebugConsole, openDebugConsole);
|
||||
appEvents.off(AppEvent.LogError, logErrorHandler);
|
||||
};
|
||||
}, [handleNewMessage, config]);
|
||||
}, [config]);
|
||||
|
||||
useEffect(() => {
|
||||
if (ctrlCTimerRef.current) {
|
||||
@@ -1283,7 +1274,7 @@ Logging in with Google... Please restart Gemini CLI to continue.
|
||||
|
||||
// Flush any messages that happened during startup before this component
|
||||
// mounted.
|
||||
coreEvents.drainFeedbackBacklog();
|
||||
coreEvents.drainBacklogs();
|
||||
|
||||
return () => {
|
||||
coreEvents.off(CoreEvent.UserFeedback, handleUserFeedback);
|
||||
|
||||
Reference in New Issue
Block a user