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
412 lines (345 loc) • 13.2 kB
JavaScript
/**
* CGMB Post-install Script
* Automatically installs required dependencies and sets up integrations
*/
const { execSync, spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
// Color codes for console output
const colors = {
reset: '\x1b[0m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m'
};
// Logging functions
function log(message, level = 'info') {
const timestamp = new Date().toISOString().substring(11, 19);
const prefix = {
info: `${colors.blue}[INFO]${colors.reset}`,
success: `${colors.green}[SUCCESS]${colors.reset}`,
warning: `${colors.yellow}[WARNING]${colors.reset}`,
error: `${colors.red}[ERROR]${colors.reset}`
};
console.log(`${timestamp} ${prefix[level]} ${message}`);
}
// Check if command exists
function commandExists(command) {
try {
execSync(`which ${command}`, { stdio: 'ignore' });
return true;
} catch {
return false;
}
}
// Install package with error handling
async function installPackage(packageName, description) {
log(`Installing ${description}...`);
return new Promise((resolve) => {
const child = spawn('npm', ['install', '-g', packageName], {
stdio: ['pipe', 'pipe', 'pipe']
});
let output = '';
let errorOutput = '';
child.stdout.on('data', (data) => {
output += data.toString();
});
child.stderr.on('data', (data) => {
errorOutput += data.toString();
});
child.on('close', (code) => {
if (code === 0) {
log(`✅ ${description} installed successfully`, 'success');
resolve(true);
} else {
// Check if it's just a warning (package already exists)
if (errorOutput.includes('EEXIST') || errorOutput.includes('already exists')) {
log(`✅ ${description} already installed`, 'success');
resolve(true);
} else {
log(`⚠️ Failed to install ${description}: ${errorOutput.trim()}`, 'warning');
log(`📋 You can install it manually: npm install -g ${packageName}`, 'info');
resolve(false);
}
}
});
// Handle installation timeout (60 seconds)
setTimeout(() => {
child.kill('SIGTERM');
log(`⏰ Installation of ${description} timed out`, 'warning');
log(`📋 You can install it manually: npm install -g ${packageName}`, 'info');
resolve(false);
}, 60000);
});
}
// Check and install AI Studio MCP Server
async function setupAIStudioMCP() {
log('🔧 Setting up AI Studio MCP Server...');
// Check if aistudio-mcp-server is available
if (commandExists('aistudio-mcp-server')) {
log('✅ AI Studio MCP Server already available', 'success');
return true;
}
// Try to find it in node_modules
const possiblePaths = [
path.join(process.cwd(), 'node_modules', '.bin', 'aistudio-mcp-server'),
path.join(__dirname, '..', 'node_modules', '.bin', 'aistudio-mcp-server')
];
for (const testPath of possiblePaths) {
if (fs.existsSync(testPath)) {
log('✅ AI Studio MCP Server found in project dependencies', 'success');
return true;
}
}
// Install globally
log('📦 AI Studio MCP Server not found, attempting installation...');
const success = await installPackage('aistudio-mcp-server', 'AI Studio MCP Server');
if (!success) {
log('💡 AI Studio MCP Server installation failed. This is optional for basic functionality.', 'warning');
log(' You can install it later with: npm install -g aistudio-mcp-server', 'info');
}
return success;
}
// Check and install Gemini CLI
async function setupGeminiCLI() {
log('🔧 Checking Gemini CLI...');
if (commandExists('gemini')) {
log('✅ Gemini CLI already installed', 'success');
return true;
}
log('📦 Gemini CLI not found, attempting installation...');
const success = await installPackage('@google/gemini-cli', 'Gemini CLI');
if (!success) {
log('💡 Gemini CLI installation failed. You can install it later:', 'warning');
log(' npm install -g @google/gemini-cli', 'info');
}
return success;
}
// Check Claude Code CLI
function checkClaudeCode() {
log('🔧 Checking Claude Code CLI...');
if (commandExists('claude')) {
log('✅ Claude Code CLI found', 'success');
return true;
}
log('⚠️ Claude Code CLI not found', 'warning');
log('📋 Please install Claude Code CLI:', 'info');
log(' npm install -g @anthropic-ai/claude-code', 'info');
log(' Or visit: https://docs.anthropic.com/claude/docs/claude-code', 'info');
return false;
}
// Setup environment file
function setupEnvironment() {
log('🔧 Setting up environment configuration...');
const envPath = path.join(process.cwd(), '.env');
const envExamplePath = path.join(process.cwd(), '.env.example');
if (fs.existsSync(envPath)) {
log('✅ .env file already exists', 'success');
return true;
}
let envContent = '';
if (fs.existsSync(envExamplePath)) {
envContent = fs.readFileSync(envExamplePath, 'utf8');
log('📄 Using .env.example as template', 'info');
} else {
envContent = `# Claude-Gemini Multimodal Bridge Configuration
# Get your API key from: https://aistudio.google.com/app/apikey
GEMINI_API_KEY=your_gemini_api_key_here
AI_STUDIO_API_KEY=\${GEMINI_API_KEY}
# Optional: Customize paths if needed
CLAUDE_CODE_PATH=/usr/local/bin/claude
GEMINI_CLI_PATH=/usr/local/bin/gemini
# Logging and performance
LOG_LEVEL=info
ENABLE_CACHING=true
GEMINI_MODEL=gemini-2.0-flash-exp
`;
log('📄 Creating basic .env template', 'info');
}
try {
fs.writeFileSync(envPath, envContent, 'utf8');
log('✅ Created .env file', 'success');
log('📝 Please edit .env and add your API keys', 'info');
return true;
} catch (error) {
log(`❌ Failed to create .env file: ${error.message}`, 'error');
return false;
}
}
// Detect Node.js environment
async function detectNodeEnvironment() {
try {
const cgmbPath = execSync('which cgmb', { encoding: 'utf8' }).trim();
const nodePath = process.execPath; // Current Node.js path
return {
cgmbPath,
nodePath,
isNvm: cgmbPath.includes('.nvm'),
isNodebrew: cgmbPath.includes('.nodebrew'),
isVolta: cgmbPath.includes('.volta'),
detected: true
};
} catch (error) {
return { detected: false };
}
}
// Setup MCP integration with environment detection
async function setupMCPIntegration() {
log('🔧 Setting up Claude Code MCP integration...');
// Skip MCP setup if CGMB is being started in serve mode to prevent Claude Code duplication
if (process.env.CGMB_SERVE_MODE === 'true' ||
process.env.CGMB_NO_CLAUDE_EXEC === 'true' ||
process.argv.includes('serve')) {
log('🔄 Serve mode detected, skipping MCP setup to prevent Claude Code duplication', 'info');
log('💡 Run "cgmb setup-mcp" manually after server setup if needed', 'info');
return true;
}
// Detect Node.js environment
const env = await detectNodeEnvironment();
if (env.detected && (env.isNvm || env.isNodebrew || env.isVolta)) {
log('🔍 Detected Node.js version manager environment', 'info');
log(` Node.js path: ${env.nodePath}`, 'info');
log(` CGMB path: ${env.cgmbPath}`, 'info');
// Set environment variables for MCP configuration
process.env.CGMB_DETECTED_PATH = env.cgmbPath;
process.env.CGMB_DETECTED_NODE_PATH = env.nodePath;
}
try {
// Try to run cgmb setup-mcp using the cgmb command
try {
// Set environment variable to prevent nested Claude Code execution
process.env.CGMB_NO_CLAUDE_EXEC = 'true';
execSync('cgmb setup-mcp --force', {
stdio: 'inherit',
env: {
...process.env,
CGMB_NO_CLAUDE_EXEC: 'true',
CGMB_DETECTED_PATH: env.cgmbPath || '',
CGMB_DETECTED_NODE_PATH: env.nodePath || ''
}
});
log('✅ MCP integration configured with cgmb command', 'success');
if (env.detected && (env.isNvm || env.isNodebrew || env.isVolta)) {
log('✅ MCP configuration updated for your Node.js environment', 'success');
}
return true;
} catch (cgmbError) {
// Fallback to direct node execution if cgmb command not available
log('⚠️ cgmb command not available, trying direct execution...', 'warning');
const cgmbPath = path.join(process.cwd(), 'dist', 'cli.js');
if (fs.existsSync(cgmbPath)) {
process.env.CGMB_NO_CLAUDE_EXEC = 'true';
execSync(`node ${cgmbPath} setup-mcp --force`, {
stdio: 'inherit',
env: {
...process.env,
CGMB_NO_CLAUDE_EXEC: 'true',
CGMB_DETECTED_PATH: env.cgmbPath || '',
CGMB_DETECTED_NODE_PATH: env.nodePath || ''
}
});
log('✅ MCP integration configured with fallback method', 'success');
return true;
} else {
log('⚠️ CGMB not built yet. Run "npm run build" then "cgmb setup-mcp"', 'warning');
return false;
}
}
} catch (error) {
log('⚠️ MCP integration setup failed. You can set it up later with: cgmb setup-mcp --force', 'warning');
return false;
}
}
// Show completion summary
function showCompletionSummary(results) {
console.log('\n' + '='.repeat(60));
log('🎉 CGMB Post-install Setup Complete!', 'success');
console.log('='.repeat(60));
// Summary of what was installed
console.log('\n📊 Installation Summary:');
Object.entries(results).forEach(([component, success]) => {
const status = success ? '✅' : '❌';
console.log(` ${status} ${component}`);
});
console.log('\n📋 Next Steps:');
console.log('1. Edit .env file and add your API keys:');
console.log(' - Get Gemini API key: https://aistudio.google.com/app/apikey');
console.log('2. Build the project (if in development):');
console.log(' npm run build');
console.log('3. Verify installation:');
console.log(' cgmb verify');
console.log('4. Set up authentication:');
console.log(' cgmb auth --interactive');
if (!results['MCP Integration']) {
console.log('5. Set up Claude Code MCP integration:');
console.log(' cgmb setup-mcp');
}
console.log('\n💡 For help and documentation:');
console.log(' cgmb --help');
console.log(' cgmb setup-guide');
console.log('\n🚀 Ready to use CGMB!');
}
// Main setup function
async function main() {
console.log('\n' + '='.repeat(60));
log('🚀 CGMB Post-install Setup Starting...', 'info');
console.log('='.repeat(60) + '\n');
const results = {};
// Check system requirements
log('📋 Checking system requirements...');
// Check Node.js version
const nodeVersion = process.version;
const requiredNodeVersion = 'v18.0.0';
if (nodeVersion >= requiredNodeVersion) {
log(`✅ Node.js ${nodeVersion} (meets requirement: ${requiredNodeVersion}+)`, 'success');
} else {
log(`❌ Node.js ${nodeVersion} is too old. Required: ${requiredNodeVersion}+`, 'error');
process.exit(1);
}
// Setup components
try {
results['Claude Code CLI'] = checkClaudeCode();
results['Gemini CLI'] = await setupGeminiCLI();
results['AI Studio MCP'] = await setupAIStudioMCP();
results['Environment Config'] = setupEnvironment();
results['MCP Integration'] = await setupMCPIntegration();
// Show completion summary
showCompletionSummary(results);
} catch (error) {
log(`❌ Setup failed with error: ${error.message}`, 'error');
log('🔧 You can complete setup manually using:', 'info');
log(' cgmb auth --interactive', 'info');
log(' cgmb setup-mcp', 'info');
process.exit(1);
}
}
// Handle process termination
process.on('SIGINT', () => {
log('\n⚠️ Setup interrupted by user', 'warning');
log('🔧 You can complete setup later with:', 'info');
log(' cgmb auth --interactive', 'info');
process.exit(1);
});
process.on('SIGTERM', () => {
log('\n⚠️ Setup terminated', 'warning');
process.exit(1);
});
// Skip postinstall in CI environments
if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
log('🔄 CI environment detected, skipping interactive setup', 'info');
process.exit(0);
}
// Skip postinstall during npm publish
if (process.env.npm_lifecycle_event === 'prepublish' || process.env.npm_lifecycle_event === 'prepare') {
log('📦 Publish process detected, skipping setup', 'info');
process.exit(0);
}
// Run main setup
main().catch((error) => {
log(`❌ Unexpected error: ${error.message}`, 'error');
process.exit(1);
});