summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/hooks
diff options
context:
space:
mode:
authorJuliette Love <[email protected]>2025-04-20 21:06:22 +0100
committerGitHub <[email protected]>2025-04-20 21:06:22 +0100
commita76d9b4dcfa291c182c4fb1320992db448f0285c (patch)
tree02390710cfc6deb73657a1d400f534c93030aaeb /packages/cli/src/ui/hooks
parentf480ef4bbcc9dc03b5a9a1e80e5f428038c8d34e (diff)
Adds shell command allowlist (#68)
* Wire through passthrough commands * Add default passthrough commands * Clean up config passing to useGeminiStream
Diffstat (limited to 'packages/cli/src/ui/hooks')
-rw-r--r--packages/cli/src/ui/hooks/useGeminiStream.ts54
1 files changed, 44 insertions, 10 deletions
diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts
index 1d839998..1cd9f5d6 100644
--- a/packages/cli/src/ui/hooks/useGeminiStream.ts
+++ b/packages/cli/src/ui/hooks/useGeminiStream.ts
@@ -14,6 +14,7 @@ import {
getErrorMessage,
isNodeError,
ToolResult,
+ Config,
} from '@gemini-code/server';
import type { Chat, PartListUnion, FunctionDeclaration } from '@google/genai';
// Import CLI types
@@ -27,8 +28,6 @@ import { StreamingState } from '../../core/gemini-stream.js';
// Import CLI tool registry
import { toolRegistry } from '../../tools/tool-registry.js';
-const _allowlistedCommands = ['ls']; // Prefix with underscore since it's unused
-
const addHistoryItem = (
setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>,
itemData: Omit<HistoryItem, 'id'>,
@@ -43,8 +42,7 @@ const addHistoryItem = (
// Hook now accepts apiKey and model
export const useGeminiStream = (
setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>,
- apiKey: string,
- model: string,
+ config: Config,
) => {
const [streamingState, setStreamingState] = useState<StreamingState>(
StreamingState.Idle,
@@ -62,15 +60,17 @@ export const useGeminiStream = (
setInitError(null);
if (!geminiClientRef.current) {
try {
- geminiClientRef.current = new GeminiClient(apiKey, model);
+ geminiClientRef.current = new GeminiClient(
+ config.getApiKey(),
+ config.getModel(),
+ );
} catch (error: unknown) {
setInitError(
`Failed to initialize client: ${getErrorMessage(error) || 'Unknown error'}`,
);
}
}
- // Dependency array includes apiKey and model now
- }, [apiKey, model]);
+ }, [config.getApiKey(), config.getModel()]);
// Input Handling Effect (remains the same)
useInput((input, key) => {
@@ -107,6 +107,39 @@ export const useGeminiStream = (
if (typeof query === 'string') {
setDebugMessage(`User query: ${query}`);
+ const maybeCommand = query.split(/\s+/)[0];
+ if (config.getPassthroughCommands().includes(maybeCommand)) {
+ // Execute and capture output
+ setDebugMessage(`Executing shell command directly: ${query}`);
+ _exec(query, (error, stdout, stderr) => {
+ const timestamp = getNextMessageId(Date.now());
+ if (error) {
+ addHistoryItem(
+ setHistory,
+ { type: 'error', text: error.message },
+ timestamp,
+ );
+ } else if (stderr) {
+ addHistoryItem(
+ setHistory,
+ { type: 'error', text: stderr },
+ timestamp,
+ );
+ } else {
+ // Add stdout as an info message
+ addHistoryItem(
+ setHistory,
+ { type: 'info', text: stdout || '' },
+ timestamp,
+ );
+ }
+ // Set state back to Idle *after* command finishes and output is added
+ setStreamingState(StreamingState.Idle);
+ });
+ // Set state to Responding while the command runs
+ setStreamingState(StreamingState.Responding);
+ return; // Prevent Gemini call
+ }
}
const userMessageTimestamp = Date.now();
@@ -391,7 +424,8 @@ export const useGeminiStream = (
}
} finally {
abortControllerRef.current = null;
- // Only set to Idle if not waiting for confirmation
+ // Only set to Idle if not waiting for confirmation.
+ // Passthrough commands handle their own Idle transition.
if (streamingState !== StreamingState.WaitingForConfirmation) {
setStreamingState(StreamingState.Idle);
}
@@ -401,8 +435,8 @@ export const useGeminiStream = (
[
streamingState,
setHistory,
- apiKey,
- model,
+ config.getApiKey(),
+ config.getModel(),
getNextMessageId,
updateGeminiMessage,
],