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
JavaScript
#!/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');