From ab1c483cab659ac2ab081e74a0e3bd0fcc48a734 Mon Sep 17 00:00:00 2001 From: Evan Otero Date: Fri, 15 Aug 2025 12:32:15 -0400 Subject: [PATCH] feat(about): Add the IDE Client's display name to `/about` (#6311) Co-authored-by: Bryan Morgan --- .../cli/src/ui/commands/aboutCommand.test.ts | 34 +++++++++++++++++++ packages/cli/src/ui/commands/aboutCommand.ts | 4 +++ packages/cli/src/ui/components/AboutBox.tsx | 14 ++++++++ .../ui/components/HistoryItemDisplay.test.tsx | 1 + .../src/ui/components/HistoryItemDisplay.tsx | 1 + .../cli/src/ui/hooks/slashCommandProcessor.ts | 1 + packages/cli/src/ui/types.ts | 2 ++ 7 files changed, 57 insertions(+) diff --git a/packages/cli/src/ui/commands/aboutCommand.test.ts b/packages/cli/src/ui/commands/aboutCommand.test.ts index 43cd59ec..27e96755 100644 --- a/packages/cli/src/ui/commands/aboutCommand.test.ts +++ b/packages/cli/src/ui/commands/aboutCommand.test.ts @@ -11,6 +11,8 @@ import { createMockCommandContext } from '../../test-utils/mockCommandContext.js import * as versionUtils from '../../utils/version.js'; import { MessageType } from '../types.js'; +import { IdeClient } from '../../../../core/src/ide/ide-client.js'; + vi.mock('../../utils/version.js', () => ({ getCliVersion: vi.fn(), })); @@ -25,6 +27,7 @@ describe('aboutCommand', () => { services: { config: { getModel: vi.fn(), + getIdeClient: vi.fn(), }, settings: { merged: { @@ -45,6 +48,9 @@ describe('aboutCommand', () => { Object.defineProperty(process, 'platform', { value: 'test-os', }); + vi.spyOn(mockContext.services.config!, 'getIdeClient').mockReturnValue({ + getDetectedIdeDisplayName: vi.fn().mockReturnValue('test-ide'), + } as Partial as IdeClient); }); afterEach(() => { @@ -78,6 +84,7 @@ describe('aboutCommand', () => { modelVersion: 'test-model', selectedAuthType: 'test-auth', gcpProject: 'test-gcp-project', + ideClient: 'test-ide', }, expect.any(Number), ); @@ -115,4 +122,31 @@ describe('aboutCommand', () => { expect.any(Number), ); }); + + it('should not show ide client when it is not detected', async () => { + vi.spyOn(mockContext.services.config!, 'getIdeClient').mockReturnValue({ + getDetectedIdeDisplayName: vi.fn().mockReturnValue(undefined), + } as Partial as IdeClient); + + process.env.SANDBOX = ''; + if (!aboutCommand.action) { + throw new Error('The about command must have an action.'); + } + + await aboutCommand.action(mockContext, ''); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + expect.objectContaining({ + type: MessageType.ABOUT, + cliVersion: 'test-version', + osVersion: 'test-os', + sandboxEnv: 'no sandbox', + modelVersion: 'test-model', + selectedAuthType: 'test-auth', + gcpProject: 'test-gcp-project', + ideClient: '', + }), + expect.any(Number), + ); + }); }); diff --git a/packages/cli/src/ui/commands/aboutCommand.ts b/packages/cli/src/ui/commands/aboutCommand.ts index 18a82682..47b1b495 100644 --- a/packages/cli/src/ui/commands/aboutCommand.ts +++ b/packages/cli/src/ui/commands/aboutCommand.ts @@ -28,6 +28,9 @@ export const aboutCommand: SlashCommand = { const selectedAuthType = context.services.settings.merged.selectedAuthType || ''; const gcpProject = process.env.GOOGLE_CLOUD_PROJECT || ''; + const ideClient = + context.services.config?.getIdeClient()?.getDetectedIdeDisplayName() || + ''; const aboutItem: Omit = { type: MessageType.ABOUT, @@ -37,6 +40,7 @@ export const aboutCommand: SlashCommand = { modelVersion, selectedAuthType, gcpProject, + ideClient, }; context.ui.addItem(aboutItem, Date.now()); diff --git a/packages/cli/src/ui/components/AboutBox.tsx b/packages/cli/src/ui/components/AboutBox.tsx index 71afbdd4..a0954576 100644 --- a/packages/cli/src/ui/components/AboutBox.tsx +++ b/packages/cli/src/ui/components/AboutBox.tsx @@ -16,6 +16,7 @@ interface AboutBoxProps { modelVersion: string; selectedAuthType: string; gcpProject: string; + ideClient: string; } export const AboutBox: React.FC = ({ @@ -25,6 +26,7 @@ export const AboutBox: React.FC = ({ modelVersion, selectedAuthType, gcpProject, + ideClient, }) => ( = ({ )} + {ideClient && ( + + + + IDE Client + + + + {ideClient} + + + )} ); diff --git a/packages/cli/src/ui/components/HistoryItemDisplay.test.tsx b/packages/cli/src/ui/components/HistoryItemDisplay.test.tsx index f806abd6..234ca968 100644 --- a/packages/cli/src/ui/components/HistoryItemDisplay.test.tsx +++ b/packages/cli/src/ui/components/HistoryItemDisplay.test.tsx @@ -71,6 +71,7 @@ describe('', () => { modelVersion: 'test-model', selectedAuthType: 'test-auth', gcpProject: 'test-project', + ideClient: 'test-ide', }; const { lastFrame } = render( , diff --git a/packages/cli/src/ui/components/HistoryItemDisplay.tsx b/packages/cli/src/ui/components/HistoryItemDisplay.tsx index 74615b26..89dd0149 100644 --- a/packages/cli/src/ui/components/HistoryItemDisplay.tsx +++ b/packages/cli/src/ui/components/HistoryItemDisplay.tsx @@ -73,6 +73,7 @@ export const HistoryItemDisplay: React.FC = ({ modelVersion={item.modelVersion} selectedAuthType={item.selectedAuthType} gcpProject={item.gcpProject} + ideClient={item.ideClient} /> )} {item.type === 'help' && commands && } diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts index 8ae0041e..d1af9964 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts @@ -116,6 +116,7 @@ export const useSlashCommandProcessor = ( modelVersion: message.modelVersion, selectedAuthType: message.selectedAuthType, gcpProject: message.gcpProject, + ideClient: message.ideClient, }; } else if (message.type === MessageType.HELP) { historyItemContent = { diff --git a/packages/cli/src/ui/types.ts b/packages/cli/src/ui/types.ts index b52bf64d..f798283a 100644 --- a/packages/cli/src/ui/types.ts +++ b/packages/cli/src/ui/types.ts @@ -95,6 +95,7 @@ export type HistoryItemAbout = HistoryItemBase & { modelVersion: string; selectedAuthType: string; gcpProject: string; + ideClient: string; }; export type HistoryItemHelp = HistoryItemBase & { @@ -188,6 +189,7 @@ export type Message = modelVersion: string; selectedAuthType: string; gcpProject: string; + ideClient: string; content?: string; // Optional content, not really used for ABOUT } | {