summaryrefslogtreecommitdiff
path: root/packages/cli/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src')
-rw-r--r--packages/cli/src/config/config.ts1
-rw-r--r--packages/cli/src/ui/App.tsx2
-rw-r--r--packages/cli/src/ui/hooks/useGeminiStream.ts54
3 files changed, 46 insertions, 11 deletions
diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts
index 6d8c10f6..81117dab 100644
--- a/packages/cli/src/config/config.ts
+++ b/packages/cli/src/config/config.ts
@@ -72,6 +72,7 @@ export function loadCliConfig(): Config {
argv.model || DEFAULT_GEMINI_MODEL,
argv.target_dir || process.cwd(),
argv.debug_mode || false,
+ // TODO: load passthroughCommands from .env file
);
}
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx
index cfbc024e..daf7845c 100644
--- a/packages/cli/src/ui/App.tsx
+++ b/packages/cli/src/ui/App.tsx
@@ -32,7 +32,7 @@ export const App = ({ config }: AppProps) => {
const [history, setHistory] = useState<HistoryItem[]>([]);
const [startupWarnings, setStartupWarnings] = useState<string[]>([]);
const { streamingState, submitQuery, initError, debugMessage } =
- useGeminiStream(setHistory, config.getApiKey(), config.getModel());
+ useGeminiStream(setHistory, config);
const { elapsedTime, currentLoadingPhrase } =
useLoadingIndicator(streamingState);
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,
],