diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx
index a8232c7c24..aad5e51211 100644
--- a/packages/cli/src/ui/App.test.tsx
+++ b/packages/cli/src/ui/App.test.tsx
@@ -32,46 +32,6 @@ vi.mock('./components/QuittingDisplay.js', () => ({
QuittingDisplay: () => Quitting...,
}));
-vi.mock('./components/Footer.js', () => ({
- Footer: () => Footer,
-}));
-
-vi.mock('./semantic-colors.js', () => ({
- theme: {
- status: {
- warning: 'yellow',
- },
- },
-}));
-
-// Don't mock the layout components - let them render normally so tests can see the Ctrl messages
-
-vi.mock('./hooks/useLayoutConfig.js', () => ({
- useLayoutConfig: () => ({
- mode: 'default',
- shouldUseStatic: true,
- shouldShowFooterInComposer: true,
- }),
-}));
-
-vi.mock('./hooks/useFooterProps.js', () => ({
- useFooterProps: () => ({
- model: 'test-model',
- targetDir: '/test',
- debugMode: false,
- branchName: 'test-branch',
- debugMessage: '',
- corgiMode: false,
- errorCount: 0,
- showErrorDetails: false,
- showMemoryUsage: false,
- promptTokenCount: 0,
- nightly: false,
- isTrustedFolder: true,
- vimMode: undefined,
- }),
-}));
-
describe('App', () => {
const mockUIState: Partial = {
streamingState: StreamingState.Idle,
@@ -95,6 +55,7 @@ describe('App', () => {
);
expect(lastFrame()).toContain('MainContent');
+ expect(lastFrame()).toContain('Notifications');
expect(lastFrame()).toContain('Composer');
});
@@ -126,6 +87,7 @@ describe('App', () => {
);
expect(lastFrame()).toContain('MainContent');
+ expect(lastFrame()).toContain('Notifications');
expect(lastFrame()).toContain('DialogManager');
});
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx
index 50d1b84afe..8a582be7f7 100644
--- a/packages/cli/src/ui/App.tsx
+++ b/packages/cli/src/ui/App.tsx
@@ -4,16 +4,18 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { useUIState } from './contexts/UIStateContext.js';
+import { Box, Text } from 'ink';
import { StreamingContext } from './contexts/StreamingContext.js';
+import { Notifications } from './components/Notifications.js';
+import { MainContent } from './components/MainContent.js';
+import { DialogManager } from './components/DialogManager.js';
+import { Composer } from './components/Composer.js';
+import { useUIState } from './contexts/UIStateContext.js';
import { QuittingDisplay } from './components/QuittingDisplay.js';
-import { useLayoutConfig } from './hooks/useLayoutConfig.js';
-import { ScreenReaderAppLayout } from './layouts/ScreenReaderAppLayout.js';
-import { DefaultAppLayout } from './layouts/DefaultAppLayout.js';
+import { theme } from './semantic-colors.js';
export const App = () => {
const uiState = useUIState();
- const layout = useLayoutConfig();
if (uiState.quittingMessages) {
return ;
@@ -21,11 +23,35 @@ export const App = () => {
return (
- {layout.mode === 'screenReader' ? (
-
- ) : (
-
- )}
+
+
+
+
+
+
+ {uiState.dialogsVisible ? (
+
+ ) : (
+
+ )}
+
+ {uiState.dialogsVisible && uiState.ctrlCPressedOnce && (
+
+
+ Press Ctrl+C again to exit.
+
+
+ )}
+
+ {uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
+
+
+ Press Ctrl+D again to exit.
+
+
+ )}
+
+
);
};
diff --git a/packages/cli/src/ui/components/Composer.tsx b/packages/cli/src/ui/components/Composer.tsx
index 2e826d97f2..9acc49a44d 100644
--- a/packages/cli/src/ui/components/Composer.tsx
+++ b/packages/cli/src/ui/components/Composer.tsx
@@ -26,12 +26,10 @@ import { useSettings } from '../contexts/SettingsContext.js';
import { ApprovalMode } from '@google/gemini-cli-core';
import { StreamingState } from '../types.js';
import { ConfigInitDisplay } from '../components/ConfigInitDisplay.js';
-import { useLayoutConfig } from '../hooks/useLayoutConfig.js';
export const Composer = () => {
const config = useConfig();
const settings = useSettings();
- const layout = useLayoutConfig();
const uiState = useUIState();
const uiActions = useUIActions();
const { vimEnabled, vimMode } = useVimMode();
@@ -178,7 +176,7 @@ export const Composer = () => {
/>
)}
- {!settings.merged.ui?.hideFooter && layout.shouldShowFooterInComposer && (
+ {!settings.merged.ui?.hideFooter && (
)}
diff --git a/packages/cli/src/ui/components/HistoryList.tsx b/packages/cli/src/ui/components/HistoryList.tsx
deleted file mode 100644
index e5957e8a38..0000000000
--- a/packages/cli/src/ui/components/HistoryList.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { HistoryItemDisplay } from './HistoryItemDisplay.js';
-import type { HistoryItem } from '../types.js';
-import type { SlashCommand } from '../commands/types.js';
-
-interface HistoryListProps {
- history: HistoryItem[];
- terminalWidth: number;
- staticAreaMaxItemHeight: number;
- slashCommands: readonly SlashCommand[];
-}
-
-export const HistoryList = ({
- history,
- terminalWidth,
- staticAreaMaxItemHeight,
- slashCommands,
-}: HistoryListProps) => (
- <>
- {history.map((h) => (
-
- ))}
- >
-);
diff --git a/packages/cli/src/ui/components/MainContent.tsx b/packages/cli/src/ui/components/MainContent.tsx
index a87260f8cd..dfb0ba6e64 100644
--- a/packages/cli/src/ui/components/MainContent.tsx
+++ b/packages/cli/src/ui/components/MainContent.tsx
@@ -5,19 +5,16 @@
*/
import { Box, Static } from 'ink';
-import { HistoryList } from './HistoryList.js';
-import { PendingHistoryList } from './PendingHistoryList.js';
+import { HistoryItemDisplay } from './HistoryItemDisplay.js';
import { ShowMoreLines } from './ShowMoreLines.js';
import { OverflowProvider } from '../contexts/OverflowContext.js';
import { useUIState } from '../contexts/UIStateContext.js';
import { useAppContext } from '../contexts/AppContext.js';
import { AppHeader } from './AppHeader.js';
-import { useLayoutConfig } from '../hooks/useLayoutConfig.js';
export const MainContent = () => {
const { version } = useAppContext();
const uiState = useUIState();
- const layout = useLayoutConfig();
const {
pendingHistoryItems,
mainAreaWidth,
@@ -25,60 +22,42 @@ export const MainContent = () => {
availableTerminalHeight,
} = uiState;
- // In screen reader mode, use regular layout without Static component
- if (!layout.shouldUseStatic) {
- return (
-
-
-
-
-
-
-
-
- );
- }
-
- // Default mode with Static component
return (
<>
,
- ,
+ ...uiState.history.map((h) => (
+
+ )),
]}
>
{(item) => item}
-
+ {pendingHistoryItems.map((item, i) => (
+
+ ))}
diff --git a/packages/cli/src/ui/components/PendingHistoryList.tsx b/packages/cli/src/ui/components/PendingHistoryList.tsx
deleted file mode 100644
index da2ed3c3ea..0000000000
--- a/packages/cli/src/ui/components/PendingHistoryList.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { HistoryItemDisplay } from './HistoryItemDisplay.js';
-import type { HistoryItemWithoutId } from '../types.js';
-
-interface PendingHistoryListProps {
- pendingHistoryItems: HistoryItemWithoutId[];
- terminalWidth: number;
- availableTerminalHeight?: number;
- constrainHeight?: boolean;
- isEditorDialogOpen: boolean;
- activePtyId?: string;
- embeddedShellFocused?: boolean;
-}
-
-export const PendingHistoryList = ({
- pendingHistoryItems,
- terminalWidth,
- availableTerminalHeight,
- constrainHeight,
- isEditorDialogOpen,
- activePtyId,
- embeddedShellFocused,
-}: PendingHistoryListProps) => (
- <>
- {pendingHistoryItems.map((item, i) => (
-
- ))}
- >
-);
diff --git a/packages/cli/src/ui/hooks/useFooterProps.ts b/packages/cli/src/ui/hooks/useFooterProps.ts
deleted file mode 100644
index f469e0126d..0000000000
--- a/packages/cli/src/ui/hooks/useFooterProps.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { useUIState } from '../contexts/UIStateContext.js';
-import { useConfig } from '../contexts/ConfigContext.js';
-import { useSettings } from '../contexts/SettingsContext.js';
-
-export const useFooterProps = () => {
- const uiState = useUIState();
- const config = useConfig();
- const settings = useSettings();
-
- return {
- model: config.getModel(),
- targetDir: config.getTargetDir(),
- debugMode: config.getDebugMode(),
- branchName: uiState.branchName,
- debugMessage: uiState.debugMessage,
- corgiMode: uiState.corgiMode,
- errorCount: uiState.errorCount,
- showErrorDetails: uiState.showErrorDetails,
- showMemoryUsage:
- config.getDebugMode() || settings.merged.ui?.showMemoryUsage || false,
- promptTokenCount: uiState.sessionStats.lastPromptTokenCount,
- nightly: uiState.nightly,
- isTrustedFolder: uiState.isTrustedFolder,
- vimMode: undefined,
- };
-};
diff --git a/packages/cli/src/ui/hooks/useLayoutConfig.ts b/packages/cli/src/ui/hooks/useLayoutConfig.ts
deleted file mode 100644
index d43568982a..0000000000
--- a/packages/cli/src/ui/hooks/useLayoutConfig.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { useIsScreenReaderEnabled } from 'ink';
-
-export interface LayoutConfig {
- shouldUseStatic: boolean;
- shouldShowFooterInComposer: boolean;
- mode: 'default' | 'screenReader';
- allowStaticToggle?: boolean;
-}
-
-export interface LayoutConfigOptions {
- forceStaticMode?: boolean;
- allowToggle?: boolean;
-}
-
-export const useLayoutConfig = (
- options?: LayoutConfigOptions,
-): LayoutConfig => {
- const isScreenReader = useIsScreenReaderEnabled();
-
- // Allow overriding static behavior when toggle is enabled
- const shouldUseStatic =
- options?.forceStaticMode !== undefined
- ? options.forceStaticMode
- : !isScreenReader;
-
- return {
- shouldUseStatic,
- shouldShowFooterInComposer: !isScreenReader,
- mode: isScreenReader ? 'screenReader' : 'default',
- allowStaticToggle: options?.allowToggle ?? false,
- };
-};
diff --git a/packages/cli/src/ui/layouts/DefaultAppLayout.tsx b/packages/cli/src/ui/layouts/DefaultAppLayout.tsx
deleted file mode 100644
index c55d512869..0000000000
--- a/packages/cli/src/ui/layouts/DefaultAppLayout.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import type React from 'react';
-import { Box, Text } from 'ink';
-import { Notifications } from '../components/Notifications.js';
-import { MainContent } from '../components/MainContent.js';
-import { DialogManager } from '../components/DialogManager.js';
-import { Composer } from '../components/Composer.js';
-import { useUIState } from '../contexts/UIStateContext.js';
-import { theme } from '../semantic-colors.js';
-
-export const DefaultAppLayout: React.FC = () => {
- const uiState = useUIState();
-
- return (
-
-
-
-
-
-
- {uiState.dialogsVisible ? (
-
- ) : (
-
- )}
-
- {uiState.dialogsVisible && uiState.ctrlCPressedOnce && (
-
-
- Press Ctrl+C again to exit.
-
-
- )}
-
- {uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
-
-
- Press Ctrl+D again to exit.
-
-
- )}
-
-
- );
-};
diff --git a/packages/cli/src/ui/layouts/ScreenReaderAppLayout.tsx b/packages/cli/src/ui/layouts/ScreenReaderAppLayout.tsx
deleted file mode 100644
index 8096960fe1..0000000000
--- a/packages/cli/src/ui/layouts/ScreenReaderAppLayout.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import type React from 'react';
-import { Box, Text } from 'ink';
-import { Notifications } from '../components/Notifications.js';
-import { MainContent } from '../components/MainContent.js';
-import { DialogManager } from '../components/DialogManager.js';
-import { Composer } from '../components/Composer.js';
-import { Footer } from '../components/Footer.js';
-import { useUIState } from '../contexts/UIStateContext.js';
-import { useFooterProps } from '../hooks/useFooterProps.js';
-import { theme } from '../semantic-colors.js';
-
-export const ScreenReaderAppLayout: React.FC = () => {
- const uiState = useUIState();
- const footerProps = useFooterProps();
-
- return (
-
-
-
-
-
-
- {uiState.dialogsVisible ? (
-
- ) : (
-
- )}
-
- {uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
-
- Press Ctrl+C again to exit.
-
- )}
-
- {uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
-
- Press Ctrl+D again to exit.
-
- )}
-
- );
-};