diff --git a/src/tools/ask-gemini.tool.ts b/src/tools/ask-gemini.tool.ts index bc76b3a..de9d77b 100644 --- a/src/tools/ask-gemini.tool.ts +++ b/src/tools/ask-gemini.tool.ts @@ -13,6 +13,7 @@ const askGeminiArgsSchema = z.object({ changeMode: z.boolean().default(false).describe("Enable structured change mode - formats prompts to prevent tool errors and returns structured edit suggestions that Claude can apply directly"), chunkIndex: z.union([z.number(), z.string()]).optional().describe("Which chunk to return (1-based)"), chunkCacheKey: z.string().optional().describe("Optional cache key for continuation"), + workingDirectory: z.string().optional().describe("Working directory to run Gemini from. Use drive root (e.g., 'C:/' or 'D:/') to access files on that drive."), }); export const askGeminiTool: UnifiedTool = { @@ -24,8 +25,8 @@ export const askGeminiTool: UnifiedTool = { }, category: 'gemini', execute: async (args, onProgress) => { - const { prompt, model, sandbox, changeMode, chunkIndex, chunkCacheKey } = args; if (!prompt?.trim()) { throw new Error(ERROR_MESSAGES.NO_PROMPT_PROVIDED); } - + const { prompt, model, sandbox, changeMode, chunkIndex, chunkCacheKey, workingDirectory } = args; if (!prompt?.trim()) { throw new Error(ERROR_MESSAGES.NO_PROMPT_PROVIDED); } + if (changeMode && chunkIndex && chunkCacheKey) { return processChangeModeOutput( '', // empty for cache... @@ -34,13 +35,14 @@ export const askGeminiTool: UnifiedTool = { prompt as string ); } - + const result = await executeGeminiCLI( prompt as string, model as string | undefined, !!sandbox, !!changeMode, - onProgress + onProgress, + workingDirectory as string | undefined ); if (changeMode) { diff --git a/src/utils/commandExecutor.ts b/src/utils/commandExecutor.ts index b9b6f1b..861efba 100644 --- a/src/utils/commandExecutor.ts +++ b/src/utils/commandExecutor.ts @@ -4,7 +4,8 @@ import { Logger } from "./logger.js"; export async function executeCommand( command: string, args: string[], - onProgress?: (newOutput: string) => void + onProgress?: (newOutput: string) => void, + cwd?: string ): Promise { return new Promise((resolve, reject) => { const startTime = Date.now(); @@ -12,8 +13,9 @@ export async function executeCommand( const childProcess = spawn(command, args, { env: process.env, - shell: false, + shell: true, stdio: ["ignore", "pipe", "pipe"], + cwd: cwd, }); let stdout = ""; diff --git a/src/utils/geminiExecutor.ts b/src/utils/geminiExecutor.ts index f7e79d3..50dc964 100644 --- a/src/utils/geminiExecutor.ts +++ b/src/utils/geminiExecutor.ts @@ -17,7 +17,8 @@ export async function executeGeminiCLI( model?: string, sandbox?: boolean, changeMode?: boolean, - onProgress?: (newOutput: string) => void + onProgress?: (newOutput: string) => void, + cwd?: string ): Promise { let prompt_processed = prompt; @@ -87,38 +88,30 @@ ${prompt_processed} prompt_processed = changeModeInstructions; } - const args = []; + const args = ['-y']; // YOLO mode for non-interactive if (model) { args.push(CLI.FLAGS.MODEL, model); } if (sandbox) { args.push(CLI.FLAGS.SANDBOX); } - - // Ensure @ symbols work cross-platform by wrapping in quotes if needed - const finalPrompt = prompt_processed.includes('@') && !prompt_processed.startsWith('"') - ? `"${prompt_processed}"` - : prompt_processed; - - args.push(CLI.FLAGS.PROMPT, finalPrompt); + + // Use positional prompt (not -p flag which is deprecated) + args.push(prompt_processed); try { - return await executeCommand(CLI.COMMANDS.GEMINI, args, onProgress); + return await executeCommand(CLI.COMMANDS.GEMINI, args, onProgress, cwd); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (errorMessage.includes(ERROR_MESSAGES.QUOTA_EXCEEDED) && model !== MODELS.FLASH) { Logger.warn(`${ERROR_MESSAGES.QUOTA_EXCEEDED}. Falling back to ${MODELS.FLASH}.`); await sendStatusMessage(STATUS_MESSAGES.FLASH_RETRY); - const fallbackArgs = []; + const fallbackArgs = ['-y']; // YOLO mode fallbackArgs.push(CLI.FLAGS.MODEL, MODELS.FLASH); if (sandbox) { fallbackArgs.push(CLI.FLAGS.SANDBOX); } - - // Same @ symbol handling for fallback - const fallbackPrompt = prompt_processed.includes('@') && !prompt_processed.startsWith('"') - ? `"${prompt_processed}"` - : prompt_processed; - - fallbackArgs.push(CLI.FLAGS.PROMPT, fallbackPrompt); + + // Use positional prompt + fallbackArgs.push(prompt_processed); try { - const result = await executeCommand(CLI.COMMANDS.GEMINI, fallbackArgs, onProgress); + const result = await executeCommand(CLI.COMMANDS.GEMINI, fallbackArgs, onProgress, cwd); Logger.warn(`Successfully executed with ${MODELS.FLASH} fallback.`); await sendStatusMessage(STATUS_MESSAGES.FLASH_SUCCESS); return result;