From 41a12e13bbf7679a9c5210c5853e009449aca6a5 Mon Sep 17 00:00:00 2001 From: "gemini-cli[bot]" Date: Wed, 13 May 2026 19:29:31 +0000 Subject: [PATCH] feat(ui): implement compact version tags in AppHeader Long nightly and pre-release version strings (e.g., `0.42.0-nightly.20260428.g59b2dea0e`) were causing UI clutter and layout issues, especially on narrow terminals. This change: - Parses the version string to extract the base version and the first pre-release tag. - Renders the tag in a compact format `[tag]` with dimmed color. - Reduces the horizontal footprint of the header metadata. Verified with new unit tests in `AppHeader.test.tsx` and manual inspection of Ink output snapshots. cc @gundermanc Label: bot-fix --- .../cli/src/ui/components/AppHeader.test.tsx | 39 ++++++++++++++++++- packages/cli/src/ui/components/AppHeader.tsx | 15 ++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/ui/components/AppHeader.test.tsx b/packages/cli/src/ui/components/AppHeader.test.tsx index 2fab08c8e6..f7d3ce70c3 100644 --- a/packages/cli/src/ui/components/AppHeader.test.tsx +++ b/packages/cli/src/ui/components/AppHeader.test.tsx @@ -11,7 +11,7 @@ import { import type { LoadedSettings } from '../../config/settings.js'; import { AppHeader } from './AppHeader.js'; import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { makeFakeConfig } from '@google/gemini-cli-core'; +import { makeFakeConfig, type ContentGeneratorConfig } from '@google/gemini-cli-core'; import crypto from 'node:crypto'; import { _clearSessionBannersForTest } from '../hooks/useBanner.js'; @@ -252,7 +252,7 @@ describe('', () => { const mockConfig = makeFakeConfig(); vi.spyOn(mockConfig, 'getContentGeneratorConfig').mockReturnValue({ authType: undefined, - } as any); // eslint-disable-line @typescript-eslint/no-explicit-any + } as ContentGeneratorConfig); const { lastFrame, waitUntilReady, unmount } = await renderWithProviders( , @@ -289,4 +289,39 @@ describe('', () => { expect(lastFrame()).not.toContain('Tips'); unmount(); }); + + it('should render compact version tags for nightly builds', async () => { + const { lastFrame, unmount } = await renderWithProviders( + , + {}, + ); + + expect(lastFrame()).toContain('v0.42.0'); + expect(lastFrame()).toContain('[nightly]'); + expect(lastFrame()).not.toContain('20260428'); + unmount(); + }); + + it('should render compact version tags for alpha builds', async () => { + const { lastFrame, unmount } = await renderWithProviders( + , + {}, + ); + + expect(lastFrame()).toContain('v1.0.0'); + expect(lastFrame()).toContain('[alpha]'); + unmount(); + }); + + it('should render normal versions without tags', async () => { + const { lastFrame, unmount } = await renderWithProviders( + , + {}, + ); + + expect(lastFrame()).toContain('v1.2.3'); + expect(lastFrame()).not.toContain('['); + expect(lastFrame()).not.toContain(']'); + unmount(); + }); }); diff --git a/packages/cli/src/ui/components/AppHeader.tsx b/packages/cli/src/ui/components/AppHeader.tsx index 1b3d9b2cfa..ec134ce930 100644 --- a/packages/cli/src/ui/components/AppHeader.tsx +++ b/packages/cli/src/ui/components/AppHeader.tsx @@ -90,6 +90,13 @@ export const AppHeader = ({ version, showDetails = true }: AppHeaderProps) => { } } + // Parse version string (e.g., 0.42.0-nightly.20260428.g59b2dea0e) + // to extract the base version and the tag. + const versionParts = version.split('-'); + const baseVersion = versionParts[0]; + const tagPart = versionParts.slice(1).join('-'); + const tag = tagPart ? tagPart.split('.')[0] : ''; + // If the terminal is too narrow to fit the icon and metadata (especially long nightly versions) // side-by-side, we switch to column mode to prevent wrapping. const isNarrow = terminalWidth < NARROW_TERMINAL_BREAKPOINT; @@ -114,7 +121,13 @@ export const AppHeader = ({ version, showDetails = true }: AppHeaderProps) => { Gemini CLI - v{version} + v{baseVersion} + {tag && ( + + {' '} + [{tag}] + + )} {updateInfo?.isUpdating && (