feat(about): Add the IDE Client's display name to `/about` (#6311)

Co-authored-by: Bryan Morgan <bryanmorgan@google.com>
This commit is contained in:
Evan Otero 2025-08-15 12:32:15 -04:00 committed by GitHub
parent 72195d5553
commit ab1c483cab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 57 additions and 0 deletions

View File

@ -11,6 +11,8 @@ import { createMockCommandContext } from '../../test-utils/mockCommandContext.js
import * as versionUtils from '../../utils/version.js'; import * as versionUtils from '../../utils/version.js';
import { MessageType } from '../types.js'; import { MessageType } from '../types.js';
import { IdeClient } from '../../../../core/src/ide/ide-client.js';
vi.mock('../../utils/version.js', () => ({ vi.mock('../../utils/version.js', () => ({
getCliVersion: vi.fn(), getCliVersion: vi.fn(),
})); }));
@ -25,6 +27,7 @@ describe('aboutCommand', () => {
services: { services: {
config: { config: {
getModel: vi.fn(), getModel: vi.fn(),
getIdeClient: vi.fn(),
}, },
settings: { settings: {
merged: { merged: {
@ -45,6 +48,9 @@ describe('aboutCommand', () => {
Object.defineProperty(process, 'platform', { Object.defineProperty(process, 'platform', {
value: 'test-os', value: 'test-os',
}); });
vi.spyOn(mockContext.services.config!, 'getIdeClient').mockReturnValue({
getDetectedIdeDisplayName: vi.fn().mockReturnValue('test-ide'),
} as Partial<IdeClient> as IdeClient);
}); });
afterEach(() => { afterEach(() => {
@ -78,6 +84,7 @@ describe('aboutCommand', () => {
modelVersion: 'test-model', modelVersion: 'test-model',
selectedAuthType: 'test-auth', selectedAuthType: 'test-auth',
gcpProject: 'test-gcp-project', gcpProject: 'test-gcp-project',
ideClient: 'test-ide',
}, },
expect.any(Number), expect.any(Number),
); );
@ -115,4 +122,31 @@ describe('aboutCommand', () => {
expect.any(Number), 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<IdeClient> 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),
);
});
}); });

View File

@ -28,6 +28,9 @@ export const aboutCommand: SlashCommand = {
const selectedAuthType = const selectedAuthType =
context.services.settings.merged.selectedAuthType || ''; context.services.settings.merged.selectedAuthType || '';
const gcpProject = process.env.GOOGLE_CLOUD_PROJECT || ''; const gcpProject = process.env.GOOGLE_CLOUD_PROJECT || '';
const ideClient =
context.services.config?.getIdeClient()?.getDetectedIdeDisplayName() ||
'';
const aboutItem: Omit<HistoryItemAbout, 'id'> = { const aboutItem: Omit<HistoryItemAbout, 'id'> = {
type: MessageType.ABOUT, type: MessageType.ABOUT,
@ -37,6 +40,7 @@ export const aboutCommand: SlashCommand = {
modelVersion, modelVersion,
selectedAuthType, selectedAuthType,
gcpProject, gcpProject,
ideClient,
}; };
context.ui.addItem(aboutItem, Date.now()); context.ui.addItem(aboutItem, Date.now());

View File

@ -16,6 +16,7 @@ interface AboutBoxProps {
modelVersion: string; modelVersion: string;
selectedAuthType: string; selectedAuthType: string;
gcpProject: string; gcpProject: string;
ideClient: string;
} }
export const AboutBox: React.FC<AboutBoxProps> = ({ export const AboutBox: React.FC<AboutBoxProps> = ({
@ -25,6 +26,7 @@ export const AboutBox: React.FC<AboutBoxProps> = ({
modelVersion, modelVersion,
selectedAuthType, selectedAuthType,
gcpProject, gcpProject,
ideClient,
}) => ( }) => (
<Box <Box
borderStyle="round" borderStyle="round"
@ -115,5 +117,17 @@ export const AboutBox: React.FC<AboutBoxProps> = ({
</Box> </Box>
</Box> </Box>
)} )}
{ideClient && (
<Box flexDirection="row">
<Box width="35%">
<Text bold color={Colors.LightBlue}>
IDE Client
</Text>
</Box>
<Box>
<Text>{ideClient}</Text>
</Box>
</Box>
)}
</Box> </Box>
); );

View File

@ -71,6 +71,7 @@ describe('<HistoryItemDisplay />', () => {
modelVersion: 'test-model', modelVersion: 'test-model',
selectedAuthType: 'test-auth', selectedAuthType: 'test-auth',
gcpProject: 'test-project', gcpProject: 'test-project',
ideClient: 'test-ide',
}; };
const { lastFrame } = render( const { lastFrame } = render(
<HistoryItemDisplay {...baseItem} item={item} />, <HistoryItemDisplay {...baseItem} item={item} />,

View File

@ -73,6 +73,7 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
modelVersion={item.modelVersion} modelVersion={item.modelVersion}
selectedAuthType={item.selectedAuthType} selectedAuthType={item.selectedAuthType}
gcpProject={item.gcpProject} gcpProject={item.gcpProject}
ideClient={item.ideClient}
/> />
)} )}
{item.type === 'help' && commands && <Help commands={commands} />} {item.type === 'help' && commands && <Help commands={commands} />}

View File

@ -116,6 +116,7 @@ export const useSlashCommandProcessor = (
modelVersion: message.modelVersion, modelVersion: message.modelVersion,
selectedAuthType: message.selectedAuthType, selectedAuthType: message.selectedAuthType,
gcpProject: message.gcpProject, gcpProject: message.gcpProject,
ideClient: message.ideClient,
}; };
} else if (message.type === MessageType.HELP) { } else if (message.type === MessageType.HELP) {
historyItemContent = { historyItemContent = {

View File

@ -95,6 +95,7 @@ export type HistoryItemAbout = HistoryItemBase & {
modelVersion: string; modelVersion: string;
selectedAuthType: string; selectedAuthType: string;
gcpProject: string; gcpProject: string;
ideClient: string;
}; };
export type HistoryItemHelp = HistoryItemBase & { export type HistoryItemHelp = HistoryItemBase & {
@ -188,6 +189,7 @@ export type Message =
modelVersion: string; modelVersion: string;
selectedAuthType: string; selectedAuthType: string;
gcpProject: string; gcpProject: string;
ideClient: string;
content?: string; // Optional content, not really used for ABOUT content?: string; // Optional content, not really used for ABOUT
} }
| { | {