UNPKG

claude-gemini-multimodal-bridge

Version:

Enterprise-grade AI integration bridge connecting Claude Code, Gemini CLI, and Google AI Studio with intelligent routing and advanced multimodal processing capabilities

1,122 lines (1,121 loc) โ€ข 77.1 kB
#!/usr/bin/env node import { Command } from 'commander'; import { CGMBServer } from './core/CGMBServer.js'; import { logger } from './utils/logger.js'; import { loadEnvironmentSmart, getEnvironmentStatus } from './utils/envLoader.js'; import { setupCGMBMCP, getMCPStatus, getManualSetupInstructions } from './utils/mcpConfigManager.js'; import { execSync } from 'child_process'; import path from 'path'; import fs from 'fs'; import { OAuthManager } from './auth/OAuthManager.js'; import { AuthVerifier } from './auth/AuthVerifier.js'; import { InteractiveSetup } from './auth/InteractiveSetup.js'; import { AuthCache } from './auth/AuthCache.js'; import { LayerManager } from './core/LayerManager.js'; import { Logger } from './utils/logger.js'; import { withCLITimeout } from './utils/TimeoutManager.js'; function showChatHelp() { console.log('๐Ÿ’ฌ CGMB Chat - Primary interface for questions and research'); console.log(''); console.log('โœจ Simple usage:'); console.log(' cgmb chat "your question"'); console.log(' cgmb c "your question"'); console.log(''); console.log('๐Ÿ”ง Advanced usage:'); console.log(' cgmb chat "question" --model gemini-2.5-flash'); console.log(' cgmb chat "question" --fast'); console.log(''); console.log('๐ŸŒ Web search is automatic - just ask about current events!'); console.log(''); console.log('๐Ÿ“‹ Task examples:'); console.log(' cgmb chat "What are the latest AI trends in 2025?"'); console.log(' cgmb c "Android security best practices"'); console.log(' cgmb chat "Current cryptocurrency market status"'); console.log(''); console.log('๐ŸŽจ For other tasks:'); console.log(' cgmb generate-image "description" # Create images'); console.log(' cgmb analyze file.pdf # Analyze documents'); console.log(''); console.log('โ“ Having issues? Try: cgmb auth-status'); } function showGeminiHelp() { console.log('๐Ÿ”ง CGMB Gemini - Advanced/Troubleshooting tool only'); console.log(''); console.log('โš ๏ธ WARNING: This is an advanced troubleshooting command.'); console.log(' For normal use, avoid this command and use the recommended ones below.'); console.log(''); console.log('โœ… Recommended for normal use:'); console.log(' cgmb chat "your question" # Primary chat interface'); console.log(' cgmb generate-image "description" # Image generation'); console.log(' cgmb analyze file.pdf # Document analysis'); console.log(''); console.log('โŒ Advanced/Troubleshooting only:'); console.log(' cgmb gemini -p "question" # Direct CLI access'); console.log(' cgmb gemini "question" --fast # Performance testing'); console.log(''); console.log('๐Ÿ’ก Use standard cgmb commands for reliable results!'); console.log('๐Ÿ” Authentication issues? Try: cgmb auth-status'); } const program = new Command(); program .name('cgmb') .description('Claude-Gemini Multimodal Bridge - Enterprise-grade AI integration tool') .version('1.0.0'); program .command('serve') .description('Start the CGMB MCP server') .option('-c, --config <path>', 'Path to configuration file') .option('-v, --verbose', 'Enable verbose logging') .option('--debug', 'Enable debug logging') .action(async (options) => { try { process.env.CGMB_SERVE_MODE = 'true'; process.env.CGMB_NO_CLAUDE_EXEC = 'true'; if (options.verbose) { process.env.LOG_LEVEL = 'debug'; } if (options.debug) { process.env.LOG_LEVEL = 'debug'; } const loadOptions = { verbose: options.verbose || options.debug }; if (options.config) { loadOptions.searchPaths = [path.dirname(options.config)]; } const envResult = await loadEnvironmentSmart(loadOptions); if (!envResult.success && envResult.errors.length > 0) { logger.warn('Environment loading had issues', { errors: envResult.errors, foundFiles: envResult.foundFiles }); } if (envResult.loadedFrom) { logger.info('Environment loaded successfully', { source: envResult.loadedFrom, hasGeminiKey: !!process.env.GEMINI_API_KEY }); } const server = new CGMBServer(); await server.start(); const gracefulShutdown = async () => { logger.info('Shutting down CGMB server...'); try { if (server && typeof server.stop === 'function') { await server.stop(); } } catch (error) { logger.error('Error during server shutdown', error); } process.exit(0); }; process.on('SIGINT', gracefulShutdown); process.on('SIGTERM', gracefulShutdown); } catch (error) { logger.error('Failed to start CGMB server', error); process.exit(1); } }); program .command('setup') .description('Set up CGMB dependencies and configuration') .option('--force', 'Force reinstall dependencies') .action(async (options) => { try { logger.info('Setting up CGMB...'); const nodeVersion = process.version; const requiredVersion = 'v22.0.0'; if (nodeVersion < requiredVersion) { throw new Error(`Node.js ${requiredVersion} or higher is required. Current: ${nodeVersion}`); } logger.info('โœ“ Node.js version check passed'); await checkDependency('claude', 'Claude Code CLI'); await checkDependency('gemini', 'Gemini CLI'); const envPath = path.join(process.cwd(), '.env'); if (!fs.existsSync(envPath)) { const examplePath = path.join(process.cwd(), '.env.example'); if (fs.existsSync(examplePath)) { fs.copyFileSync(examplePath, envPath); logger.info('โœ“ Created .env configuration file'); logger.info('Note: API keys are optional if using OAuth authentication'); } } const logsDir = path.join(process.cwd(), 'logs'); if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir, { recursive: true }); logger.info('โœ“ Created logs directory'); } logger.info('Setup completed successfully!'); logger.info('Next steps:'); logger.info('1. Set up authentication: cgmb auth --interactive'); logger.info('2. Verify installation: cgmb verify'); logger.info('3. Start the server: cgmb serve'); logger.info(''); logger.info('๐Ÿ’ก Tip: OAuth authentication is recommended (no API keys needed)'); } catch (error) { logger.error('Setup failed', error); process.exit(1); } }); program .command('auth') .description('Manage authentication for all services') .option('--service <service>', 'Specific service to authenticate (gemini|aistudio|claude)') .option('--method <method>', 'Authentication method (oauth|apikey)') .option('--interactive', 'Interactive authentication setup') .option('--reset-cache', 'Reset authentication cache') .action(async (options) => { try { await loadEnvironmentSmart({ verbose: false }); const authManager = new OAuthManager(); const interactiveSetup = new InteractiveSetup(); logger.info('CGMB Authentication Manager'); if (options.resetCache) { const authCache = AuthCache.getInstance(); if (options.service) { authCache.forceRefresh(options.service); console.log(`โœ… Authentication cache cleared for ${options.service}`); } else { authCache.clear(); console.log('โœ… All authentication cache cleared'); } console.log('๐Ÿ’ก Next authentication check will verify fresh credentials'); process.exit(0); } if (options.interactive) { await interactiveSetup.runAuthSetupWizard(); } else if (options.service) { logger.info(`Setting up authentication for ${options.service}...`); await interactiveSetup.setupServiceAuth(options.service); } else { logger.info('Running full authentication setup...'); await interactiveSetup.runAuthSetupWizard(); } logger.info('Authentication setup completed successfully'); process.exit(0); } catch (error) { logger.error('Authentication setup failed', error); process.exit(1); } }); program .command('auth-status') .description('Check authentication status for all services') .option('--verbose', 'Show detailed authentication information') .action(async (options) => { try { await loadEnvironmentSmart({ verbose: false }); const verifier = new AuthVerifier(); const result = await verifier.verifyAllAuthentications(); console.log('\n๐Ÿ” Authentication Status Report\n'); console.log('โ•'.repeat(50)); Object.entries(result.services).forEach(([service, status]) => { const icon = status.success ? 'โœ…' : 'โŒ'; const serviceName = service.charAt(0).toUpperCase() + service.slice(1); console.log(`${icon} ${serviceName}: ${status.success ? 'Authenticated' : 'Not Authenticated'}`); if (options.verbose && status.status.userInfo) { console.log(` Method: ${status.status.method}`); console.log(` User: ${status.status.userInfo.email || 'N/A'}`); if (status.status.userInfo.quotaRemaining !== undefined) { console.log(` Quota: ${status.status.userInfo.quotaRemaining} requests remaining`); } if (status.status.userInfo.planType) { console.log(` Plan: ${status.status.userInfo.planType}`); } } if (!status.success && status.actionInstructions) { console.log(` โš ๏ธ Action needed: ${status.actionInstructions}`); } console.log(''); }); console.log('โ•'.repeat(50)); console.log(`Overall Status: ${result.overall ? '๐ŸŸข READY' : '๐ŸŸก NEEDS ATTENTION'}`); if (result.recommendations.length > 0) { console.log('\n๐Ÿ’ก Recommendations:'); result.recommendations.forEach(rec => console.log(` โ€ข ${rec}`)); } console.log(''); process.exit(0); } catch (error) { logger.error('Failed to check authentication status', error); process.exit(1); } }); program .command('quota-status') .description('Check Gemini API quota usage') .option('--detailed', 'Show detailed information') .action(async (options) => { process.env.CGMB_CLI_MODE = 'true'; console.log('๐Ÿ“Š Gemini API (Generative Language API) Quota Status'); console.log('===================================================='); console.log(); console.log('To check your actual API usage and quota:'); console.log(); console.log('1. Visit Google Cloud Console:'); console.log(' ๐Ÿ”— https://console.cloud.google.com'); console.log(); console.log('2. Navigate to:'); console.log(' APIs & Services โ†’ Dashboard โ†’ Generative Language API'); console.log(); console.log('3. View your real-time quota and usage metrics there.'); console.log(); console.log('๐Ÿ“š Official Documentation:'); console.log(' โ€ข Rate Limits: https://ai.google.dev/gemini-api/docs/rate-limits'); console.log(' โ€ข Pricing: https://ai.google.dev/gemini-api/docs/pricing'); console.log(); console.log('๐Ÿ’ก For current free tier limits and pricing details,'); console.log(' please refer to the official documentation above.'); process.exit(0); }); program .command('detect-paths') .description('Detect and show paths for required CLI tools') .option('--fix', 'Attempt to fix PATH issues automatically') .action(async (options) => { try { console.log('๐Ÿ” Detecting CLI Tool Paths'); console.log('==========================='); const tools = [ { name: 'Claude Code', commands: ['claude', 'claude-code'], env: 'CLAUDE_CODE_PATH' }, { name: 'Gemini CLI', commands: ['gemini'], env: 'GEMINI_CLI_PATH' }, { name: 'Node.js', commands: ['node'], env: 'NODE_PATH' }, { name: 'NPM', commands: ['npm'], env: 'NPM_PATH' } ]; for (const tool of tools) { console.log(`\n${tool.name}:`); let foundPath = null; for (const command of tool.commands) { try { const output = execSync(`which ${command} 2>/dev/null || where ${command} 2>nul`, { encoding: 'utf8', stdio: 'pipe', timeout: 5000, }); foundPath = output.trim().split('\n')[0]; if (foundPath) { console.log(` โœ… Found: ${foundPath}`); try { execSync(`${foundPath} --version 2>/dev/null || ${foundPath} -v 2>/dev/null`, { stdio: 'ignore', timeout: 3000, }); console.log(` Works: โœ…`); } catch { console.log(` Works: โŒ (command failed)`); } break; } } catch { continue; } } if (!foundPath) { console.log(` โŒ Not found in PATH`); if (tool.env) { console.log(` Set ${tool.env}=/path/to/${tool.commands[0]} in your environment`); } if (options.fix && tool.name === 'Gemini CLI') { console.log(` ๐Ÿ’ก Install with: npm install -g @google/gemini-cli`); } } } console.log('\n๐Ÿ“‹ Environment Variables:'); const envVars = ['AI_STUDIO_API_KEY', 'CLAUDE_CODE_PATH', 'GEMINI_CLI_PATH']; for (const envVar of envVars) { const value = process.env[envVar]; if (value) { const displayValue = envVar.includes('API_KEY') ? `${value.substring(0, 8)}...` : value; console.log(` โœ… ${envVar}: ${displayValue}`); } else { console.log(` โŒ ${envVar}: Not set`); } } console.log(''); console.log('๐Ÿ”ง Environment Variable Migration:'); const deprecatedVars = [ { old: 'GEMINI_API_KEY', new: 'AI_STUDIO_API_KEY', purpose: 'AI Studio authentication' }, { old: 'GOOGLE_AI_STUDIO_API_KEY', new: 'AI_STUDIO_API_KEY', purpose: 'AI Studio authentication' } ]; for (const { old, new: newVar, purpose } of deprecatedVars) { const value = process.env[old]; if (value) { console.log(` โš ๏ธ ${old}: ${value.substring(0, 8)}... (DEPRECATED)`); console.log(` โ†’ Migrate to: ${newVar} (for ${purpose})`); console.log(` โ†’ Add to .env: ${newVar}=${value}`); } } const hasProperAIStudioKey = !!process.env.AI_STUDIO_API_KEY; const hasDeprecatedKeys = deprecatedVars.some(v => !!process.env[v.old]); if (!hasProperAIStudioKey && hasDeprecatedKeys) { console.log(''); console.log('๐Ÿ”„ Migration Required:'); console.log(' AI Studio authentication detected using deprecated variable names.'); console.log(' This may cause the authentication failures seen in Error.md.'); console.log(' Please update your .env file to use AI_STUDIO_API_KEY.'); } else if (hasProperAIStudioKey) { console.log(''); console.log('โœ… Environment Configuration: Using recommended variable names'); } } catch (error) { logger.error('Failed to detect paths', error); console.error('โŒ Failed to detect paths:', error.message); process.exit(1); } }); program .command('setup-guide') .description('Show step-by-step authentication setup guide') .action(() => { const interactiveSetup = new InteractiveSetup(); interactiveSetup.displaySetupGuide(); }); program .command('setup-mcp') .description('Configure Claude Code MCP integration for CGMB') .option('--force', 'Force update existing configuration') .option('--dry-run', 'Show what would be done without making changes') .option('--manual', 'Show manual setup instructions instead of automatic setup') .action(async (options) => { try { await loadEnvironmentSmart({ verbose: false }); if (options.manual) { console.log('๐Ÿ“‹ Manual Claude Code MCP Setup Instructions'); console.log('โ•'.repeat(50)); console.log(getManualSetupInstructions()); return; } console.log('๐Ÿ”ง Setting up Claude Code MCP integration...\n'); let claudeVersion = ''; if (process.env.CGMB_NO_CLAUDE_EXEC === 'true') { console.log('๐Ÿ”„ Claude command execution skipped (serve mode protection)'); console.log('๐Ÿ’ก Manual setup required. See: cgmb setup-mcp --manual'); return; } try { claudeVersion = execSync('claude --version', { encoding: 'utf8' }).trim(); console.log(`Claude Code CLI version: ${claudeVersion}`); } catch (error) { console.log('โš ๏ธ Could not detect Claude Code CLI version'); } let hasNewMCPCommand = false; if (process.env.CGMB_NO_CLAUDE_EXEC !== 'true') { try { execSync('claude mcp --help', { stdio: 'ignore' }); hasNewMCPCommand = true; console.log('โœ… Detected new Claude Code CLI with mcp command support\n'); } catch { console.log('โ„น๏ธ Using legacy MCP configuration method\n'); } } if (hasNewMCPCommand && !options.force && process.env.CGMB_NO_CLAUDE_EXEC !== 'true') { try { const mcpListOutput = execSync('claude mcp list', { encoding: 'utf8' }); if (mcpListOutput.includes('claude-gemini-multimodal-bridge')) { console.log('โœ… CGMB is already configured in Claude Code MCP'); console.log('\nCurrent configuration:'); const mcpGetOutput = execSync('claude mcp get claude-gemini-multimodal-bridge', { encoding: 'utf8' }); console.log(mcpGetOutput); if (!options.force) { console.log('\n๐Ÿ’ก To reconfigure, use: cgmb setup-mcp --force'); return; } } console.log('Adding CGMB to Claude Code using new MCP command...'); const addCommand = 'claude mcp add claude-gemini-multimodal-bridge cgmb serve -e NODE_ENV=production'; if (options.dryRun) { console.log(`๐Ÿงช Dry Run: Would execute: ${addCommand}`); return; } execSync(addCommand, { stdio: 'inherit' }); console.log('\nโœ… Successfully added CGMB to Claude Code MCP!'); console.log('\nNext steps:'); console.log('1. Restart Claude Code to load the new MCP configuration'); console.log('2. Run "cgmb verify" to test the connection'); console.log('3. Check that CGMB tools are available in Claude Code'); return; } catch (error) { console.log('โš ๏ธ Failed to use new MCP command, falling back to legacy method'); logger.debug('MCP command error', { error: error.message }); } } const status = await getMCPStatus(); console.log('๐Ÿ“Š Current MCP Configuration Status'); console.log('โ•'.repeat(60)); console.log(`Configuration Path: ${status.configPath || 'โŒ Claude Code config not found'}`); console.log(`CGMB Configured: ${status.isConfigured ? 'โœ… Yes' : 'โŒ No'}`); if (status.currentConfig) { console.log(`Current Command: ${status.currentConfig.command}`); console.log(`Current Args: ${status.currentConfig.args.join(' ')}`); } if (status.recommendations.length > 0) { console.log('\n๐Ÿ’ก System Status:'); status.recommendations.forEach(rec => { const icon = rec.includes('properly configured') ? 'โœ…' : 'โ„น๏ธ'; console.log(` ${icon} ${rec}`); }); } if (status.issues.length > 0) { console.log('\nโš ๏ธ Issues Detected:'); status.issues.forEach(issue => console.log(` โ€ข ${issue}`)); } console.log(''); if (options.dryRun) { console.log('๐Ÿงช Dry Run Mode - Showing what would be done:'); console.log(''); } const result = await setupCGMBMCP({ force: options.force, dryRun: options.dryRun }); if (result.success) { const actionText = options.dryRun ? 'Would be' : 'Successfully'; console.log(`โœ… ${actionText} ${result.action} CGMB MCP configuration`); if (result.configPath) { console.log(`๐Ÿ“ Configuration file: ${result.configPath}`); } if (result.backupPath) { console.log(`๐Ÿ’พ Backup created: ${result.backupPath}`); } if (!options.dryRun) { console.log(''); console.log('๐ŸŽ‰ Setup Complete!'); console.log(''); console.log('Next steps:'); console.log('1. Restart Claude Code to load the new MCP configuration'); console.log('2. Run "cgmb verify" to test the connection'); console.log('3. Check that CGMB tools are available in Claude Code'); if (status.recommendations.length > 0) { console.log(''); console.log('๐Ÿ’ก Recommendations:'); status.recommendations.forEach(rec => console.log(` โ€ข ${rec}`)); } } } else { console.log(`โŒ ${result.message}`); if (result.action === 'error') { console.log(''); console.log('๐Ÿ”ง Manual Setup Alternative:'); console.log('Run: cgmb setup-mcp --manual'); } process.exit(1); } } catch (error) { logger.error('MCP setup failed', error); console.log('โŒ Failed to setup MCP configuration'); console.log(''); console.log('๐Ÿ”ง Try manual setup instead:'); console.log(' cgmb setup-mcp --manual'); process.exit(1); } }); program .command('mcp-status') .description('Check Claude Code MCP configuration status') .action(async () => { try { await loadEnvironmentSmart({ verbose: false }); console.log('๐Ÿ“Š Claude Code MCP Configuration Status'); console.log('โ•'.repeat(50)); const status = await getMCPStatus(); console.log(`Configuration Path: ${status.configPath || 'Not found'}`); console.log(`CGMB Configured: ${status.isConfigured ? 'โœ… Yes' : 'โŒ No'}`); console.log(''); if (status.currentConfig) { console.log('๐Ÿ”ง Current CGMB Configuration:'); console.log(` Command: ${status.currentConfig.command}`); console.log(` Arguments: ${status.currentConfig.args.join(' ')}`); if (status.currentConfig.env) { console.log(` Environment: ${Object.keys(status.currentConfig.env).join(', ')}`); } console.log(''); } if (status.issues.length > 0) { console.log('โš ๏ธ Issues:'); status.issues.forEach(issue => console.log(` โ€ข ${issue}`)); console.log(''); } if (status.recommendations.length > 0) { console.log('๐Ÿ’ก Recommendations:'); status.recommendations.forEach(rec => console.log(` โ€ข ${rec}`)); console.log(''); } if (!status.isConfigured) { console.log('๐Ÿš€ To setup MCP integration, run:'); console.log(' cgmb setup-mcp'); console.log(''); console.log('๐Ÿ“‹ For manual setup instructions, run:'); console.log(' cgmb setup-mcp --manual'); } } catch (error) { logger.error('Failed to check MCP status', error); process.exit(1); } }); program .command('verify') .description('Verify CGMB installation and authentication') .option('--fix', 'Attempt to fix authentication issues automatically') .action(async (options) => { try { logger.info('๐Ÿ” Verifying CGMB installation and authentication...'); await loadEnvironmentSmart({ verbose: false }); const authVerifier = new AuthVerifier(); const interactiveSetup = new InteractiveSetup(); const systemChecks = [ { name: 'Node.js version', check: () => { const version = process.version; const required = 'v22.0.0'; if (version < required) { throw new Error(`Node.js ${required}+ required, found ${version}`); } return true; } }, { name: 'Project dependencies', check: () => { const packagePath = path.join(process.cwd(), 'package.json'); return fs.existsSync(packagePath); } }, { name: 'Claude Code CLI', check: () => checkCommand('claude --version') }, { name: 'Gemini CLI', check: () => checkCommand('gemini --help') } ]; logger.info('\n๐Ÿ“‹ System Requirements Check:'); let systemChecksPassed = true; for (const { name, check } of systemChecks) { try { await check(); logger.info(`โœ“ ${name}`); } catch (error) { logger.error(`โœ— ${name}: ${error.message}`); systemChecksPassed = false; } } logger.info('\n๐Ÿ” Authentication Verification:'); const authResults = await authVerifier.verifyAllAuthentications(); let authChecksPassed = true; Object.entries(authResults.services).forEach(([service, result]) => { const icon = result.success ? 'โœ…' : 'โŒ'; const serviceName = service.charAt(0).toUpperCase() + service.slice(1); logger.info(`${icon} ${serviceName}: ${result.success ? 'Authenticated' : 'Not Authenticated'}`); if (!result.success) { authChecksPassed = false; if (result.error) { logger.info(` Error: ${result.error}`); } if (result.actionInstructions) { logger.info(` Action: ${result.actionInstructions}`); } } }); logger.info('\n๐Ÿ”— MCP Configuration Verification:'); const mcpStatus = await getMCPStatus(); let mcpChecksPassed = true; const mcpIcon = mcpStatus.isConfigured ? 'โœ…' : 'โŒ'; logger.info(`${mcpIcon} Claude Code MCP Integration: ${mcpStatus.isConfigured ? 'Configured' : 'Not Configured'}`); if (!mcpStatus.isConfigured) { mcpChecksPassed = false; logger.info(' Action: Run "cgmb setup-mcp" to configure MCP integration'); } else if (mcpStatus.currentConfig) { logger.info(` Command: ${mcpStatus.currentConfig.command}`); logger.info(` Args: ${mcpStatus.currentConfig.args.join(' ')}`); } if (mcpStatus.issues.length > 0) { mcpStatus.issues.forEach(issue => { logger.info(` โš ๏ธ ${issue}`); }); } const allPassed = systemChecksPassed && authChecksPassed && mcpChecksPassed; logger.info('\n' + 'โ•'.repeat(50)); if (allPassed) { logger.info('๐ŸŽ‰ All verification checks passed!'); logger.info('\n๐Ÿš€ Testing server initialization...'); try { const server = new CGMBServer(); await server.initialize(); logger.info('โœ“ Server initialization test passed'); if (server && typeof server.cleanup === 'function') { await server.cleanup(); } } catch (initError) { logger.warn('Server initialization test failed, but basic checks passed', { error: initError.message }); logger.info('โœ“ Basic verification completed (server test skipped)'); } logger.info('\nโœจ CGMB is ready to use!'); logger.info('๐Ÿ’ก Try: cgmb serve'); process.exit(0); } else { logger.error('โš ๏ธ Some verification checks failed', new Error('Verification checks failed')); if (options.fix && !authChecksPassed) { logger.info('\n๐Ÿ”ง Attempting to fix authentication issues...'); try { await interactiveSetup.runAuthSetupWizard(); logger.info('โœ“ Authentication setup completed'); logger.info('๐Ÿ’ก Please run "cgmb verify" again to confirm fixes'); } catch (fixError) { logger.error('โŒ Automatic fix failed', fixError); logger.info('๐Ÿ’ก Please run "cgmb auth --interactive" for manual setup'); } } else if (!authChecksPassed) { logger.info('\n๐Ÿ’ก To fix authentication issues:'); logger.info(' Run: cgmb verify --fix'); logger.info(' Or: cgmb auth --interactive'); } if (!systemChecksPassed) { logger.info('\n๐Ÿ’ก To fix system issues:'); logger.info(' 1. Install missing CLI tools'); logger.info(' 2. Run: cgmb setup'); logger.info(' 3. Run: cgmb verify'); } if (!mcpChecksPassed) { logger.info('\n๐Ÿ’ก To fix MCP integration:'); logger.info(' 1. Run: cgmb setup-mcp'); logger.info(' 2. Restart Claude Code'); logger.info(' 3. Run: cgmb verify'); } if (authResults.recommendations.length > 0) { logger.info('\n๐Ÿ“ Recommendations:'); authResults.recommendations.forEach(rec => logger.info(` โ€ข ${rec}`)); } if (mcpStatus.recommendations.length > 0) { logger.info('\n๐Ÿ”— MCP Recommendations:'); mcpStatus.recommendations.forEach(rec => logger.info(` โ€ข ${rec}`)); } process.exit(1); } } catch (error) { logger.error('โŒ Verification failed', error); logger.info('\n๐Ÿ’ก Try:'); logger.info(' 1. cgmb setup'); logger.info(' 2. cgmb auth --interactive'); logger.info(' 3. cgmb verify'); process.exit(1); } }); program .command('test') .description('Run a test multimodal processing request') .option('-f, --file <path>', 'Path to test file') .option('-p, --prompt <text>', 'Test prompt', 'Analyze this content') .option('--timeout <ms>', 'Timeout in milliseconds', '120000') .action(async (options) => { try { await loadEnvironmentSmart({ verbose: false }); logger.info('Running CGMB test...'); const server = new CGMBServer(); await server.initialize(); const { MultimodalProcess } = await import('./tools/multimodalProcess.js'); const processor = new MultimodalProcess(); if (options.file) { logger.info(`Testing with file: ${options.file}`); const result = await processor.processSingleFile(options.file, options.prompt, { timeout: parseInt(options.timeout) }); logger.info('โœ… File processing test completed successfully!'); logger.info(`Result: ${result.content.substring(0, 200)}...`); logger.info(`Processing time: ${result.processing_time}ms`); logger.info(`Layers involved: ${result.layers_involved?.join(', ')}`); } else { logger.info('Testing with text-only prompt...'); const result = await processor.processMultimodal({ prompt: options.prompt, files: [], workflow: 'analysis', options: { timeout: parseInt(options.timeout) } }); logger.info('โœ… Text processing test completed successfully!'); logger.info(`Result: ${result.content.substring(0, 200)}...`); logger.info(`Processing time: ${result.processing_time}ms`); logger.info(`Layers involved: ${result.layers_involved?.join(', ')}`); } logger.info('๐ŸŽ‰ CGMB test completed successfully!'); logger.info('All systems are working correctly'); process.exit(0); } catch (error) { logger.error('โŒ Test failed', error); logger.error('This might indicate authentication or configuration issues'); logger.info('๐Ÿ’ก Try running: cgmb verify'); process.exit(1); } }); program .command('chat') .alias('c') .description('Chat with Gemini (user-friendly interface)') .argument('[prompt...]', 'Your question or prompt') .option('-m, --model <model>', 'Gemini model to use', 'gemini-2.5-pro') .option('--fast', 'Use fast path for better performance') .action(async (promptArgs, options) => { try { const prompt = promptArgs.join(' '); if (!prompt) { showChatHelp(); process.exit(1); } const imageGenerationPatterns = [ /generate.*image/i, /create.*image/i, /make.*image/i, /draw.*image/i, /generate.*picture/i, /create.*picture/i, /image.*of/i, /picture.*of/i ]; if (imageGenerationPatterns.some(pattern => pattern.test(prompt))) { console.log('\n๐Ÿ’ก It looks like you want to generate an image!'); console.log(''); console.log('The chat command doesn\'t generate images. Use the dedicated command:'); console.log(` cgmb generate-image "${prompt}"`); console.log(''); console.log('This will automatically:'); console.log(' โ€ข Sanitize your prompt (cute โ†’ friendly-looking)'); console.log(' โ€ข Add safety prefixes'); console.log(' โ€ข Generate the image properly'); console.log(''); process.exit(0); } console.log('๐Ÿ’ก Auto-detected prompt (using chat mode)'); options.prompt = prompt; await executeGeminiCommand(options); } catch (error) { const errorMessage = error.message; if (errorMessage.includes('function response parts') || errorMessage.includes('function call parts')) { logger.error('โŒ Chat API Error', error); logger.info('๐Ÿ”ง This looks like an authentication issue:'); logger.info(' โ€ข Try OAuth: gemini auth'); logger.info(' โ€ข Check status: cgmb auth-status --verbose'); } else { logger.error('โŒ Chat command failed', error); logger.info('๐Ÿ’ก Troubleshooting:'); logger.info(' โ€ข Check auth: cgmb auth-status'); logger.info(' โ€ข Verify setup: cgmb verify'); } process.exit(1); } }); program .command('gemini') .description('โš ๏ธ ADVANCED: Direct Gemini CLI access (troubleshooting only - use cgmb chat instead)') .argument('[prompt...]', 'Direct prompt (auto-detects if -p missing)') .option('-p, --prompt <text>', 'Explicit prompt for Gemini CLI') .option('-m, --model <model>', 'Gemini model to use', 'gemini-2.5-pro') .option('-f, --file <path>', 'File to analyze with prompt') .option('--fast', 'Use direct CLI call (bypass CGMB layers for faster response)') .action(async (promptArgs, options) => { try { let prompt = options.prompt; if (!prompt && promptArgs.length > 0) { prompt = promptArgs.join(' '); console.log('๐Ÿ’ก Auto-detected prompt (tip: use -p for explicit mode)'); } if (!prompt) { showGeminiHelp(); process.exit(1); } const imageGenerationPatterns = [ /generate.*image/i, /create.*image/i, /make.*image/i, /draw.*image/i, /generate.*picture/i, /create.*picture/i, /image.*of/i, /picture.*of/i ]; if (imageGenerationPatterns.some(pattern => pattern.test(prompt))) { console.log('\n๐Ÿ’ก It looks like you want to generate an image!'); console.log(''); console.log('The gemini command doesn\'t generate images. Use the dedicated command:'); console.log(` cgmb generate-image "${prompt}"`); console.log(''); console.log('This will automatically:'); console.log(' โ€ข Sanitize your prompt (cute โ†’ friendly-looking)'); console.log(' โ€ข Add safety prefixes'); console.log(' โ€ข Generate the image properly'); console.log(''); process.exit(0); } options.prompt = prompt; await executeGeminiCommand(options); } catch (error) { const errorMessage = error.message; if (errorMessage.includes('function response parts') || errorMessage.includes('function call parts')) { logger.error('โŒ API Function Call Error', error); logger.info('๐Ÿ”ง This error usually indicates an authentication issue:'); logger.info(' 1. Try OAuth authentication: gemini auth'); logger.info(' 2. Check API key configuration'); logger.info(' 3. Verify Gemini CLI version: gemini --version'); logger.info(' 4. Check status: cgmb auth-status --verbose'); } else if (errorMessage.includes('UNAUTHENTICATED') || errorMessage.includes('API_KEY')) { logger.error('โŒ Authentication Error', error); logger.info('๐Ÿ”ง Fix authentication:'); logger.info(' โ€ข OAuth (recommended): gemini auth'); logger.info(' โ€ข Check status: cgmb auth-status'); } else if (errorMessage.includes('quota exceeded') || errorMessage.includes('Quota exceeded') || errorMessage.includes('Resource exhausted')) { logger.error('โŒ Gemini CLI Service Quota Exceeded', error); logger.info('๐Ÿ”ง This is a Gemini CLI service limitation (separate from Gemini API):'); logger.info(' โ€ข Wait a few minutes for quota reset'); logger.info(' โ€ข Try AI Studio layer: cgmb aistudio -p "your question"'); logger.info(' โ€ข Check AI Studio quota: cgmb quota-status'); logger.info(' ๐Ÿ’ก Note: Gemini CLI quota โ‰  Gemini API quota (different services)'); } else if (errorMessage.includes('not found') || errorMessage.includes('command not found')) { logger.error('โŒ Gemini CLI Not Found', error); logger.info('๐Ÿ”ง Install Gemini CLI:'); logger.info(' โ€ข Run setup: cgmb setup'); logger.info(' โ€ข Manual install: npm install -g @google/gemini-cli'); } else if (errorMessage.includes('timeout')) { logger.error('โŒ Request Timeout', error); logger.info('๐Ÿ’ก Try:'); logger.info(' โ€ข Shorter prompt'); logger.info(' โ€ข Check network connection'); logger.info(' โ€ข Use --fast flag for direct calls'); } else { logger.error('โŒ Gemini CLI processing failed', error); logger.info('๐Ÿ’ก General troubleshooting:'); logger.info(' โ€ข Check authentication: cgmb auth-status'); logger.info(' โ€ข Verify setup: cgmb verify'); logger.info(' โ€ข View help: cgmb gemini --help'); } process.exit(1); } }); async function executeGeminiCommand(options) { try { if (!options.prompt) { throw new Error('Prompt is required'); } if (process.argv.includes('--search')) { console.log('\n๐Ÿ’ก Note: Web search is automatically enabled in Gemini CLI.'); console.log(' No --search flag needed. Just ask about current events or trends!'); console.log(' Example: cgmb gemini -p "latest AI security trends 2025"\n'); } await loadEnvironmentSmart({ verbose: false }); logger.info('๐Ÿ” Processing with Gemini CLI...'); if (options.fast && !options.file) { logger.info('Using fast path (direct Gemini CLI call)...'); const args = ['gemini']; if (options.model && options.model !== 'gemini-2.5-pro') { args.push('-m', options.model); } args.push('-p', options.prompt); try { const { spawn } = await import('child_process'); const child = spawn(args[0], args.slice(1)); let result = ''; let error = ''; child.stdout?.on('data', (data) => { result += data.toString(); }); child.stderr?.on('data', (data) => { error += data.toString(); }); await new Promise((resolve, reject) => { child.on('close', (code) => { if (code !== 0) { reject(new Error(`Process exited with code ${code}: ${error}`)); } else { resolve(); } }); child.on('error', (err) => { reject(err); }); setTimeout(() => { child.kill(); reject(new Error('Process timeout')); }, 90000); }); logger.info('โœ… Fast path Gemini CLI processing completed'); console.log('\n๐Ÿ“‹ Result:'); console.log('โ•'.repeat(50)); console.log(result); console.log('\n๐Ÿ“Š Metadata:'); console.log('Method: Direct Gemini CLI (fast path)'); console.log('Bypass: CGMB layer overhead eliminated'); return; } catch (error) { logger.warn('Fast path failed, falling back to CGMB layers', { error: error.message }); } } const { GeminiCLILayer } = await import('./layers/GeminiCLILayer.js'); const geminiLayer = new GeminiCLILayer(); await geminiLayer.initialize(); let result; if (options.file) { result = await geminiLayer.processFiles([{ path: options.file, type: 'document' }], options.prompt); } else { result = await geminiLayer.execute({ type: 'text_processing', prompt: options.prompt, useSearch: true }); } logger.info('โœ… Gemini CLI processing completed'); console.log('\n๐Ÿ“‹ Result:'); console.log('โ•'.repeat(50)); if ('data' in result) { console.log(result.data); } else if ('content' in result) { console.log(result.content); } else { console.log('Processing completed'); } if (result.metadata) { console.log('\n๐Ÿ“Š Metadata:'); const metadata = result.metadata; console.log(`Processing time: ${metadata.duration || metadata.processing_time || 'N/A'}ms`); console.log(`Model: ${metadata.model || 'N/A'}`); console.log(`Tokens used: ${metadata.tokens_used || 'N/A'}`); } process.exit(0); } catch (error) { logger.error('โŒ Gemini CLI processing failed', error); logger.info('๐Ÿ’ก Check authentication: cgmb auth-status'); process.exit(1); } } program .command('aistudio') .description('โš ๏ธ ADVANCED: Direct AI Studio access (use cgmb analyze instead for documents)') .option('-p, --prompt <text>', 'Prompt for AI Studio') .option('-f, --files <paths...>', 'Files to process (images, documents, etc.)') .option('-m, --model <model>', 'AI Studio model to use', 'gemini-2.0-flash-exp') .action(async (options) => { try { if (!options.prompt) { logger.error('Prompt is required. Use: cgmb aistudio -p "your question" -f file1 file2'); process.exit(1); } const imageGenerationPatterns = [ /generate.*image/i, /create.*image/i, /make.*image/i, /draw.*image/i, /generate.*picture/i, /create.*picture/i, /image.*of/i, /picture.*of/i ]; if (imageGenerationPatterns.some(pattern => pattern.test(options.prompt))) { console.log('\nโš ๏ธ WARNING: You seem to be trying to generate an image.'); console.log(''); console.log('The "cgmb aistudio" command does NOT generate images - it only analyzes text!'); console.log(''); console.log('โœ… To generate images, use the correct command:'); console.log(` cgmb generate-image "${options.prompt}"`); console.log(''); console.log('Example:'); console.log(' cgmb generate-image "cute cat" # This will generate an image'); console.log(''); console.log('The generate-image command includes:'); console.log(' โ€ข Automatic prompt sanitization (cute โ†’ friendly-looking)'); console.log(' โ€ข Safety prefixes to avoid content policy issues'); console.log(' โ€ข Proper image generation with Gemini 2.0 Flash'); console.log(''); console.log('Would you like to continue with text analysis anyway? (y/N)'); const readline = await import('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const answer = await new Promise((resolve) => { rl.question('', (answer) => { rl.close(); resolve(answer.toLowerCase()); }); }); if (answer !== 'y' && answer !== 'yes') { console.log('\n๐Ÿ’ก Redirecting to image generation command...'); console.log(` Run: cgmb generate-image "${options.prompt}"`); process.exit(0); } } await loadEnvironmentSmart({ verbose: false }); logger.info('๐ŸŽจ Processing with AI Studio...'); const { AIStudioLayer } = await import('./layers/AIStudioLayer.js'); const aiStudioLayer = new AIStudioLayer(); await aiStudioLayer.initialize(); const files = options.files || []; if (files.length === 0) { console.log('\nโŒ ERROR: AI Studio layer requires multimodal content (files)'); console.log(''); console.log('๐Ÿ“‹ AI Studio is designed for multimodal processing with files.'); console.log(' For text-only queries, use the appropriate layer:'); console.log(''); console.log('โœ… For web search & current information:'); console.log(` cgmb chat "${options.prompt}"`); console.log(` cgmb gemini -p "${options.prompt}"`); console.log(''); console.log('โœ… For complex reasoning & analysis:'); console.log(` cgmb process -p "${options.prompt}"`); console.log(''); console.log('โœ… For AI Studio with files:'); console.log(` cgmb aistudio -p "${options.prompt}" -f file1.pdf file2.jpg`); console.log(''); console.log('๐Ÿ’ก This enforces CGMB\'s architectural separation of concerns.'); process.exit(1); } logger.info(`Processing ${files.length} files with AI Studio`); const result = await aiStudioLayer.execute({ type: 'multimodal_processing', prompt: options.prompt, files: files.map((f) => ({ path: f, type: 'document' })), model: options.model }); logger.info('โœ… AI Studio processing completed');