diff options
Diffstat (limited to 'packages/cli/src')
| -rw-r--r-- | packages/cli/src/ui/App.tsx | 29 | ||||
| -rw-r--r-- | packages/cli/src/ui/hooks/slashCommandProcessor.test.ts | 30 | ||||
| -rw-r--r-- | packages/cli/src/ui/hooks/slashCommandProcessor.ts | 30 |
3 files changed, 70 insertions, 19 deletions
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index cdec11e2..dcd2b7ee 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -89,6 +89,9 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const [showToolDescriptions, setShowToolDescriptions] = useState<boolean>(false); const [ctrlCPressedOnce, setCtrlCPressedOnce] = useState(false); + const [quittingMessages, setQuittingMessages] = useState< + HistoryItem[] | null + >(null); const ctrlCTimerRef = useRef<NodeJS.Timeout | null>(null); const errorCount = useMemo( @@ -162,6 +165,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { performMemoryRefresh, toggleCorgiMode, showToolDescriptions, + setQuittingMessages, ); useInput((input: string, key: InkKeyType) => { @@ -185,7 +189,14 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { if (ctrlCTimerRef.current) { clearTimeout(ctrlCTimerRef.current); } - process.exit(0); + const quitCommand = slashCommands.find( + (cmd) => cmd.name === 'quit' || cmd.altName === 'exit', + ); + if (quitCommand) { + quitCommand.action('quit', '', ''); + } else { + process.exit(0); + } } else { setCtrlCPressedOnce(true); ctrlCTimerRef.current = setTimeout(() => { @@ -338,6 +349,22 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const branchName = useGitBranchName(config.getTargetDir()); + if (quittingMessages) { + return ( + <Box flexDirection="column" marginBottom={1}> + {quittingMessages.map((item) => ( + <HistoryItemDisplay + key={item.id} + availableTerminalHeight={availableTerminalHeight} + item={item} + isPending={false} + config={config} + /> + ))} + </Box> + ); + } + return ( <StreamingContext.Provider value={streamingState}> <Box flexDirection="column" marginBottom={1} width="90%"> diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts index 0c12d855..971d7aac 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts @@ -98,6 +98,7 @@ describe('useSlashCommandProcessor', () => { let mockOnDebugMessage: ReturnType<typeof vi.fn>; let mockOpenThemeDialog: ReturnType<typeof vi.fn>; let mockPerformMemoryRefresh: ReturnType<typeof vi.fn>; + let mockSetQuittingMessages: ReturnType<typeof vi.fn>; let mockConfig: Config; let mockCorgiMode: ReturnType<typeof vi.fn>; const mockUseSessionStats = useSessionStats as Mock; @@ -111,6 +112,7 @@ describe('useSlashCommandProcessor', () => { mockOnDebugMessage = vi.fn(); mockOpenThemeDialog = vi.fn(); mockPerformMemoryRefresh = vi.fn().mockResolvedValue(undefined); + mockSetQuittingMessages = vi.fn(); mockConfig = { getDebugMode: vi.fn(() => false), getSandbox: vi.fn(() => 'test-sandbox'), @@ -156,6 +158,7 @@ describe('useSlashCommandProcessor', () => { mockPerformMemoryRefresh, mockCorgiMode, showToolDescriptions, + mockSetQuittingMessages, ), ); return result.current; @@ -406,7 +409,7 @@ Add any other context about the problem here. }); it.each([['/quit'], ['/exit']])( - 'should handle %s, add a quit message, and exit the process', + 'should handle %s, set quitting messages, and exit the process', async (command) => { const { handleSlashCommand } = getProcessor(); const mockDate = new Date('2025-01-01T01:02:03.000Z'); @@ -416,18 +419,25 @@ Add any other context about the problem here. handleSlashCommand(command); }); - expect(mockAddItem).toHaveBeenCalledTimes(2); - expect(mockAddItem).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ - type: MessageType.QUIT, + expect(mockAddItem).not.toHaveBeenCalled(); + expect(mockSetQuittingMessages).toHaveBeenCalledWith([ + { + type: 'user', + text: command, + id: expect.any(Number), + }, + { + type: 'quit', + stats: expect.any(Object), duration: '1h 2m 3s', - }), - expect.any(Number), - ); + id: expect.any(Number), + }, + ]); // Fast-forward timers to trigger process.exit - vi.advanceTimersByTime(100); + await act(async () => { + vi.advanceTimersByTime(100); + }); expect(mockProcessExit).toHaveBeenCalledWith(0); }, ); diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts index 478a62a3..d343c6ff 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts @@ -69,6 +69,7 @@ export const useSlashCommandProcessor = ( performMemoryRefresh: () => Promise<void>, toggleCorgiMode: () => void, showToolDescriptions: boolean = false, + setQuittingMessages: (message: HistoryItem[]) => void, ) => { const session = useSessionStats(); const gitService = useMemo(() => { @@ -608,17 +609,24 @@ Add any other context about the problem here. name: 'quit', altName: 'exit', description: 'exit the cli', - action: async (_mainCommand, _subCommand, _args) => { + action: async (mainCommand, _subCommand, _args) => { const now = new Date(); const { sessionStartTime, cumulative } = session.stats; const wallDuration = now.getTime() - sessionStartTime.getTime(); - addMessage({ - type: MessageType.QUIT, - stats: cumulative, - duration: formatDuration(wallDuration), - timestamp: new Date(), - }); + setQuittingMessages([ + { + type: 'user', + text: `/${mainCommand}`, + id: now.getTime() - 1, + }, + { + type: 'quit', + stats: cumulative, + duration: formatDuration(wallDuration), + id: now.getTime(), + }, + ]); setTimeout(() => { process.exit(0); @@ -749,6 +757,7 @@ Add any other context about the problem here. gitService, loadHistory, addItem, + setQuittingMessages, ]); const handleSlashCommand = useCallback( @@ -763,7 +772,12 @@ Add any other context about the problem here. return false; } const userMessageTimestamp = Date.now(); - addItem({ type: MessageType.USER, text: trimmed }, userMessageTimestamp); + if (trimmed !== '/quit' && trimmed !== '/exit') { + addItem( + { type: MessageType.USER, text: trimmed }, + userMessageTimestamp, + ); + } let subCommand: string | undefined; let args: string | undefined; |
