diff options
| author | Taylor Mullen <[email protected]> | 2025-05-20 00:21:01 -0700 |
|---|---|---|
| committer | N. Taylor Mullen <[email protected]> | 2025-05-20 00:23:12 -0700 |
| commit | 6ca446bdeda359339b20aaf024d5cce4234bfe9a (patch) | |
| tree | 63a93661d0359996267850e3c7dde7dd749c38c2 /packages/cli/src/ui/hooks/shellCommandProcessor.ts | |
| parent | 9c72a3ae129a5ab6cbc13fded86da01f2a354a75 (diff) | |
fix(cli): Prevent truncation of first character in shell commands
- The shell command processor was incorrectly truncating the first
character of the command (e.g., 'ls' became 's') due to an
erroneous `slice(1)` operation, likely introduced during a
previous merge. This change removes the slice, ensuring the full
command is processed.
- Introduces unit tests for the shellCommandProcessor hook.
- Fixes a minor grammatical issue in the display of GEMINI.md file count.
Diffstat (limited to 'packages/cli/src/ui/hooks/shellCommandProcessor.ts')
| -rw-r--r-- | packages/cli/src/ui/hooks/shellCommandProcessor.ts | 64 |
1 files changed, 37 insertions, 27 deletions
diff --git a/packages/cli/src/ui/hooks/shellCommandProcessor.ts b/packages/cli/src/ui/hooks/shellCommandProcessor.ts index 5e43712b..35935e7d 100644 --- a/packages/cli/src/ui/hooks/shellCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/shellCommandProcessor.ts @@ -4,7 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { exec as _exec } from 'child_process'; +import { exec as defaultExec } from 'child_process'; +import type { exec as ExecType } from 'child_process'; import { useCallback } from 'react'; import { Config } from '@gemini-code/server'; import { type PartListUnion } from '@google/genai'; @@ -13,6 +14,7 @@ import crypto from 'crypto'; import path from 'path'; import os from 'os'; import fs from 'fs'; + /** * Hook to process shell commands (e.g., !ls, $pwd). * Executes the command in the target directory and adds output/errors to history. @@ -22,6 +24,7 @@ export const useShellCommandProcessor = ( onExec: (command: Promise<void>) => void, onDebugMessage: (message: string) => void, config: Config, + executeCommand: typeof ExecType = defaultExec, // Injectable for testing ) => { /** * Checks if the query is a shell command, executes it, and adds results to history. @@ -33,7 +36,7 @@ export const useShellCommandProcessor = ( return false; } - let commandToExecute = rawQuery.trim().slice(1).trimStart(); + let commandToExecute = rawQuery.trim().trimStart(); // wrap command to write pwd to temporary file const pwdFileName = `shell_pwd_${crypto.randomBytes(6).toString('hex')}.tmp`; @@ -48,7 +51,7 @@ export const useShellCommandProcessor = ( userMessageTimestamp, ); - if (!commandToExecute) { + if (rawQuery.trim() === '') { addItemToHistory( { type: 'error', text: 'Empty shell command.' }, userMessageTimestamp, @@ -65,37 +68,44 @@ export const useShellCommandProcessor = ( }; const execPromise = new Promise<void>((resolve) => { - _exec(commandToExecute, execOptions, (error, stdout, stderr) => { - if (error) { - addItemToHistory( - { type: 'error', text: error.message }, - userMessageTimestamp, - ); - } else { - let output = ''; - if (stdout) output += stdout; - if (stderr) output += (output ? '\n' : '') + stderr; // Include stderr as info + executeCommand( + commandToExecute, + execOptions, + (error, stdout, stderr) => { + if (error) { + addItemToHistory( + { type: 'error', text: error.message }, + userMessageTimestamp, + ); + } else { + let output = ''; + if (stdout) output += stdout; + if (stderr) output += (output ? '\n' : '') + stderr; // Include stderr as info - addItemToHistory( - { type: 'info', text: output || '(Command produced no output)' }, - userMessageTimestamp, - ); - } - if (fs.existsSync(pwdFilePath)) { - const pwd = fs.readFileSync(pwdFilePath, 'utf8').trim(); - if (pwd !== targetDir) { addItemToHistory( { type: 'info', - text: `WARNING: shell mode is stateless; \`cd ${pwd}\` will not apply to next command`, + text: output || '(Command produced no output)', }, userMessageTimestamp, ); } - fs.unlinkSync(pwdFilePath); - } - resolve(); - }); + if (fs.existsSync(pwdFilePath)) { + const pwd = fs.readFileSync(pwdFilePath, 'utf8').trim(); + if (pwd !== targetDir) { + addItemToHistory( + { + type: 'info', + text: `WARNING: shell mode is stateless; \`cd ${pwd}\` will not apply to next command`, + }, + userMessageTimestamp, + ); + } + fs.unlinkSync(pwdFilePath); + } + resolve(); + }, + ); }); try { @@ -106,7 +116,7 @@ export const useShellCommandProcessor = ( return true; // Command was initiated }, - [config, onDebugMessage, addItemToHistory, onExec], + [config, onDebugMessage, addItemToHistory, onExec, executeCommand], ); return { handleShellCommand }; |
