diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index ad65adc6..259319ff 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -12,6 +12,7 @@ import { Static, Text, useStdin, + useStdout, useInput, type Key as InkKeyType, } from 'ink'; @@ -66,6 +67,7 @@ import { useTextBuffer } from './components/shared/text-buffer.js'; import * as fs from 'fs'; import { UpdateNotification } from './components/UpdateNotification.js'; import { checkForUpdates } from './utils/updateCheck.js'; +import ansiEscapes from 'ansi-escapes'; const CTRL_EXIT_PROMPT_DURATION_MS = 1000; @@ -83,6 +85,7 @@ export const AppWrapper = (props: AppProps) => ( const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const [updateMessage, setUpdateMessage] = useState(null); + const { stdout } = useStdout(); useEffect(() => { checkForUpdates().then(setUpdateMessage); @@ -98,8 +101,9 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const [staticNeedsRefresh, setStaticNeedsRefresh] = useState(false); const [staticKey, setStaticKey] = useState(0); const refreshStatic = useCallback(() => { + stdout.write(ansiEscapes.clearTerminal); setStaticKey((prev) => prev + 1); - }, [setStaticKey]); + }, [setStaticKey, stdout]); const [geminiMdFileCount, setGeminiMdFileCount] = useState(0); const [debugMessage, setDebugMessage] = useState(''); @@ -231,6 +235,8 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const pendingHistoryItems = [...pendingSlashCommandHistoryItems]; const { rows: terminalHeight, columns: terminalWidth } = useTerminalSize(); + const lastTerminalWidth = useRef(terminalWidth); + const isInitialMount = useRef(true); const { stdin, setRawMode } = useStdin(); const isValidPath = useCallback((filePath: string): boolean => { try { @@ -433,6 +439,26 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { [terminalHeight, footerHeight], ); + useEffect(() => { + // skip refreshing Static during first mount + if (isInitialMount.current) { + isInitialMount.current = false; + return; + } + + // debounce so it doesn't fire up too often during resize + const handler = setTimeout(() => { + if (terminalWidth < lastTerminalWidth.current) { + setStaticNeedsRefresh(true); + } + lastTerminalWidth.current = terminalWidth; + }, 300); + + return () => { + clearTimeout(handler); + }; + }, [terminalWidth]); + useEffect(() => { if (!pendingHistoryItems.length) { return;