diff --git a/packages/cli/src/ui/hooks/shellCommandProcessor.test.ts b/packages/cli/src/ui/hooks/shellCommandProcessor.test.ts index 3645cc80..92bc98ea 100644 --- a/packages/cli/src/ui/hooks/shellCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/shellCommandProcessor.test.ts @@ -15,6 +15,7 @@ import type { exec as ExecType } from 'child_process'; // For typing the injecte // Mocks const mockAddItemToHistory = vi.fn(); +const mockSetPendingHistoryItem = vi.fn(); const mockOnExec = vi.fn(async (promise) => await promise); const mockOnDebugMessage = vi.fn(); const mockGetTargetDir = vi.fn(); @@ -94,6 +95,7 @@ describe('useShellCommandProcessor', () => { renderHook(() => useShellCommandProcessor( mockAddItemToHistory, + mockSetPendingHistoryItem, mockOnExec, mockOnDebugMessage, mockConfig, diff --git a/packages/cli/src/ui/hooks/shellCommandProcessor.ts b/packages/cli/src/ui/hooks/shellCommandProcessor.ts index 9ad5ef03..e7ccefcd 100644 --- a/packages/cli/src/ui/hooks/shellCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/shellCommandProcessor.ts @@ -5,6 +5,7 @@ */ import { spawn } from 'child_process'; +import type { HistoryItemWithoutId } from '../types.js'; import type { exec as ExecType } from 'child_process'; import { useCallback } from 'react'; import { Config } from '@gemini-code/server'; @@ -21,6 +22,9 @@ import fs from 'fs'; */ export const useShellCommandProcessor = ( addItemToHistory: UseHistoryManagerReturn['addItem'], + setPendingHistoryItem: React.Dispatch< + React.SetStateAction + >, onExec: (command: Promise) => void, onDebugMessage: (message: string) => void, config: Config, @@ -115,18 +119,25 @@ export const useShellCommandProcessor = ( cwd: targetDir, stdio: ['ignore', 'pipe', 'pipe'], }); + let output = ''; - child.stdout.on('data', (data) => { + const handleOutput = (data: string) => { output += data; - }); - child.stderr.on('data', (data) => { - output += data; - }); + setPendingHistoryItem({ + type: 'info', + text: output, + }); + }; + child.stdout.on('data', handleOutput); + child.stderr.on('data', handleOutput); + let error: Error | null = null; child.on('error', (err: Error) => { error = err; }); + child.on('close', (code, signal) => { + setPendingHistoryItem(null); output = output.trim() || '(Command produced no output)'; if (error) { const text = `${error.message.replace(commandToExecute, rawQuery)}\n${output}`; @@ -169,7 +180,14 @@ export const useShellCommandProcessor = ( return true; // Command was initiated }, - [config, onDebugMessage, addItemToHistory, onExec, executeCommand], + [ + config, + onDebugMessage, + addItemToHistory, + setPendingHistoryItem, + onExec, + executeCommand, + ], ); return { handleShellCommand }; diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index 1cd2438c..de7980d5 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -82,6 +82,7 @@ export const useGeminiStream = ( }, []); const { handleShellCommand } = useShellCommandProcessor( addItem, + setPendingHistoryItem, onExec, onDebugMessage, config,