From f307ff00ac8b21f325dd3e261f763e0a1f4c43c5 Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Mon, 9 Feb 2026 23:05:54 -0800 Subject: [PATCH 01/10] feat(ui): redesign header to be compact with ASCII icon fix(ui): move sync file I/O out of render loop in AppHeader test(ui): update AppHeader snapshots test(ui): fix Tips test and update all snapshots for compact header --- .../src/ui/__snapshots__/App.test.tsx.snap | 113 ++++++++------- packages/cli/src/ui/components/AppHeader.tsx | 121 +++++++++++++--- packages/cli/src/ui/components/Tips.test.tsx | 34 ++--- packages/cli/src/ui/components/Tips.tsx | 42 ++---- ...ternateBufferQuittingDisplay.test.tsx.snap | 130 +++++++----------- .../__snapshots__/AppHeader.test.tsx.snap | 96 +++++-------- .../ui/components/shared/HorizontalLine.tsx | 59 ++++++-- 7 files changed, 321 insertions(+), 274 deletions(-) diff --git a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap index 450da8362e..8b3308803d 100644 --- a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap +++ b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap @@ -2,20 +2,20 @@ exports[`App > Snapshots > renders default layout correctly 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.2.3 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results + + + + @@ -47,34 +47,29 @@ exports[`App > Snapshots > renders screen reader layout correctly 1`] = ` "Notifications Footer - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.2.3 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. -Composer -" +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results +Composer" `; exports[`App > Snapshots > renders with dialogs visible 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.2.3 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + + + + @@ -110,34 +105,34 @@ DialogManager exports[`App > should render ToolConfirmationQueue along with Composer when tool is confirming and experiment is on 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.2.3 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results HistoryItemDisplay -╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ Action Required │ -│ │ -│ ? ls list directory │ -│ │ -│ ls │ -│ Allow execution of: 'ls'? │ -│ │ -│ ● 1. Allow once │ -│ 2. Allow for this session │ -│ 3. No, suggest changes (esc) │ -│ │ -╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Action Required │ +│ │ +│ ? ls list directory │ +│ │ +│ ls │ +│ Allow execution of: 'ls'? │ +│ │ +│ ● 1. Allow once │ +│ 2. Allow for this session │ +│ 3. No, suggest changes (esc) │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ + + + + diff --git a/packages/cli/src/ui/components/AppHeader.tsx b/packages/cli/src/ui/components/AppHeader.tsx index ad5e2f67d2..aaa16e86a5 100644 --- a/packages/cli/src/ui/components/AppHeader.tsx +++ b/packages/cli/src/ui/components/AppHeader.tsx @@ -4,55 +4,140 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Box } from 'ink'; -import { Header } from './Header.js'; +import { Box, Text } from 'ink'; +import { useEffect, useMemo, useState } from 'react'; +import { UserAccountManager, AuthType } from '@google/gemini-cli-core'; import { Tips } from './Tips.js'; -import { UserIdentity } from './UserIdentity.js'; import { useSettings } from '../contexts/SettingsContext.js'; import { useConfig } from '../contexts/ConfigContext.js'; import { useUIState } from '../contexts/UIStateContext.js'; import { Banner } from './Banner.js'; import { useBanner } from '../hooks/useBanner.js'; import { useTips } from '../hooks/useTips.js'; +import { theme } from '../semantic-colors.js'; +import { ThemedGradient } from './ThemedGradient.js'; +import { CliSpinner } from './CliSpinner.js'; interface AppHeaderProps { version: string; showDetails?: boolean; } +const ICON = `▝▜▄ + ▝▜▄ + ▗▟▀ +▝▀ `; + export const AppHeader = ({ version, showDetails = true }: AppHeaderProps) => { const settings = useSettings(); const config = useConfig(); - const { nightly, terminalWidth, bannerData, bannerVisible } = useUIState(); + const { terminalWidth, bannerData, bannerVisible, updateInfo } = useUIState(); const { bannerText } = useBanner(bannerData); const { showTips } = useTips(); + const authType = config.getContentGeneratorConfig()?.authType; + const [email, setEmail] = useState(); + + useEffect(() => { + if (authType) { + const userAccountManager = new UserAccountManager(); + // Even though the current implementation of getCachedGoogleAccount is sync, + // it performs file I/O. Moving it to useEffect ensures it doesn't block the render cycle. + setEmail(userAccountManager.getCachedGoogleAccount() ?? undefined); + } + }, [authType]); + + const tierName = useMemo(() => config.getUserTierName(), [config]); + + const showHeader = !( + settings.merged.ui.hideBanner || config.getScreenReader() + ); + if (!showDetails) { return ( -
+ {showHeader && ( + + + {ICON} + + + + + Gemini CLI + + v{version} + + + + )} ); } return ( - {!(settings.merged.ui.hideBanner || config.getScreenReader()) && ( - <> -
- {bannerVisible && bannerText && ( - - )} - + {showHeader && ( + + + {ICON} + + + {/* Line 1: Gemini CLI vVersion [Updating] */} + + + Gemini CLI + + v{version} + {updateInfo && ( + + + Updating + + + )} + + + {/* Line 2: Blank */} + + + {/* Line 3: User Email /auth */} + + + {authType === AuthType.LOGIN_WITH_GOOGLE ? ( + {email ?? 'Logged in with Google'} + ) : ( + `Authenticated with ${authType}` + )} + + /auth + + + {/* Line 4: Tier Name /upgrade */} + + + {tierName ?? 'Gemini Code Assist for individuals'} + + /upgrade + + + )} - {settings.merged.ui.showUserIdentity !== false && ( - + + {bannerVisible && bannerText && ( + )} + {!(settings.merged.ui.hideTips || config.getScreenReader()) && showTips && } diff --git a/packages/cli/src/ui/components/Tips.test.tsx b/packages/cli/src/ui/components/Tips.test.tsx index 06b4760834..1730ae81fd 100644 --- a/packages/cli/src/ui/components/Tips.test.tsx +++ b/packages/cli/src/ui/components/Tips.test.tsx @@ -6,27 +6,23 @@ import { render } from '../../test-utils/render.js'; import { Tips } from './Tips.js'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect } from 'vitest'; import type { Config } from '@google/gemini-cli-core'; describe('Tips', () => { - it.each([ - [0, '3. Create GEMINI.md files'], - [5, '3. /help for more information'], - ])( - 'renders correct tips when file count is %i', - async (count, expectedText) => { - const config = { - getGeminiMdFileCount: vi.fn().mockReturnValue(count), - } as unknown as Config; + it('renders correct tips', async () => { + const config = {} as unknown as Config; - const { lastFrame, waitUntilReady, unmount } = render( - , - ); - await waitUntilReady(); - const output = lastFrame(); - expect(output).toContain(expectedText); - unmount(); - }, - ); + const { lastFrame, waitUntilReady, unmount } = render( + , + ); + await waitUntilReady(); + const output = lastFrame(); + expect(output).toContain('1. /help for more information'); + expect(output).toContain( + '2. Ask coding questions, edit code or run commands', + ); + expect(output).toContain('3. Be specific for the best results'); + unmount(); + }); }); diff --git a/packages/cli/src/ui/components/Tips.tsx b/packages/cli/src/ui/components/Tips.tsx index 576b8494c5..94ff8dee6e 100644 --- a/packages/cli/src/ui/components/Tips.tsx +++ b/packages/cli/src/ui/components/Tips.tsx @@ -13,33 +13,15 @@ interface TipsProps { config: Config; } -export const Tips: React.FC = ({ config }) => { - const geminiMdFileCount = config.getGeminiMdFileCount(); - return ( - - Tips for getting started: - - 1. Ask questions, edit files, or run commands. - - - 2. Be specific for the best results. - - {geminiMdFileCount === 0 && ( - - 3. Create{' '} - - GEMINI.md - {' '} - files to customize your interactions with Gemini. - - )} - - {geminiMdFileCount === 0 ? '4.' : '3.'}{' '} - - /help - {' '} - for more information. - - - ); -}; +export const Tips: React.FC = () => ( + + Tips for getting started: + + 1. /help for more information + + + 2. Ask coding questions, edit code or run commands + + 3. Be specific for the best results + +); diff --git a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap index 18e75b75e2..a2ca66d9f5 100644 --- a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap @@ -2,20 +2,16 @@ exports[`AlternateBufferQuittingDisplay > renders with a tool awaiting confirmation > with_confirming_tool 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v0.10.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results Action Required (was prompted): @@ -25,20 +21,16 @@ Action Required (was prompted): exports[`AlternateBufferQuittingDisplay > renders with active and pending tool messages > with_history_and_pending 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v0.10.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool1 Description for tool 1 │ │ │ @@ -46,45 +38,35 @@ Tips for getting started: ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool2 Description for tool 2 │ │ │ -╰──────────────────────────────────────────────────────────────────────────╯ -" +╰──────────────────────────────────────────────────────────────────────────╯" `; exports[`AlternateBufferQuittingDisplay > renders with empty history and no pending items > empty 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v0.10.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. -" +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results" `; exports[`AlternateBufferQuittingDisplay > renders with history but no pending items > with_history_no_pending 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v0.10.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool1 Description for tool 1 │ │ │ @@ -92,47 +74,37 @@ Tips for getting started: ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool2 Description for tool 2 │ │ │ -╰──────────────────────────────────────────────────────────────────────────╯ -" +╰──────────────────────────────────────────────────────────────────────────╯" `; exports[`AlternateBufferQuittingDisplay > renders with pending items but no history > with_pending_no_history 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v0.10.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. -" +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results" `; exports[`AlternateBufferQuittingDisplay > renders with user and gemini messages > with_user_gemini_messages 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v0.10.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ - > Hello Gemini + > Hello Gemini ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ✦ Hello User! " diff --git a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap index 324274fddd..b3866162ad 100644 --- a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap @@ -2,82 +2,62 @@ exports[` > should not render the banner when no flags are set 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.0.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. -" +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results" `; exports[` > should not render the default banner if shown count is 5 or more 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.0.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. -" +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results" `; exports[` > should render the banner with default text 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.0.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + +╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ This is the default banner │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ This is the default banner │ -╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. -" +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results" `; exports[` > should render the banner with warning text 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.0.0 + ▝▜▄ + ▗▟▀ Authenticated with undefined /auth + ▝▀ Gemini Code Assist for individuals /upgrade + +╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ There are capacity issues │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ There are capacity issues │ -╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ Tips for getting started: -1. Ask questions, edit files, or run commands. -2. Be specific for the best results. -3. Create GEMINI.md files to customize your interactions with Gemini. -4. /help for more information. -" +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results" `; diff --git a/packages/cli/src/ui/components/shared/HorizontalLine.tsx b/packages/cli/src/ui/components/shared/HorizontalLine.tsx index 92935617a7..f2463c404e 100644 --- a/packages/cli/src/ui/components/shared/HorizontalLine.tsx +++ b/packages/cli/src/ui/components/shared/HorizontalLine.tsx @@ -8,20 +8,57 @@ import type React from 'react'; import { Box } from 'ink'; import { theme } from '../../semantic-colors.js'; +export type LinePosition = 'top' | 'center' | 'bottom'; + interface HorizontalLineProps { color?: string; + width?: number | string; + position?: LinePosition; } +const overlineStyle = { + top: '‾', + bottom: '', + left: '', + right: '', + topLeft: '', + topRight: '', + bottomLeft: '', + bottomRight: '', +}; + +const underlineStyle = { + top: '_', + bottom: '', + left: '', + right: '', + topLeft: '', + topRight: '', + bottomLeft: '', + bottomRight: '', +}; + export const HorizontalLine: React.FC = ({ color = theme.border.default, -}) => ( - -); + width = '100%', + position = 'center', +}) => { + const borderStyle = + position === 'top' + ? overlineStyle + : position === 'bottom' + ? underlineStyle + : 'single'; + + return ( + + ); +}; From 39754c509351c6fd98fa99c2107e084897cb2864 Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Tue, 10 Feb 2026 11:14:36 -0800 Subject: [PATCH 02/10] fix(ui): reuse UserIdentity component in AppHeader per TL feedback --- packages/cli/src/ui/components/AppHeader.tsx | 38 +++----------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/packages/cli/src/ui/components/AppHeader.tsx b/packages/cli/src/ui/components/AppHeader.tsx index aaa16e86a5..25ef20c963 100644 --- a/packages/cli/src/ui/components/AppHeader.tsx +++ b/packages/cli/src/ui/components/AppHeader.tsx @@ -5,8 +5,7 @@ */ import { Box, Text } from 'ink'; -import { useEffect, useMemo, useState } from 'react'; -import { UserAccountManager, AuthType } from '@google/gemini-cli-core'; +import { UserIdentity } from './UserIdentity.js'; import { Tips } from './Tips.js'; import { useSettings } from '../contexts/SettingsContext.js'; import { useConfig } from '../contexts/ConfigContext.js'; @@ -36,20 +35,6 @@ export const AppHeader = ({ version, showDetails = true }: AppHeaderProps) => { const { bannerText } = useBanner(bannerData); const { showTips } = useTips(); - const authType = config.getContentGeneratorConfig()?.authType; - const [email, setEmail] = useState(); - - useEffect(() => { - if (authType) { - const userAccountManager = new UserAccountManager(); - // Even though the current implementation of getCachedGoogleAccount is sync, - // it performs file I/O. Moving it to useEffect ensures it doesn't block the render cycle. - setEmail(userAccountManager.getCachedGoogleAccount() ?? undefined); - } - }, [authType]); - - const tierName = useMemo(() => config.getUserTierName(), [config]); - const showHeader = !( settings.merged.ui.hideBanner || config.getScreenReader() ); @@ -107,24 +92,11 @@ export const AppHeader = ({ version, showDetails = true }: AppHeaderProps) => { {/* Line 2: Blank */} - {/* Line 3: User Email /auth */} + {/* Lines 3 & 4: User Identity info (Email /auth and Plan /upgrade) */} - - {authType === AuthType.LOGIN_WITH_GOOGLE ? ( - {email ?? 'Logged in with Google'} - ) : ( - `Authenticated with ${authType}` - )} - - /auth - - - {/* Line 4: Tier Name /upgrade */} - - - {tierName ?? 'Gemini Code Assist for individuals'} - - /upgrade + {settings.merged.ui.showUserIdentity !== false && ( + + )} From c6561682e5fdb9cf010f4cb3b0fad6ebc957d856 Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Mon, 9 Feb 2026 23:05:54 -0800 Subject: [PATCH 03/10] feat(ui): redesign header to be compact with ASCII icon --- packages/cli/src/ui/components/AppHeader.tsx | 8 +++---- .../src/ui/components/UserIdentity.test.tsx | 21 ++++++------------- .../cli/src/ui/components/UserIdentity.tsx | 17 ++++++++------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/packages/cli/src/ui/components/AppHeader.tsx b/packages/cli/src/ui/components/AppHeader.tsx index 25ef20c963..26ca8182a0 100644 --- a/packages/cli/src/ui/components/AppHeader.tsx +++ b/packages/cli/src/ui/components/AppHeader.tsx @@ -93,11 +93,9 @@ export const AppHeader = ({ version, showDetails = true }: AppHeaderProps) => { {/* Lines 3 & 4: User Identity info (Email /auth and Plan /upgrade) */} - - {settings.merged.ui.showUserIdentity !== false && ( - - )} - + {settings.merged.ui.showUserIdentity !== false && ( + + )} )} diff --git a/packages/cli/src/ui/components/UserIdentity.test.tsx b/packages/cli/src/ui/components/UserIdentity.test.tsx index a5b41f4b61..8e63415f5c 100644 --- a/packages/cli/src/ui/components/UserIdentity.test.tsx +++ b/packages/cli/src/ui/components/UserIdentity.test.tsx @@ -45,12 +45,12 @@ describe('', () => { await waitUntilReady(); const output = lastFrame(); - expect(output).toContain('Logged in with Google: test@example.com'); + expect(output).toContain('test@example.com'); expect(output).toContain('/auth'); unmount(); }); - it('should render login message without colon if email is missing', async () => { + it('should render login message if email is missing', async () => { // Modify the mock for this specific test vi.mocked(UserAccountManager).mockImplementationOnce( () => @@ -73,12 +73,11 @@ describe('', () => { const output = lastFrame(); expect(output).toContain('Logged in with Google'); - expect(output).not.toContain('Logged in with Google:'); expect(output).toContain('/auth'); unmount(); }); - it('should render plan name on a separate line if provided', async () => { + it('should render plan name and upgrade indicator', async () => { const mockConfig = makeFakeConfig(); vi.spyOn(mockConfig, 'getContentGeneratorConfig').mockReturnValue({ authType: AuthType.LOGIN_WITH_GOOGLE, @@ -92,18 +91,10 @@ describe('', () => { await waitUntilReady(); const output = lastFrame(); - expect(output).toContain('Logged in with Google: test@example.com'); + expect(output).toContain('test@example.com'); expect(output).toContain('/auth'); - expect(output).toContain('Plan: Premium Plan'); - - // Check for two lines (or more if wrapped, but here it should be separate) - const lines = output?.split('\n').filter((line) => line.trim().length > 0); - expect(lines?.some((line) => line.includes('Logged in with Google'))).toBe( - true, - ); - expect(lines?.some((line) => line.includes('Plan: Premium Plan'))).toBe( - true, - ); + expect(output).toContain('Premium Plan'); + expect(output).toContain('/upgrade'); unmount(); }); diff --git a/packages/cli/src/ui/components/UserIdentity.tsx b/packages/cli/src/ui/components/UserIdentity.tsx index e506bfb052..0542241c16 100644 --- a/packages/cli/src/ui/components/UserIdentity.tsx +++ b/packages/cli/src/ui/components/UserIdentity.tsx @@ -37,25 +37,26 @@ export const UserIdentity: React.FC = ({ config }) => { } return ( - + + {/* User Email /auth */} {authType === AuthType.LOGIN_WITH_GOOGLE ? ( - - Logged in with Google{email ? ':' : ''} - {email ? ` ${email}` : ''} - + {email ?? 'Logged in with Google'} ) : ( `Authenticated with ${authType}` )} /auth - {tierName && ( + + {/* Tier Name /upgrade */} + - Plan: {tierName} + {tierName ?? 'Gemini Code Assist for individuals'} - )} + /upgrade + ); }; From 22f20d88c7137e54659545a49b2a5d95339a6a5b Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Mon, 9 Feb 2026 23:18:15 -0800 Subject: [PATCH 04/10] fix(ui): move sync file I/O out of render loop in AppHeader --- .../cli/src/ui/components/UserIdentity.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/ui/components/UserIdentity.tsx b/packages/cli/src/ui/components/UserIdentity.tsx index 0542241c16..51b65e3812 100644 --- a/packages/cli/src/ui/components/UserIdentity.tsx +++ b/packages/cli/src/ui/components/UserIdentity.tsx @@ -5,7 +5,7 @@ */ import type React from 'react'; -import { useMemo } from 'react'; +import { useMemo, useEffect, useState } from 'react'; import { Box, Text } from 'ink'; import { theme } from '../semantic-colors.js'; import { @@ -20,16 +20,17 @@ interface UserIdentityProps { export const UserIdentity: React.FC = ({ config }) => { const authType = config.getContentGeneratorConfig()?.authType; + const [email, setEmail] = useState(); - const { email, tierName } = useMemo(() => { - if (!authType) { - return { email: undefined, tierName: undefined }; + useEffect(() => { + if (authType) { + const userAccountManager = new UserAccountManager(); + setEmail(userAccountManager.getCachedGoogleAccount() ?? undefined); } - const userAccountManager = new UserAccountManager(); - return { - email: userAccountManager.getCachedGoogleAccount(), - tierName: config.getUserTierName(), - }; + }, [authType]); + + const tierName = useMemo(() => { + return authType ? config.getUserTierName() : undefined; }, [config, authType]); if (!authType) { From a4857ca53154838bf1a6893e57a87befb1cc831f Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Tue, 10 Feb 2026 00:08:47 -0800 Subject: [PATCH 05/10] test(ui): fix Tips test and update all snapshots for compact header --- startup-header.png | Bin 0 -> 18852 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 startup-header.png diff --git a/startup-header.png b/startup-header.png new file mode 100644 index 0000000000000000000000000000000000000000..236a16a51564f5f6b86bdef6382995d05ad2bd53 GIT binary patch literal 18852 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 Date: Tue, 10 Feb 2026 11:52:51 -0800 Subject: [PATCH 06/10] test(ui): update AppHeader snapshots after reusing UserIdentity --- .../__snapshots__/AppHeader.test.tsx.snap | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap index b3866162ad..a963c78701 100644 --- a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap @@ -4,8 +4,8 @@ exports[` > should not render the banner when no flags are set 1`] " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: @@ -18,8 +18,8 @@ exports[` > should not render the default banner if shown count is " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: @@ -32,8 +32,8 @@ exports[` > should render the banner with default text 1`] = ` " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ This is the default banner │ @@ -49,8 +49,8 @@ exports[` > should render the banner with warning text 1`] = ` " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ There are capacity issues │ From b32ca37ce70af8ec774397605653c49e9135305c Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Tue, 24 Feb 2026 00:19:52 -0800 Subject: [PATCH 07/10] test(ui): update snapshots and fix test utility crashes for compact header --- packages/cli/src/test-utils/render.tsx | 17 +++++-- .../src/ui/__snapshots__/App.test.tsx.snap | 45 ++++++++++--------- .../cli/src/ui/components/AppHeader.test.tsx | 7 +++ ...ternateBufferQuittingDisplay.test.tsx.snap | 36 ++++++++------- .../__snapshots__/AppHeader.test.tsx.snap | 24 +++++----- 5 files changed, 78 insertions(+), 51 deletions(-) diff --git a/packages/cli/src/test-utils/render.tsx b/packages/cli/src/test-utils/render.tsx index 6908fd36fb..366e7d5619 100644 --- a/packages/cli/src/test-utils/render.tsx +++ b/packages/cli/src/test-utils/render.tsx @@ -211,7 +211,7 @@ class XtermStdout extends EventEmitter { } await act(async () => { if (vi.isFakeTimers()) { - await vi.advanceTimersByTimeAsync(50); + await vi.advanceTimersByTimeAsync(200); } else { // Wait for at least one render to be called if we haven't rendered yet or since start of this call, // but don't wait forever as some renders might be synchronous or skipped. @@ -220,7 +220,7 @@ class XtermStdout extends EventEmitter { this.once('render', resolve), ); const timeoutPromise = new Promise((resolve) => - setTimeout(resolve, 50), + setTimeout(resolve, 200), ); await Promise.race([renderPromise, timeoutPromise]); } @@ -264,6 +264,13 @@ class XtermStdout extends EventEmitter { return true; } + if (this.lastRenderOutput === undefined && currentFrame !== '') { + // If Ink hasn't reported a render yet but terminal has content, + // it means a render happened but metrics weren't captured or reported yet. + // In this case, we consider it a match if we are just waiting for "anything" (empty expected). + return true; + } + if (this.lastRenderOutput === undefined) { return false; } @@ -528,12 +535,13 @@ export const mockSettings = new LoadedSettings( // A minimal mock UIState to satisfy the context provider. // Tests that need specific UIState values should provide their own. const baseMockUiState = { + history: [], renderMarkdown: true, streamingState: StreamingState.Idle, terminalWidth: 100, terminalHeight: 40, currentModel: 'gemini-pro', - terminalBackgroundColor: 'black', + terminalBackgroundColor: 'black' as const, cleanUiDetailsVisible: false, allowPlanMode: true, activePtyId: undefined, @@ -552,6 +560,9 @@ const baseMockUiState = { warningText: '', }, bannerVisible: false, + nightly: false, + updateInfo: null, + pendingHistoryItems: [], }; export const mockAppState: AppState = { diff --git a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap index 8b3308803d..4ef43ad93c 100644 --- a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap +++ b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap @@ -4,8 +4,8 @@ exports[`App > Snapshots > renders default layout correctly 1`] = ` " ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: @@ -49,23 +49,24 @@ Footer ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: 1. /help for more information 2. Ask coding questions, edit code or run commands 3. Be specific for the best results -Composer" +Composer +" `; exports[`App > Snapshots > renders with dialogs visible 1`] = ` " ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ @@ -107,8 +108,8 @@ exports[`App > should render ToolConfirmationQueue along with Composer when tool " ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: @@ -116,19 +117,19 @@ Tips for getting started: 2. Ask coding questions, edit code or run commands 3. Be specific for the best results HistoryItemDisplay -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ Action Required │ -│ │ -│ ? ls list directory │ -│ │ -│ ls │ -│ Allow execution of: 'ls'? │ -│ │ -│ ● 1. Allow once │ -│ 2. Allow for this session │ -│ 3. No, suggest changes (esc) │ -│ │ -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Action Required │ +│ │ +│ ? ls list directory │ +│ │ +│ ls │ +│ Allow execution of: 'ls'? │ +│ │ +│ ● 1. Allow once │ +│ 2. Allow for this session │ +│ 3. No, suggest changes (esc) │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/packages/cli/src/ui/components/AppHeader.test.tsx b/packages/cli/src/ui/components/AppHeader.test.tsx index 9bf821febc..ebcd4de973 100644 --- a/packages/cli/src/ui/components/AppHeader.test.tsx +++ b/packages/cli/src/ui/components/AppHeader.test.tsx @@ -213,6 +213,12 @@ describe('', () => { it('should NOT render Tips when tipsShown is 10 or more', async () => { const mockConfig = makeFakeConfig(); + const uiState = { + bannerData: { + defaultText: '', + warningText: '', + }, + }; persistentStateMock.setData({ tipsShown: 10 }); @@ -220,6 +226,7 @@ describe('', () => { , { config: mockConfig, + uiState, }, ); await waitUntilReady(); diff --git a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap index a2ca66d9f5..089399adee 100644 --- a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap @@ -4,8 +4,8 @@ exports[`AlternateBufferQuittingDisplay > renders with a tool awaiting confirmat " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: @@ -23,8 +23,8 @@ exports[`AlternateBufferQuittingDisplay > renders with active and pending tool m " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: @@ -38,29 +38,31 @@ Tips for getting started: ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool2 Description for tool 2 │ │ │ -╰──────────────────────────────────────────────────────────────────────────╯" +╰──────────────────────────────────────────────────────────────────────────╯ +" `; exports[`AlternateBufferQuittingDisplay > renders with empty history and no pending items > empty 1`] = ` " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: 1. /help for more information 2. Ask coding questions, edit code or run commands -3. Be specific for the best results" +3. Be specific for the best results +" `; exports[`AlternateBufferQuittingDisplay > renders with history but no pending items > with_history_no_pending 1`] = ` " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: @@ -74,29 +76,31 @@ Tips for getting started: ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool2 Description for tool 2 │ │ │ -╰──────────────────────────────────────────────────────────────────────────╯" +╰──────────────────────────────────────────────────────────────────────────╯ +" `; exports[`AlternateBufferQuittingDisplay > renders with pending items but no history > with_pending_no_history 1`] = ` " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: 1. /help for more information 2. Ask coding questions, edit code or run commands -3. Be specific for the best results" +3. Be specific for the best results +" `; exports[`AlternateBufferQuittingDisplay > renders with user and gemini messages > with_user_gemini_messages 1`] = ` " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ Authenticated with undefined /auth - ▝▀ Gemini Code Assist for individuals /upgrade + ▗▟▀ + ▝▀ Tips for getting started: diff --git a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap index a963c78701..5a0b15adc9 100644 --- a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap @@ -11,7 +11,8 @@ exports[` > should not render the banner when no flags are set 1`] Tips for getting started: 1. /help for more information 2. Ask coding questions, edit code or run commands -3. Be specific for the best results" +3. Be specific for the best results +" `; exports[` > should not render the default banner if shown count is 5 or more 1`] = ` @@ -25,7 +26,8 @@ exports[` > should not render the default banner if shown count is Tips for getting started: 1. /help for more information 2. Ask coding questions, edit code or run commands -3. Be specific for the best results" +3. Be specific for the best results +" `; exports[` > should render the banner with default text 1`] = ` @@ -35,14 +37,15 @@ exports[` > should render the banner with default text 1`] = ` ▗▟▀ ▝▀ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ This is the default banner │ -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ This is the default banner │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ Tips for getting started: 1. /help for more information 2. Ask coding questions, edit code or run commands -3. Be specific for the best results" +3. Be specific for the best results +" `; exports[` > should render the banner with warning text 1`] = ` @@ -52,12 +55,13 @@ exports[` > should render the banner with warning text 1`] = ` ▗▟▀ ▝▀ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ There are capacity issues │ -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ There are capacity issues │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ Tips for getting started: 1. /help for more information 2. Ask coding questions, edit code or run commands -3. Be specific for the best results" +3. Be specific for the best results +" `; From 84d5f30245cd6997c394610460a9d09b4c02b50c Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Fri, 27 Feb 2026 13:01:08 -0800 Subject: [PATCH 08/10] test(ui): update snapshots after rebase and clean build --- .../src/ui/__snapshots__/App.test.tsx.snap | 16 +- .../cli/src/ui/components/UserIdentity.tsx | 7 +- ...ternateBufferQuittingDisplay.test.tsx.snap | 26 ++-- .../__snapshots__/AppHeader.test.tsx.snap | 16 +- ...-search-dialog-google_web_search-.snap.svg | 142 +++--------------- ...der-SVG-snapshot-for-a-shell-tool.snap.svg | 142 +++--------------- ...pty-slice-following-a-search-tool.snap.svg | 142 +++--------------- .../__snapshots__/borderStyles.test.tsx.snap | 36 ++--- 8 files changed, 120 insertions(+), 407 deletions(-) diff --git a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap index 4ef43ad93c..47bedd41d4 100644 --- a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap +++ b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap @@ -4,8 +4,8 @@ exports[`App > Snapshots > renders default layout correctly 1`] = ` " ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -49,8 +49,8 @@ Footer ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -65,8 +65,8 @@ exports[`App > Snapshots > renders with dialogs visible 1`] = ` " ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ @@ -108,8 +108,8 @@ exports[`App > should render ToolConfirmationQueue along with Composer when tool " ▝▜▄ Gemini CLI v1.2.3 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: diff --git a/packages/cli/src/ui/components/UserIdentity.tsx b/packages/cli/src/ui/components/UserIdentity.tsx index 51b65e3812..753fcd2abd 100644 --- a/packages/cli/src/ui/components/UserIdentity.tsx +++ b/packages/cli/src/ui/components/UserIdentity.tsx @@ -29,9 +29,10 @@ export const UserIdentity: React.FC = ({ config }) => { } }, [authType]); - const tierName = useMemo(() => { - return authType ? config.getUserTierName() : undefined; - }, [config, authType]); + const tierName = useMemo( + () => (authType ? config.getUserTierName() : undefined), + [config, authType], + ); if (!authType) { return null; diff --git a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap index 089399adee..ed20cded7c 100644 --- a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap @@ -4,8 +4,8 @@ exports[`AlternateBufferQuittingDisplay > renders with a tool awaiting confirmat " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -23,8 +23,8 @@ exports[`AlternateBufferQuittingDisplay > renders with active and pending tool m " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -46,8 +46,8 @@ exports[`AlternateBufferQuittingDisplay > renders with empty history and no pend " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -61,8 +61,8 @@ exports[`AlternateBufferQuittingDisplay > renders with history but no pending it " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -84,8 +84,8 @@ exports[`AlternateBufferQuittingDisplay > renders with pending items but no hist " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -99,8 +99,8 @@ exports[`AlternateBufferQuittingDisplay > renders with user and gemini messages " ▝▜▄ Gemini CLI v0.10.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -108,7 +108,7 @@ Tips for getting started: 2. Ask coding questions, edit code or run commands 3. Be specific for the best results ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ - > Hello Gemini + > Hello Gemini ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ✦ Hello User! " diff --git a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap index 5a0b15adc9..42a6488176 100644 --- a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap @@ -4,8 +4,8 @@ exports[` > should not render the banner when no flags are set 1`] " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -19,8 +19,8 @@ exports[` > should not render the default banner if shown count is " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ Tips for getting started: @@ -34,8 +34,8 @@ exports[` > should render the banner with default text 1`] = ` " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ This is the default banner │ @@ -52,8 +52,8 @@ exports[` > should render the banner with warning text 1`] = ` " ▝▜▄ Gemini CLI v1.0.0 ▝▜▄ - ▗▟▀ - ▝▀ + ▗▟▀ + ▝▀ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ There are capacity issues │ diff --git a/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-pending-search-dialog-google_web_search-.snap.svg b/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-pending-search-dialog-google_web_search-.snap.svg index b9290efcac..280f558d63 100644 --- a/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-pending-search-dialog-google_web_search-.snap.svg +++ b/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-pending-search-dialog-google_web_search-.snap.svg @@ -1,123 +1,31 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ - - ⊷ google_web_search - - - - - Searching... - - ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ + + + + Gemini CLI + v1.2.3 + + + + + + + + + ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ + + ⊷ google_web_search + + + + + Searching... + + ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ \ No newline at end of file diff --git a/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-shell-tool.snap.svg b/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-shell-tool.snap.svg index 0ba0125a62..3dddced46d 100644 --- a/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-shell-tool.snap.svg +++ b/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-a-shell-tool.snap.svg @@ -1,123 +1,31 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ - - ⊷ run_shell_command - - - - - Running command... - - ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ + + + + Gemini CLI + v1.2.3 + + + + + + + + + ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ + + ⊷ run_shell_command + + + + + Running command... + + ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ \ No newline at end of file diff --git a/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-an-empty-slice-following-a-search-tool.snap.svg b/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-an-empty-slice-following-a-search-tool.snap.svg index b9290efcac..280f558d63 100644 --- a/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-an-empty-slice-following-a-search-tool.snap.svg +++ b/packages/cli/src/ui/utils/__snapshots__/borderStyles-MainContent-tool-group-border-SVG-snapshots-should-render-SVG-snapshot-for-an-empty-slice-following-a-search-tool.snap.svg @@ -1,123 +1,31 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ - - ⊷ google_web_search - - - - - Searching... - - ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ + + + + Gemini CLI + v1.2.3 + + + + + + + + + ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ + + ⊷ google_web_search + + + + + Searching... + + ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ \ No newline at end of file diff --git a/packages/cli/src/ui/utils/__snapshots__/borderStyles.test.tsx.snap b/packages/cli/src/ui/utils/__snapshots__/borderStyles.test.tsx.snap index fbdc559480..d34d820236 100644 --- a/packages/cli/src/ui/utils/__snapshots__/borderStyles.test.tsx.snap +++ b/packages/cli/src/ui/utils/__snapshots__/borderStyles.test.tsx.snap @@ -2,14 +2,10 @@ exports[`MainContent tool group border SVG snapshots > should render SVG snapshot for a pending search dialog (google_web_search) 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.2.3 + ▝▜▄ + ▗▟▀ + ▝▀ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊷ google_web_search │ @@ -20,14 +16,10 @@ exports[`MainContent tool group border SVG snapshots > should render SVG snapsho exports[`MainContent tool group border SVG snapshots > should render SVG snapshot for a shell tool 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.2.3 + ▝▜▄ + ▗▟▀ + ▝▀ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊷ run_shell_command │ @@ -38,14 +30,10 @@ exports[`MainContent tool group border SVG snapshots > should render SVG snapsho exports[`MainContent tool group border SVG snapshots > should render SVG snapshot for an empty slice following a search tool 1`] = ` " - ███ █████████ -░░░███ ███░░░░░███ - ░░░███ ███ ░░░ - ░░░███░███ - ███░ ░███ █████ - ███░ ░░███ ░░███ - ███░ ░░█████████ -░░░ ░░░░░░░░░ + ▝▜▄ Gemini CLI v1.2.3 + ▝▜▄ + ▗▟▀ + ▝▀ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊷ google_web_search │ From e7a2b1864b6b1e5a70f6079f6b815929b77222ef Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Fri, 27 Feb 2026 15:37:56 -0800 Subject: [PATCH 09/10] chore: update copyright year --- packages/cli/src/ui/components/AppHeader.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/ui/components/AppHeader.tsx b/packages/cli/src/ui/components/AppHeader.tsx index 26ca8182a0..b9601e772a 100644 --- a/packages/cli/src/ui/components/AppHeader.tsx +++ b/packages/cli/src/ui/components/AppHeader.tsx @@ -1,6 +1,6 @@ /** * @license - * Copyright 2025 Google LLC + * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ From f576e5b55b987221ff0842514676084b78779112 Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Fri, 27 Feb 2026 16:25:23 -0800 Subject: [PATCH 10/10] test(ui): update snapshots and address reviewer feedback --- .../src/ui/__snapshots__/App.test.tsx.snap | 23 ++++---- packages/cli/src/ui/components/Tips.test.tsx | 20 +++---- packages/cli/src/ui/components/Tips.tsx | 40 +++++++++---- .../cli/src/ui/components/UserIdentity.tsx | 6 +- ...ternateBufferQuittingDisplay.test.tsx.snap | 42 +++++++------ .../__snapshots__/AppHeader.test.tsx.snap | 28 +++++---- .../__snapshots__/Tips.test.tsx.snap | 20 +++++++ .../ui/components/shared/HorizontalLine.tsx | 59 ++++--------------- 8 files changed, 123 insertions(+), 115 deletions(-) create mode 100644 packages/cli/src/ui/components/__snapshots__/Tips.test.tsx.snap diff --git a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap index 47bedd41d4..9e1d66df01 100644 --- a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap +++ b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap @@ -9,10 +9,10 @@ exports[`App > Snapshots > renders default layout correctly 1`] = ` Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results - +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results @@ -54,9 +54,10 @@ Footer Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results Composer " `; @@ -113,9 +114,10 @@ exports[`App > should render ToolConfirmationQueue along with Composer when tool Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results HistoryItemDisplay ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Action Required │ @@ -141,7 +143,6 @@ HistoryItemDisplay - Notifications Composer " diff --git a/packages/cli/src/ui/components/Tips.test.tsx b/packages/cli/src/ui/components/Tips.test.tsx index 1730ae81fd..873230fb87 100644 --- a/packages/cli/src/ui/components/Tips.test.tsx +++ b/packages/cli/src/ui/components/Tips.test.tsx @@ -1,28 +1,28 @@ /** * @license - * Copyright 2025 Google LLC + * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { render } from '../../test-utils/render.js'; import { Tips } from './Tips.js'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; import type { Config } from '@google/gemini-cli-core'; describe('Tips', () => { - it('renders correct tips', async () => { - const config = {} as unknown as Config; + it.each([ + { fileCount: 0, description: 'renders all tips including GEMINI.md tip' }, + { fileCount: 5, description: 'renders fewer tips when GEMINI.md exists' }, + ])('$description', async ({ fileCount }) => { + const config = { + getGeminiMdFileCount: vi.fn().mockReturnValue(fileCount), + } as unknown as Config; const { lastFrame, waitUntilReady, unmount } = render( , ); await waitUntilReady(); - const output = lastFrame(); - expect(output).toContain('1. /help for more information'); - expect(output).toContain( - '2. Ask coding questions, edit code or run commands', - ); - expect(output).toContain('3. Be specific for the best results'); + expect(lastFrame()).toMatchSnapshot(); unmount(); }); }); diff --git a/packages/cli/src/ui/components/Tips.tsx b/packages/cli/src/ui/components/Tips.tsx index 94ff8dee6e..8ac6f33bf8 100644 --- a/packages/cli/src/ui/components/Tips.tsx +++ b/packages/cli/src/ui/components/Tips.tsx @@ -1,6 +1,6 @@ /** * @license - * Copyright 2025 Google LLC + * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ @@ -13,15 +13,29 @@ interface TipsProps { config: Config; } -export const Tips: React.FC = () => ( - - Tips for getting started: - - 1. /help for more information - - - 2. Ask coding questions, edit code or run commands - - 3. Be specific for the best results - -); +export const Tips: React.FC = ({ config }) => { + const geminiMdFileCount = config.getGeminiMdFileCount(); + + return ( + + Tips for getting started: + {geminiMdFileCount === 0 && ( + + 1. Create GEMINI.md files to customize your + interactions + + )} + + {geminiMdFileCount === 0 ? '2.' : '1.'}{' '} + /help for more information + + + {geminiMdFileCount === 0 ? '3.' : '2.'} Ask coding questions, edit code + or run commands + + + {geminiMdFileCount === 0 ? '4.' : '3.'} Be specific for the best results + + + ); +}; diff --git a/packages/cli/src/ui/components/UserIdentity.tsx b/packages/cli/src/ui/components/UserIdentity.tsx index 753fcd2abd..08c82573d9 100644 --- a/packages/cli/src/ui/components/UserIdentity.tsx +++ b/packages/cli/src/ui/components/UserIdentity.tsx @@ -1,6 +1,6 @@ /** * @license - * Copyright 2025 Google LLC + * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ @@ -42,7 +42,7 @@ export const UserIdentity: React.FC = ({ config }) => { {/* User Email /auth */} - + {authType === AuthType.LOGIN_WITH_GOOGLE ? ( {email ?? 'Logged in with Google'} ) : ( @@ -54,7 +54,7 @@ export const UserIdentity: React.FC = ({ config }) => { {/* Tier Name /upgrade */} - + {tierName ?? 'Gemini Code Assist for individuals'} /upgrade diff --git a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap index ed20cded7c..ec8712ebc1 100644 --- a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap @@ -9,9 +9,10 @@ exports[`AlternateBufferQuittingDisplay > renders with a tool awaiting confirmat Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results Action Required (was prompted): @@ -28,9 +29,10 @@ exports[`AlternateBufferQuittingDisplay > renders with active and pending tool m Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool1 Description for tool 1 │ │ │ @@ -51,9 +53,10 @@ exports[`AlternateBufferQuittingDisplay > renders with empty history and no pend Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results " `; @@ -66,9 +69,10 @@ exports[`AlternateBufferQuittingDisplay > renders with history but no pending it Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results ╭──────────────────────────────────────────────────────────────────────────╮ │ ✓ tool1 Description for tool 1 │ │ │ @@ -89,9 +93,10 @@ exports[`AlternateBufferQuittingDisplay > renders with pending items but no hist Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results " `; @@ -104,9 +109,10 @@ exports[`AlternateBufferQuittingDisplay > renders with user and gemini messages Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ > Hello Gemini ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ diff --git a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap index 42a6488176..4411f766de 100644 --- a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap @@ -9,9 +9,10 @@ exports[` > should not render the banner when no flags are set 1`] Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results " `; @@ -24,9 +25,10 @@ exports[` > should not render the default banner if shown count is Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results " `; @@ -42,9 +44,10 @@ exports[` > should render the banner with default text 1`] = ` ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results " `; @@ -60,8 +63,9 @@ exports[` > should render the banner with warning text 1`] = ` ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ Tips for getting started: -1. /help for more information -2. Ask coding questions, edit code or run commands -3. Be specific for the best results +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results " `; diff --git a/packages/cli/src/ui/components/__snapshots__/Tips.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/Tips.test.tsx.snap new file mode 100644 index 0000000000..dbc60fcf4d --- /dev/null +++ b/packages/cli/src/ui/components/__snapshots__/Tips.test.tsx.snap @@ -0,0 +1,20 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Tips > 'renders all tips including GEMINI.md …' 1`] = ` +" +Tips for getting started: +1. Create GEMINI.md files to customize your interactions +2. /help for more information +3. Ask coding questions, edit code or run commands +4. Be specific for the best results +" +`; + +exports[`Tips > 'renders fewer tips when GEMINI.md exi…' 1`] = ` +" +Tips for getting started: +1. /help for more information +2. Ask coding questions, edit code or run commands +3. Be specific for the best results +" +`; diff --git a/packages/cli/src/ui/components/shared/HorizontalLine.tsx b/packages/cli/src/ui/components/shared/HorizontalLine.tsx index f2463c404e..92935617a7 100644 --- a/packages/cli/src/ui/components/shared/HorizontalLine.tsx +++ b/packages/cli/src/ui/components/shared/HorizontalLine.tsx @@ -8,57 +8,20 @@ import type React from 'react'; import { Box } from 'ink'; import { theme } from '../../semantic-colors.js'; -export type LinePosition = 'top' | 'center' | 'bottom'; - interface HorizontalLineProps { color?: string; - width?: number | string; - position?: LinePosition; } -const overlineStyle = { - top: '‾', - bottom: '', - left: '', - right: '', - topLeft: '', - topRight: '', - bottomLeft: '', - bottomRight: '', -}; - -const underlineStyle = { - top: '_', - bottom: '', - left: '', - right: '', - topLeft: '', - topRight: '', - bottomLeft: '', - bottomRight: '', -}; - export const HorizontalLine: React.FC = ({ color = theme.border.default, - width = '100%', - position = 'center', -}) => { - const borderStyle = - position === 'top' - ? overlineStyle - : position === 'bottom' - ? underlineStyle - : 'single'; - - return ( - - ); -}; +}) => ( + +);