diff options
Diffstat (limited to 'packages/cli/src/ui')
| -rw-r--r-- | packages/cli/src/ui/commands/docsCommand.test.ts | 99 | ||||
| -rw-r--r-- | packages/cli/src/ui/commands/docsCommand.ts | 37 | ||||
| -rw-r--r-- | packages/cli/src/ui/hooks/slashCommandProcessor.ts | 21 |
3 files changed, 136 insertions, 21 deletions
diff --git a/packages/cli/src/ui/commands/docsCommand.test.ts b/packages/cli/src/ui/commands/docsCommand.test.ts new file mode 100644 index 00000000..73b7396a --- /dev/null +++ b/packages/cli/src/ui/commands/docsCommand.test.ts @@ -0,0 +1,99 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'; +import open from 'open'; +import { docsCommand } from './docsCommand.js'; +import { type CommandContext } from './types.js'; +import { createMockCommandContext } from '../../test-utils/mockCommandContext.js'; +import { MessageType } from '../types.js'; + +// Mock the 'open' library +vi.mock('open', () => ({ + default: vi.fn(), +})); + +describe('docsCommand', () => { + let mockContext: CommandContext; + beforeEach(() => { + // Create a fresh mock context before each test + mockContext = createMockCommandContext(); + // Reset the `open` mock + vi.mocked(open).mockClear(); + }); + + afterEach(() => { + // Restore any stubbed environment variables + vi.unstubAllEnvs(); + }); + + it("should add an info message and call 'open' in a non-sandbox environment", async () => { + if (!docsCommand.action) { + throw new Error('docsCommand must have an action.'); + } + + const docsUrl = 'https://goo.gle/gemini-cli-docs'; + + await docsCommand.action(mockContext, ''); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.INFO, + text: `Opening documentation in your browser: ${docsUrl}`, + }, + expect.any(Number), + ); + + expect(open).toHaveBeenCalledWith(docsUrl); + }); + + it('should only add an info message in a sandbox environment', async () => { + if (!docsCommand.action) { + throw new Error('docsCommand must have an action.'); + } + + // Simulate a sandbox environment + process.env.SANDBOX = 'gemini-sandbox'; + const docsUrl = 'https://goo.gle/gemini-cli-docs'; + + await docsCommand.action(mockContext, ''); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.INFO, + text: `Please open the following URL in your browser to view the documentation:\n${docsUrl}`, + }, + expect.any(Number), + ); + + // Ensure 'open' was not called in the sandbox + expect(open).not.toHaveBeenCalled(); + }); + + it("should not open browser for 'sandbox-exec'", async () => { + if (!docsCommand.action) { + throw new Error('docsCommand must have an action.'); + } + + // Simulate the specific 'sandbox-exec' environment + process.env.SANDBOX = 'sandbox-exec'; + const docsUrl = 'https://goo.gle/gemini-cli-docs'; + + await docsCommand.action(mockContext, ''); + + // The logic should fall through to the 'else' block + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.INFO, + text: `Opening documentation in your browser: ${docsUrl}`, + }, + expect.any(Number), + ); + + // 'open' should be called in this specific sandbox case + expect(open).toHaveBeenCalledWith(docsUrl); + }); +}); diff --git a/packages/cli/src/ui/commands/docsCommand.ts b/packages/cli/src/ui/commands/docsCommand.ts new file mode 100644 index 00000000..e53a4a80 --- /dev/null +++ b/packages/cli/src/ui/commands/docsCommand.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import open from 'open'; +import process from 'node:process'; +import { type CommandContext, type SlashCommand } from './types.js'; +import { MessageType } from '../types.js'; + +export const docsCommand: SlashCommand = { + name: 'docs', + description: 'open full Gemini CLI documentation in your browser', + action: async (context: CommandContext): Promise<void> => { + const docsUrl = 'https://goo.gle/gemini-cli-docs'; + + if (process.env.SANDBOX && process.env.SANDBOX !== 'sandbox-exec') { + context.ui.addItem( + { + type: MessageType.INFO, + text: `Please open the following URL in your browser to view the documentation:\n${docsUrl}`, + }, + Date.now(), + ); + } else { + context.ui.addItem( + { + type: MessageType.INFO, + text: `Opening documentation in your browser: ${docsUrl}`, + }, + Date.now(), + ); + await open(docsUrl); + } + }, +}; diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts index 8355ea19..8fa3f880 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts @@ -201,27 +201,6 @@ export const useSlashCommandProcessor = ( const commands: LegacySlashCommand[] = [ // `/help` and `/clear` have been migrated and REMOVED from this list. { - name: 'docs', - description: 'open full Gemini CLI documentation in your browser', - action: async (_mainCommand, _subCommand, _args) => { - const docsUrl = 'https://goo.gle/gemini-cli-docs'; - if (process.env.SANDBOX && process.env.SANDBOX !== 'sandbox-exec') { - addMessage({ - type: MessageType.INFO, - content: `Please open the following URL in your browser to view the documentation:\n${docsUrl}`, - timestamp: new Date(), - }); - } else { - addMessage({ - type: MessageType.INFO, - content: `Opening documentation in your browser: ${docsUrl}`, - timestamp: new Date(), - }); - await open(docsUrl); - } - }, - }, - { name: 'editor', description: 'set external editor preference', action: (_mainCommand, _subCommand, _args) => openEditorDialog(), |
