import { RuntimeAgentService } from './runtime-agent.service.abstract.js'; import { SessionCommandHelper } from '../session/index.js'; import { type RuntimeType } from '../../constants.js'; /** * Gemini CLI specific runtime service implementation. * Handles Gemini CLI initialization, detection, and interaction patterns. */ export declare class GeminiRuntimeService extends RuntimeAgentService { constructor(sessionHelper: SessionCommandHelper, projectRoot: string); /** * Launch Gemini CLI, after making sure it will not stop on a dialog. * * Two dialogs used to hold a fresh install at startup until the readiness * window ran out ("Failed to initialize agent" after ~207s, 0 sessions): * - The auth dialog. Interactive Gemini reads its auth method only from * settings, so with a key but no saved method it asks every time. It is * pre-answered here when a Gemini API key is configured. * - The workspace trust dialog. Gemini reads its trusted-folder list once, * at startup, so folders trusted after launch still prompt when * postInitialize runs `/directory add`. They are trusted here, first. * * @param sessionName - PTY session name * @param targetPath - Working directory for the session * @param runtimeFlags - Optional CLI flags * @param promptFilePath - Optional prompt file path * @param agentName - Optional agent name * @param resumeSessionId - Optional conversation to resume */ executeRuntimeInitScript(sessionName: string, targetPath?: string, runtimeFlags?: string[], promptFilePath?: string, agentName?: string, resumeSessionId?: string): Promise; /** * Pre-answer Gemini's startup dialogs. Never throws: a failure here only * means the dialog may appear, which readiness still handles or reports. * * @param targetPath - Working directory the session will use */ prepareGeminiLaunch(targetPath?: string): Promise; /** * Folders postInitialize adds to the Gemini workspace, which must already be * trusted when Gemini starts: Gemini reads its trusted-folder list only at * startup, so a folder trusted later raises a trust dialog when it is added. * * Includes the system temp directory: skills write screenshots and other * artifacts there (remote-browser, screenshot-compare, transcribe-audio, * ...), and Gemini's file tools can only read workspace folders. Other * runtimes read /tmp without any setup, so Gemini must not be the exception. * * @param targetPath - The session's project path, if different from the root * @returns Absolute folder paths */ getStartupTrustedPaths(targetPath?: string): string[]; /** * Gemini CLI can show an interactive trust gate on first launch: * "Do you trust this folder?". * Auto-accept the default "Trust folder" option so startup does not stall. * * @throws RuntimeStartupBlockedError (reason `auth_required`) as soon as * Gemini asks how to authenticate, and (reason `runtime_not_installed`) * when the shell cannot find `gemini`: neither resolves by waiting. */ waitForRuntimeReady(sessionName: string, timeout: number, checkInterval?: number): Promise; protected getRuntimeType(): RuntimeType; /** * Gemini CLI specific detection using '/' command */ protected detectRuntimeSpecific(sessionName: string): Promise; /** * Gemini CLI specific ready patterns */ protected getRuntimeReadyPatterns(): string[]; /** * Gemini CLI paints its `>` input box on the auth-method picker too, so * the sign-in text vetoes readiness until login completes. * * @returns Gemini-specific "not ready" markers */ protected getNotReadyMarkers(): readonly string[]; /** * Gemini's startup folder-trust dialog. Wording varies by version: * "Do you trust this folder?" (older) and "Do you trust the files in this * folder?" (0.61). Option 1, "Trust folder", is selected by default. * * @param output - Captured terminal output * @returns True when the dialog is on screen */ isGeminiTrustPrompt(output: string): boolean; /** * Gemini's dialog for folders added with `/directory add` that were not * trusted at startup. Option 1, "Yes", is selected by default. * * @param output - Captured terminal output * @returns True when the dialog is on screen */ isGeminiWorkspaceTrustPrompt(output: string): boolean; /** * Gemini's "How would you like to authenticate" dialog. * * @param output - Captured terminal output * @returns True when the dialog is on screen */ isGeminiAuthDialog(output: string): boolean; /** * Gemini CLI specific exit patterns for runtime exit detection. * * Includes both clean exit patterns (e.g. "Agent powering down") and * failure patterns that indicate the CLI is stuck or crashed and needs * recovery (e.g. API quota exhaustion, network errors). * * @returns Array of RegExp patterns that match runtime exit or failure output */ protected getRuntimeExitPatterns(): RegExp[]; /** * Gemini CLI specific error patterns */ protected getRuntimeErrorPatterns(): string[]; /** * Post-initialization hook for Gemini CLI. * Adds ~/.crewly to the directory allowlist and ensures MCP server * configuration (e.g., playwright) is present in the project directory. * * @param sessionName - PTY session name * @param targetProjectPath - Optional target project path for MCP config. * Falls back to this.projectRoot if not provided. */ postInitialize(sessionName: string, targetProjectPath?: string, additionalAllowlistPaths?: string[]): Promise; /** * Ensure Gemini CLI MCP server configuration exists in the project directory. * * Creates or merges `.gemini/settings.json` with required MCP servers. * Delegates to the shared `ensureMcpConfig` in the base class. * * @param projectPath - Project directory where `.gemini/settings.json` will be created */ ensureGeminiMcpConfig(projectPath: string): Promise; /** * Ensure the project root `.env` file contains GEMINI_API_KEY. * Gemini CLI reads this key from `.env` in the working directory. * If the key exists in the process environment but not in `.env`, append it. * Also ensures `.gitignore` includes `.env` to prevent accidental commits. * * @param projectPath - Project directory where `.env` will be created/updated */ private ensureGeminiEnvFile; /** * Ensure Gemini trusted folders contain the required paths. * Gemini blocks `/directory add` for paths that are not pre-trusted. * Delegates to the shared addGeminiTrustedFolders utility. */ private ensureGeminiTrustedFolders; /** * Check if Gemini CLI is installed and configured */ checkGeminiInstallation(): Promise<{ isInstalled: boolean; version?: string; message: string; }>; /** * Initialize Gemini in an existing session */ initializeGeminiInSession(sessionName: string): Promise<{ success: boolean; message: string; }>; /** * Add a single project path to Gemini CLI allowlist * Uses '/directory add' command after Gemini CLI is running */ addProjectToAllowlist(sessionName: string, projectPath: string): Promise<{ success: boolean; message: string; }>; /** * Heuristic to detect text that is still sitting in Gemini's input box. * This indicates the message was typed but Enter was not processed. */ private isTextLikelyStuckAtPrompt; /** * Detect whether Gemini CLI output indicates a path is already allowlisted. */ private isPathAlreadyAllowlisted; /** * Add multiple project paths to Gemini CLI allowlist * Attempts a single batched slash command first, then falls back to * per-path commands for resiliency. */ addMultipleProjectsToAllowlist(sessionName: string, projectPaths: string[]): Promise<{ success: boolean; message: string; results: Array<{ path: string; success: boolean; error?: string; }>; }>; /** * Send a single batched `/directory add` command with comma-separated paths. */ private addProjectsToAllowlistBatch; /** * Wait until Gemini's slash-command queue is idle and the prompt is ready * for normal text input. */ private waitForSlashQueueToDrain; } //# sourceMappingURL=gemini-runtime.service.d.ts.map