@@ -12,7 +12,14 @@ import {
1212 useRef ,
1313 useLayoutEffect ,
1414} from 'react' ;
15- import { type DOMElement , measureElement } from 'ink' ;
15+ import {
16+ type DOMElement ,
17+ measureElement ,
18+ useApp ,
19+ useStdout ,
20+ useStdin ,
21+ type AppProps ,
22+ } from 'ink' ;
1623import { App } from './App.js' ;
1724import { AppContext } from './contexts/AppContext.js' ;
1825import { UIStateContext , type UIState } from './contexts/UIStateContext.js' ;
@@ -87,7 +94,6 @@ import { useVimMode } from './contexts/VimModeContext.js';
8794import { useConsoleMessages } from './hooks/useConsoleMessages.js' ;
8895import { useTerminalSize } from './hooks/useTerminalSize.js' ;
8996import { calculatePromptWidths } from './components/InputPrompt.js' ;
90- import { useApp , useStdout , useStdin } from 'ink' ;
9197import { calculateMainAreaWidth } from './utils/ui-sizing.js' ;
9298import ansiEscapes from 'ansi-escapes' ;
9399import { basename } from 'node:path' ;
@@ -145,7 +151,7 @@ import { NewAgentsChoice } from './components/NewAgentsNotification.js';
145151import { isSlashCommand } from './utils/commandUtils.js' ;
146152import { useTerminalTheme } from './hooks/useTerminalTheme.js' ;
147153import { useTimedMessage } from './hooks/useTimedMessage.js' ;
148- import { isITerm2 } from './utils/terminalUtils .js' ;
154+ import { useSuspend } from './hooks/useSuspend .js' ;
149155
150156function isToolExecuting ( pendingHistoryItems : HistoryItemWithoutId [ ] ) {
151157 return pendingHistoryItems . some ( ( item ) => {
@@ -199,6 +205,7 @@ export const AppContainer = (props: AppContainerProps) => {
199205 useMemoryMonitor ( historyManager ) ;
200206 const isAlternateBuffer = useAlternateBuffer ( ) ;
201207 const [ corgiMode , setCorgiMode ] = useState ( false ) ;
208+ const [ forceRerenderKey , setForceRerenderKey ] = useState ( 0 ) ;
202209 const [ debugMessage , setDebugMessage ] = useState < string > ( '' ) ;
203210 const [ quittingMessages , setQuittingMessages ] = useState <
204211 HistoryItem [ ] | null
@@ -345,7 +352,7 @@ export const AppContainer = (props: AppContainerProps) => {
345352 const { columns : terminalWidth , rows : terminalHeight } = useTerminalSize ( ) ;
346353 const { stdin, setRawMode } = useStdin ( ) ;
347354 const { stdout } = useStdout ( ) ;
348- const app = useApp ( ) ;
355+ const app : AppProps = useApp ( ) ;
349356
350357 // Additional hooks moved from App.tsx
351358 const { stats : sessionStats } = useSessionStats ( ) ;
@@ -1366,6 +1373,23 @@ Logging in with Google... Restarting Gemini CLI to continue.
13661373 } ;
13671374 } , [ showTransientMessage ] ) ;
13681375
1376+ const handleWarning = useCallback (
1377+ ( message : string ) => {
1378+ showTransientMessage ( {
1379+ text : message ,
1380+ type : TransientMessageType . Warning ,
1381+ } ) ;
1382+ } ,
1383+ [ showTransientMessage ] ,
1384+ ) ;
1385+
1386+ const { handleSuspend } = useSuspend ( {
1387+ handleWarning,
1388+ setRawMode,
1389+ refreshStatic,
1390+ setForceRerenderKey,
1391+ } ) ;
1392+
13691393 useEffect ( ( ) => {
13701394 if ( ideNeedsRestart ) {
13711395 // IDE trust changed, force a restart.
@@ -1517,6 +1541,9 @@ Logging in with Google... Restarting Gemini CLI to continue.
15171541 } else if ( keyMatchers [ Command . EXIT ] ( key ) ) {
15181542 setCtrlDPressCount ( ( prev ) => prev + 1 ) ;
15191543 return true ;
1544+ } else if ( keyMatchers [ Command . SUSPEND_APP ] ( key ) ) {
1545+ handleSuspend ( ) ;
1546+ return true ;
15201547 }
15211548
15221549 let enteringConstrainHeightMode = false ;
@@ -1528,15 +1555,6 @@ Logging in with Google... Restarting Gemini CLI to continue.
15281555 if ( keyMatchers [ Command . SHOW_ERROR_DETAILS ] ( key ) ) {
15291556 setShowErrorDetails ( ( prev ) => ! prev ) ;
15301557 return true ;
1531- } else if ( keyMatchers [ Command . SUSPEND_APP ] ( key ) ) {
1532- const undoMessage = isITerm2 ( )
1533- ? 'Undo has been moved to Option + Z'
1534- : 'Undo has been moved to Alt/Option + Z or Cmd + Z' ;
1535- showTransientMessage ( {
1536- text : undoMessage ,
1537- type : TransientMessageType . Warning ,
1538- } ) ;
1539- return true ;
15401558 } else if ( keyMatchers [ Command . SHOW_FULL_TODOS ] ( key ) ) {
15411559 setShowFullTodos ( ( prev ) => ! prev ) ;
15421560 return true ;
@@ -1645,11 +1663,12 @@ Logging in with Google... Restarting Gemini CLI to continue.
16451663 handleSlashCommand ,
16461664 cancelOngoingRequest ,
16471665 activePtyId ,
1666+ handleSuspend ,
16481667 embeddedShellFocused ,
16491668 settings . merged . general . debugKeystrokeLogging ,
16501669 refreshStatic ,
1651- setCopyModeEnabled ,
1652- copyModeEnabled ,
1670+ tabFocusTimeoutRef ,
1671+ handleWarning ,
16531672 isAlternateBuffer ,
16541673 backgroundCurrentShell ,
16551674 toggleBackgroundShell ,
@@ -1659,6 +1678,9 @@ Logging in with Google... Restarting Gemini CLI to continue.
16591678 lastOutputTimeRef ,
16601679 tabFocusTimeoutRef ,
16611680 showTransientMessage ,
1681+ handleWarning ,
1682+ setCopyModeEnabled ,
1683+ copyModeEnabled ,
16621684 ] ,
16631685 ) ;
16641686
@@ -2223,7 +2245,7 @@ Logging in with Google... Restarting Gemini CLI to continue.
22232245 >
22242246 < ToolActionsProvider config = { config } toolCalls = { allToolCalls } >
22252247 < ShellFocusContext . Provider value = { isFocused } >
2226- < App />
2248+ < App key = { `app- ${ forceRerenderKey } ` } />
22272249 </ ShellFocusContext . Provider >
22282250 </ ToolActionsProvider >
22292251 </ AppContext . Provider >
0 commit comments