summaryrefslogtreecommitdiff
path: root/packages/cli/src
diff options
context:
space:
mode:
authorAbhi <[email protected]>2025-07-15 02:22:46 -0400
committerGitHub <[email protected]>2025-07-15 06:22:46 +0000
commit6e258e28508e2862c0a7f7be40b5ab6fd725f453 (patch)
tree0b4d6a994d4b4340bf7d7395b3dd2637877a4434 /packages/cli/src
parent2862ae7344db11f3de96b9b13fcc6c98b19f5b26 (diff)
migrate /about (#4207)
Diffstat (limited to 'packages/cli/src')
-rw-r--r--packages/cli/src/services/CommandService.test.ts14
-rw-r--r--packages/cli/src/services/CommandService.ts2
-rw-r--r--packages/cli/src/ui/commands/aboutCommand.test.ts117
-rw-r--r--packages/cli/src/ui/commands/aboutCommand.ts43
-rw-r--r--packages/cli/src/ui/hooks/slashCommandProcessor.test.ts83
-rw-r--r--packages/cli/src/ui/hooks/slashCommandProcessor.ts30
6 files changed, 172 insertions, 117 deletions
diff --git a/packages/cli/src/services/CommandService.test.ts b/packages/cli/src/services/CommandService.test.ts
index 1a62c904..e780ec5f 100644
--- a/packages/cli/src/services/CommandService.test.ts
+++ b/packages/cli/src/services/CommandService.test.ts
@@ -13,6 +13,7 @@ import { clearCommand } from '../ui/commands/clearCommand.js';
import { authCommand } from '../ui/commands/authCommand.js';
import { themeCommand } from '../ui/commands/themeCommand.js';
import { privacyCommand } from '../ui/commands/privacyCommand.js';
+import { aboutCommand } from '../ui/commands/aboutCommand.js';
// Mock the command modules to isolate the service from the command implementations.
vi.mock('../ui/commands/memoryCommand.js', () => ({
@@ -33,6 +34,9 @@ vi.mock('../ui/commands/themeCommand.js', () => ({
vi.mock('../ui/commands/privacyCommand.js', () => ({
privacyCommand: { name: 'privacy', description: 'Mock Privacy' },
}));
+vi.mock('../ui/commands/aboutCommand.js', () => ({
+ aboutCommand: { name: 'about', description: 'Mock About' },
+}));
describe('CommandService', () => {
describe('when using default production loader', () => {
@@ -58,7 +62,7 @@ describe('CommandService', () => {
const tree = commandService.getCommands();
// Post-condition assertions
- expect(tree.length).toBe(6);
+ expect(tree.length).toBe(7);
const commandNames = tree.map((cmd) => cmd.name);
expect(commandNames).toContain('auth');
@@ -67,19 +71,20 @@ describe('CommandService', () => {
expect(commandNames).toContain('clear');
expect(commandNames).toContain('theme');
expect(commandNames).toContain('privacy');
+ expect(commandNames).toContain('about');
});
it('should overwrite any existing commands when called again', async () => {
// Load once
await commandService.loadCommands();
- expect(commandService.getCommands().length).toBe(6);
+ expect(commandService.getCommands().length).toBe(7);
// Load again
await commandService.loadCommands();
const tree = commandService.getCommands();
// Should not append, but overwrite
- expect(tree.length).toBe(6);
+ expect(tree.length).toBe(7);
});
});
@@ -91,8 +96,9 @@ describe('CommandService', () => {
await commandService.loadCommands();
const loadedTree = commandService.getCommands();
- expect(loadedTree.length).toBe(6);
+ expect(loadedTree.length).toBe(7);
expect(loadedTree).toEqual([
+ aboutCommand,
authCommand,
clearCommand,
helpCommand,
diff --git a/packages/cli/src/services/CommandService.ts b/packages/cli/src/services/CommandService.ts
index 0e2a8acb..ef31952d 100644
--- a/packages/cli/src/services/CommandService.ts
+++ b/packages/cli/src/services/CommandService.ts
@@ -11,8 +11,10 @@ import { clearCommand } from '../ui/commands/clearCommand.js';
import { authCommand } from '../ui/commands/authCommand.js';
import { themeCommand } from '../ui/commands/themeCommand.js';
import { privacyCommand } from '../ui/commands/privacyCommand.js';
+import { aboutCommand } from '../ui/commands/aboutCommand.js';
const loadBuiltInCommands = async (): Promise<SlashCommand[]> => [
+ aboutCommand,
authCommand,
clearCommand,
helpCommand,
diff --git a/packages/cli/src/ui/commands/aboutCommand.test.ts b/packages/cli/src/ui/commands/aboutCommand.test.ts
new file mode 100644
index 00000000..48dd6db3
--- /dev/null
+++ b/packages/cli/src/ui/commands/aboutCommand.test.ts
@@ -0,0 +1,117 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
+import { aboutCommand } from './aboutCommand.js';
+import { type CommandContext } from './types.js';
+import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
+import * as versionUtils from '../../utils/version.js';
+import { MessageType } from '../types.js';
+
+vi.mock('../../utils/version.js', () => ({
+ getCliVersion: vi.fn(),
+}));
+
+describe('aboutCommand', () => {
+ let mockContext: CommandContext;
+ const originalPlatform = process.platform;
+ const originalEnv = { ...process.env };
+
+ beforeEach(() => {
+ mockContext = createMockCommandContext({
+ services: {
+ config: {
+ getModel: vi.fn(),
+ },
+ settings: {
+ merged: {
+ selectedAuthType: 'test-auth',
+ },
+ },
+ },
+ ui: {
+ addItem: vi.fn(),
+ },
+ } as unknown as CommandContext);
+
+ vi.mocked(versionUtils.getCliVersion).mockResolvedValue('test-version');
+ vi.spyOn(mockContext.services.config!, 'getModel').mockReturnValue(
+ 'test-model',
+ );
+ process.env.GOOGLE_CLOUD_PROJECT = 'test-gcp-project';
+ Object.defineProperty(process, 'platform', {
+ value: 'test-os',
+ });
+ });
+
+ afterEach(() => {
+ vi.unstubAllEnvs();
+ Object.defineProperty(process, 'platform', {
+ value: originalPlatform,
+ });
+ process.env = originalEnv;
+ vi.clearAllMocks();
+ });
+
+ it('should have the correct name and description', () => {
+ expect(aboutCommand.name).toBe('about');
+ expect(aboutCommand.description).toBe('show version info');
+ });
+
+ it('should call addItem with all version info', async () => {
+ if (!aboutCommand.action) {
+ throw new Error('The about command must have an action.');
+ }
+
+ await aboutCommand.action(mockContext, '');
+
+ expect(mockContext.ui.addItem).toHaveBeenCalledWith(
+ {
+ type: MessageType.ABOUT,
+ cliVersion: 'test-version',
+ osVersion: 'test-os',
+ sandboxEnv: 'no sandbox',
+ modelVersion: 'test-model',
+ selectedAuthType: 'test-auth',
+ gcpProject: 'test-gcp-project',
+ },
+ expect.any(Number),
+ );
+ });
+
+ it('should show the correct sandbox environment variable', async () => {
+ process.env.SANDBOX = 'gemini-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({
+ sandboxEnv: 'gemini-sandbox',
+ }),
+ expect.any(Number),
+ );
+ });
+
+ it('should show sandbox-exec profile when applicable', async () => {
+ process.env.SANDBOX = 'sandbox-exec';
+ process.env.SEATBELT_PROFILE = 'test-profile';
+ if (!aboutCommand.action) {
+ throw new Error('The about command must have an action.');
+ }
+
+ await aboutCommand.action(mockContext, '');
+
+ expect(mockContext.ui.addItem).toHaveBeenCalledWith(
+ expect.objectContaining({
+ sandboxEnv: 'sandbox-exec (test-profile)',
+ }),
+ expect.any(Number),
+ );
+ });
+});
diff --git a/packages/cli/src/ui/commands/aboutCommand.ts b/packages/cli/src/ui/commands/aboutCommand.ts
new file mode 100644
index 00000000..3cb8c2f6
--- /dev/null
+++ b/packages/cli/src/ui/commands/aboutCommand.ts
@@ -0,0 +1,43 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { getCliVersion } from '../../utils/version.js';
+import { SlashCommand } from './types.js';
+import process from 'node:process';
+import { MessageType, type HistoryItemAbout } from '../types.js';
+
+export const aboutCommand: SlashCommand = {
+ name: 'about',
+ description: 'show version info',
+ action: async (context) => {
+ const osVersion = process.platform;
+ let sandboxEnv = 'no sandbox';
+ if (process.env.SANDBOX && process.env.SANDBOX !== 'sandbox-exec') {
+ sandboxEnv = process.env.SANDBOX;
+ } else if (process.env.SANDBOX === 'sandbox-exec') {
+ sandboxEnv = `sandbox-exec (${
+ process.env.SEATBELT_PROFILE || 'unknown'
+ })`;
+ }
+ const modelVersion = context.services.config?.getModel() || 'Unknown';
+ const cliVersion = await getCliVersion();
+ const selectedAuthType =
+ context.services.settings.merged.selectedAuthType || '';
+ const gcpProject = process.env.GOOGLE_CLOUD_PROJECT || '';
+
+ const aboutItem: Omit<HistoryItemAbout, 'id'> = {
+ type: MessageType.ABOUT,
+ cliVersion,
+ osVersion,
+ sandboxEnv,
+ modelVersion,
+ selectedAuthType,
+ gcpProject,
+ };
+
+ context.ui.addItem(aboutItem, Date.now());
+ },
+};
diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts
index d920117d..6946bde0 100644
--- a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts
+++ b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts
@@ -277,89 +277,6 @@ describe('useSlashCommandProcessor', () => {
});
});
- describe('/about command', () => {
- it('should show the about box with all details including auth and project', async () => {
- // Arrange
- mockGetCliVersionFn.mockResolvedValue('test-version');
- process.env.SANDBOX = 'gemini-sandbox';
- process.env.GOOGLE_CLOUD_PROJECT = 'test-gcp-project';
- vi.mocked(mockConfig.getModel).mockReturnValue('test-model-from-config');
-
- const settings = {
- merged: {
- selectedAuthType: 'test-auth-type',
- contextFileName: 'GEMINI.md',
- },
- } as unknown as LoadedSettings;
-
- const { result } = renderHook(() =>
- useSlashCommandProcessor(
- mockConfig,
- settings,
- [],
- mockAddItem,
- mockClearItems,
- mockLoadHistory,
- mockRefreshStatic,
- mockSetShowHelp,
- mockOnDebugMessage,
- mockOpenThemeDialog,
- mockOpenAuthDialog,
- mockOpenEditorDialog,
- mockCorgiMode,
- false,
- mockSetQuittingMessages,
- vi.fn(), // mockOpenPrivacyNotice
- ),
- );
-
- // Act
- await act(async () => {
- await result.current.handleSlashCommand('/about');
- });
-
- // Assert
- expect(mockAddItem).toHaveBeenCalledTimes(2); // user message + about message
- expect(mockAddItem).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({
- type: 'about',
- cliVersion: 'test-version',
- osVersion: 'test-platform',
- sandboxEnv: 'gemini-sandbox',
- modelVersion: 'test-model-from-config',
- selectedAuthType: 'test-auth-type',
- gcpProject: 'test-gcp-project',
- }),
- expect.any(Number),
- );
- });
-
- it('should show sandbox-exec profile when applicable', async () => {
- // Arrange
- mockGetCliVersionFn.mockResolvedValue('test-version');
- process.env.SANDBOX = 'sandbox-exec';
- process.env.SEATBELT_PROFILE = 'test-profile';
- vi.mocked(mockConfig.getModel).mockReturnValue('test-model-from-config');
-
- const { result } = getProcessorHook();
-
- // Act
- await act(async () => {
- await result.current.handleSlashCommand('/about');
- });
-
- // Assert
- expect(mockAddItem).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({
- sandboxEnv: 'sandbox-exec (test-profile)',
- }),
- expect.any(Number),
- );
- });
- });
-
describe('Other commands', () => {
it('/editor should open editor dialog and return handled', async () => {
const { handleSlashCommand } = getProcessor();
diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts
index 6465a49d..e8d773b4 100644
--- a/packages/cli/src/ui/hooks/slashCommandProcessor.ts
+++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts
@@ -585,35 +585,6 @@ export const useSlashCommandProcessor = (
},
},
{
- name: 'about',
- description: 'show version info',
- action: async (_mainCommand, _subCommand, _args) => {
- const osVersion = process.platform;
- let sandboxEnv = 'no sandbox';
- if (process.env.SANDBOX && process.env.SANDBOX !== 'sandbox-exec') {
- sandboxEnv = process.env.SANDBOX;
- } else if (process.env.SANDBOX === 'sandbox-exec') {
- sandboxEnv = `sandbox-exec (${
- process.env.SEATBELT_PROFILE || 'unknown'
- })`;
- }
- const modelVersion = config?.getModel() || 'Unknown';
- const cliVersion = await getCliVersion();
- const selectedAuthType = settings.merged.selectedAuthType || '';
- const gcpProject = process.env.GOOGLE_CLOUD_PROJECT || '';
- addMessage({
- type: MessageType.ABOUT,
- timestamp: new Date(),
- cliVersion,
- osVersion,
- sandboxEnv,
- modelVersion,
- selectedAuthType,
- gcpProject,
- });
- },
- },
- {
name: 'bug',
description: 'submit a bug report',
action: async (_mainCommand, _subCommand, args) => {
@@ -1021,7 +992,6 @@ export const useSlashCommandProcessor = (
toggleCorgiMode,
savedChatTags,
config,
- settings,
showToolDescriptions,
session,
gitService,