diff options
| author | Harold Mciver <[email protected]> | 2025-07-15 16:10:04 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-15 20:10:04 +0000 |
| commit | 03b3917f62e5db2b00bcb27df9d78ee5289d9a85 (patch) | |
| tree | dc6007c213bbdef4a39f1627d7c3d59a3bf44a23 /packages/cli/src/ui/commands | |
| parent | 8d9dc44b71c71dc7800f1dedcc5f88ec1ab654fa (diff) | |
updated `/stats` to use new slash command arch (#4146)
Diffstat (limited to 'packages/cli/src/ui/commands')
| -rw-r--r-- | packages/cli/src/ui/commands/statsCommand.test.ts | 78 | ||||
| -rw-r--r-- | packages/cli/src/ui/commands/statsCommand.ts | 63 |
2 files changed, 141 insertions, 0 deletions
diff --git a/packages/cli/src/ui/commands/statsCommand.test.ts b/packages/cli/src/ui/commands/statsCommand.test.ts new file mode 100644 index 00000000..485fcf69 --- /dev/null +++ b/packages/cli/src/ui/commands/statsCommand.test.ts @@ -0,0 +1,78 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { vi, describe, it, expect, beforeEach } from 'vitest'; +import { statsCommand } from './statsCommand.js'; +import { type CommandContext } from './types.js'; +import { createMockCommandContext } from '../../test-utils/mockCommandContext.js'; +import { MessageType } from '../types.js'; +import { formatDuration } from '../utils/formatters.js'; + +describe('statsCommand', () => { + let mockContext: CommandContext; + const startTime = new Date('2025-07-14T10:00:00.000Z'); + const endTime = new Date('2025-07-14T10:00:30.000Z'); + + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(endTime); + + // 1. Create the mock context with all default values + mockContext = createMockCommandContext(); + + // 2. Directly set the property on the created mock context + mockContext.session.stats.sessionStartTime = startTime; + }); + + it('should display general session stats when run with no subcommand', () => { + if (!statsCommand.action) throw new Error('Command has no action'); + + statsCommand.action(mockContext, ''); + + const expectedDuration = formatDuration( + endTime.getTime() - startTime.getTime(), + ); + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.STATS, + duration: expectedDuration, + }, + expect.any(Number), + ); + }); + + it('should display model stats when using the "model" subcommand', () => { + const modelSubCommand = statsCommand.subCommands?.find( + (sc) => sc.name === 'model', + ); + if (!modelSubCommand?.action) throw new Error('Subcommand has no action'); + + modelSubCommand.action(mockContext, ''); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.MODEL_STATS, + }, + expect.any(Number), + ); + }); + + it('should display tool stats when using the "tools" subcommand', () => { + const toolsSubCommand = statsCommand.subCommands?.find( + (sc) => sc.name === 'tools', + ); + if (!toolsSubCommand?.action) throw new Error('Subcommand has no action'); + + toolsSubCommand.action(mockContext, ''); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.TOOL_STATS, + }, + expect.any(Number), + ); + }); +}); diff --git a/packages/cli/src/ui/commands/statsCommand.ts b/packages/cli/src/ui/commands/statsCommand.ts new file mode 100644 index 00000000..87e902d4 --- /dev/null +++ b/packages/cli/src/ui/commands/statsCommand.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { MessageType, HistoryItemStats } from '../types.js'; +import { formatDuration } from '../utils/formatters.js'; +import { type CommandContext, type SlashCommand } from './types.js'; + +export const statsCommand: SlashCommand = { + name: 'stats', + altName: 'usage', + description: 'check session stats. Usage: /stats [model|tools]', + action: (context: CommandContext) => { + const now = new Date(); + const { sessionStartTime } = context.session.stats; + if (!sessionStartTime) { + context.ui.addItem( + { + type: MessageType.ERROR, + text: 'Session start time is unavailable, cannot calculate stats.', + }, + Date.now(), + ); + return; + } + const wallDuration = now.getTime() - sessionStartTime.getTime(); + + const statsItem: HistoryItemStats = { + type: MessageType.STATS, + duration: formatDuration(wallDuration), + }; + + context.ui.addItem(statsItem, Date.now()); + }, + subCommands: [ + { + name: 'model', + description: 'Show model-specific usage statistics.', + action: (context: CommandContext) => { + context.ui.addItem( + { + type: MessageType.MODEL_STATS, + }, + Date.now(), + ); + }, + }, + { + name: 'tools', + description: 'Show tool-specific usage statistics.', + action: (context: CommandContext) => { + context.ui.addItem( + { + type: MessageType.TOOL_STATS, + }, + Date.now(), + ); + }, + }, + ], +}; |
