/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import type React from 'react'; import { Box, Text } from 'ink'; import { theme } from '../semantic-colors.js'; import { ContextUsageDisplay } from './ContextUsageDisplay.js'; import { useTerminalSize } from '../hooks/useTerminalSize.js'; import { AutoAcceptIndicator } from './AutoAcceptIndicator.js'; import { ShellModeIndicator } from './ShellModeIndicator.js'; import { isNarrowWidth } from '../utils/isNarrowWidth.js'; import { useUIState } from '../contexts/UIStateContext.js'; import { useConfig } from '../contexts/ConfigContext.js'; import { useVimMode } from '../contexts/VimModeContext.js'; import { useVerboseMode } from '../contexts/VerboseModeContext.js'; import { ApprovalMode } from '@qwen-code/qwen-code-core'; import { t } from '../../i18n/index.js'; export const Footer: React.FC = () => { const uiState = useUIState(); const config = useConfig(); const { vimEnabled, vimMode } = useVimMode(); const { verboseMode } = useVerboseMode(); const { promptTokenCount, showAutoAcceptIndicator } = { promptTokenCount: uiState.sessionStats.lastPromptTokenCount, showAutoAcceptIndicator: uiState.showAutoAcceptIndicator, }; const { columns: terminalWidth } = useTerminalSize(); const isNarrow = isNarrowWidth(terminalWidth); // Determine sandbox info from environment const sandboxEnv = process.env['SANDBOX']; const sandboxInfo = sandboxEnv ? sandboxEnv === 'sandbox-exec' ? 'seatbelt' : sandboxEnv.startsWith('qwen-code') ? 'docker' : sandboxEnv : null; // Check if debug mode is enabled const debugMode = config.getDebugMode(); const contextWindowSize = config.getContentGeneratorConfig()?.contextWindowSize; // Left section should show exactly ONE thing at any time, in priority order. const leftContent = uiState.ctrlCPressedOnce ? ( {t('Press Ctrl+C again to exit.')} ) : uiState.ctrlDPressedOnce ? ( {t('Press Ctrl+D again to exit.')} ) : uiState.showEscapePrompt ? ( {t('Press Esc again to clear.')} ) : vimEnabled && vimMode === 'INSERT' ? ( -- INSERT -- ) : uiState.shellModeActive ? ( ) : showAutoAcceptIndicator !== undefined && showAutoAcceptIndicator !== ApprovalMode.DEFAULT ? ( ) : ( {t('? for shortcuts')} ); const rightItems: Array<{ key: string; node: React.ReactNode }> = []; if (sandboxInfo) { rightItems.push({ key: 'sandbox', node: 🔒 {sandboxInfo}, }); } if (debugMode) { rightItems.push({ key: 'debug', node: Debug Mode, }); } if (promptTokenCount > 0 && contextWindowSize) { rightItems.push({ key: 'context', node: ( ), }); } if (verboseMode) { rightItems.push({ key: 'verbose', node: {t('verbose')}, }); } return ( {/* Left Section: Exactly one status line (exit prompts / mode indicator / default hint) */} {leftContent} {/* Right Section: Sandbox Info, Debug Mode, Context Usage, and Console Summary */} {rightItems.map(({ key, node }, index) => ( {index > 0 && | } {node} ))} ); };