From dfa46df474b474af0f0c27758a11e70ceb6ab695 Mon Sep 17 00:00:00 2001 From: Seth Troisi Date: Mon, 28 Apr 2025 12:38:07 -0700 Subject: [PATCH] Refactor hardcoded slash commands (#179) --- packages/cli/src/ui/hooks/useGeminiStream.ts | 82 ++++++++++++++------ 1 file changed, 59 insertions(+), 23 deletions(-) diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index 5a9de54d..f6aa5ae6 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -30,6 +30,12 @@ import { } from '../types.js'; import { findSafeSplitPoint } from '../utils/markdownUtilities.js'; +interface SlashCommand { + name: string; // slash command + description: string; // flavor text in UI + action: (value: PartListUnion) => void; +} + const addHistoryItem = ( setHistory: React.Dispatch>, itemData: Omit, @@ -58,6 +64,47 @@ export const useGeminiStream = ( const messageIdCounterRef = useRef(0); const currentGeminiMessageIdRef = useRef(null); + const slashCommands: SlashCommand[] = [ + { + name: 'clear', + description: 'clear the screen', + action: (_value: PartListUnion) => { + // This just clears the *UI* history, not the model history. + setDebugMessage('Clearing terminal.'); + setHistory((_) => []); + }, + }, + { + name: 'exit', + description: 'Exit gemini-code', + action: (_value: PartListUnion) => { + setDebugMessage('Exiting. Good-bye.'); + const timestamp = getNextMessageId(Date.now()); + addHistoryItem( + setHistory, + { type: 'info', text: 'good-bye!' }, + timestamp, + ); + process.exit(0); + }, + }, + { + // TODO: dedup with exit by adding altName or cmdRegex. + name: 'quit', + description: 'Quit gemini-code', + action: (_value: PartListUnion) => { + setDebugMessage('Quitting. Good-bye.'); + const timestamp = getNextMessageId(Date.now()); + addHistoryItem( + setHistory, + { type: 'info', text: 'good-bye!' }, + timestamp, + ); + process.exit(0); + }, + }, + ]; + // Initialize Client Effect - uses props now useEffect(() => { setInitError(null); @@ -105,31 +152,20 @@ export const useGeminiStream = ( return false; } - const query = rawQuery.trim(); - if (query === 'clear' || query === '/clear') { - // This just clears the *UI* history, not the model history. - // TODO: add a slash command for that. - setDebugMessage('Clearing terminal.'); - setHistory((_) => []); - return true; + const trimmedQuery = rawQuery.trim(); + let query = trimmedQuery; + if (query.length && query.charAt(0) === '/') { + query = query.slice(1); } - if ( - query === 'exit' || - query === '/exit' || - query === 'quit' || - query === '/quit' - ) { - setDebugMessage('Quitting. Good-bye.'); - const timestamp = getNextMessageId(Date.now()); - addHistoryItem( - setHistory, - { type: 'info', text: 'good-bye!' }, - timestamp, - ); - process.exit(0); - return true; + + for (const cmd of slashCommands) { + if (query === cmd.name) { + cmd.action(query); + return true; + } } - const maybeCommand = query.split(/\s+/)[0]; + + const maybeCommand = trimmedQuery.split(/\s+/)[0]; if (config.getPassthroughCommands().includes(maybeCommand)) { // Execute and capture output const targetDir = config.getTargetDir();