Skip to main content
Glama
GeminiCliAdapter.ts3.27 kB
/** * GeminiCliAdapter - Adapter for Gemini CLI hook format * * DESIGN PATTERNS: * - Adapter pattern: Converts Gemini CLI format to normalized format * - Parser pattern: Extracts file paths and operations from tool inputs * * CODING STANDARDS: * - Parse Gemini CLI JSON stdin format exactly as specified * - Format output to match Gemini CLI hook response schema * - Handle missing/optional fields gracefully * * AVOID: * - Assuming all fields are present * - Hardcoding tool names (use constants if needed) * - Mutating input objects */ import { BaseAdapter } from './BaseAdapter'; import type { HookResponse } from '../types'; import { DECISION_ALLOW, DECISION_DENY, DECISION_ASK, DECISION_SKIP } from '../constants'; import { log } from '@agiflowai/aicode-utils'; /** * Gemini CLI hook input format (BeforeTool/AfterTool) */ export interface GeminiCliHookInput { tool_name: string; tool_input: Record<string, any>; cwd: string; session_id: string; event: 'BeforeTool' | 'AfterTool' | 'BeforeModel' | 'AfterModel'; llm_tool?: string; } /** * Gemini CLI hook output format */ interface GeminiCliHookOutput { decision: 'ALLOW' | 'DENY' | 'ASK_USER'; message?: string; updatedInput?: Record<string, any>; } /** * Adapter for Gemini CLI hook format */ export class GeminiCliAdapter extends BaseAdapter<GeminiCliHookInput> { /** * Parse Gemini CLI stdin into full hook input (preserves all fields) * * @param stdin - Raw JSON string from Gemini CLI * @returns Full Gemini CLI hook input */ parseInput(stdin: string): GeminiCliHookInput { log.debug('GeminiCliAdapter.parseInput - Raw input:', stdin); const input = JSON.parse(stdin) as GeminiCliHookInput; log.debug('GeminiCliAdapter.parseInput - Parsed input:', JSON.stringify(input, null, 2)); return input; } /** * Format normalized HookResponse into Gemini CLI output * * @param response - Normalized hook response * @returns JSON string for Gemini CLI */ formatOutput(response: HookResponse): string { log.debug( 'GeminiCliAdapter.formatOutput - Normalized response:', JSON.stringify(response, null, 2), ); // If decision is 'skip', return ALLOW with no message (transparent pass-through) if (response.decision === DECISION_SKIP) { const output = JSON.stringify( { decision: 'ALLOW', }, null, 2, ); log.debug('GeminiCliAdapter.formatOutput - Output (skip):', output); return output; } // Map our decision types to Gemini CLI format const decisionMap: Record<string, 'ALLOW' | 'DENY' | 'ASK_USER'> = { [DECISION_ALLOW]: 'ALLOW', [DECISION_DENY]: 'DENY', [DECISION_ASK]: 'ASK_USER', }; const output: GeminiCliHookOutput = { decision: decisionMap[response.decision] || 'ALLOW', }; // Add message if provided if (response.message) { output.message = response.message; } // Add updated input if provided if (response.updatedInput) { output.updatedInput = response.updatedInput; } const outputStr = JSON.stringify(output, null, 2); log.debug('GeminiCliAdapter.formatOutput - Output:', outputStr); return outputStr; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AgiFlow/aicode-toolkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server