UNPKG

blue-beatle

Version:

šŸ¤– AI-Powered Development Assistant - Intelligent code analysis, problem solving, and terminal automation using Gemini API

435 lines (361 loc) • 15 kB
#!/usr/bin/env node /** * šŸš€ Blue Beatle Setup Script * Handles initial installation and configuration */ const fs = require('fs-extra'); const path = require('path'); const { execSync } = require('child_process'); const chalk = require('chalk'); const inquirer = require('inquirer'); const ora = require('ora'); class BlueBeatleSetup { constructor() { this.isWindows = process.platform === 'win32'; this.isMacOS = process.platform === 'darwin'; this.isLinux = process.platform === 'linux'; this.requirements = { node: '16.0.0', npm: '8.0.0' }; } async run() { try { console.clear(); this.showWelcome(); await this.checkSystemRequirements(); await this.installDependencies(); await this.setupConfiguration(); await this.createShortcuts(); await this.finalizeInstallation(); this.showSuccess(); } catch (error) { console.error(chalk.red('āŒ Setup failed:'), error.message); process.exit(1); } } showWelcome() { const figlet = require('figlet'); const gradient = require('gradient-string'); const title = figlet.textSync('Blue Beatle', { font: 'ANSI Shadow', horizontalLayout: 'default' }); console.log(gradient(['#00f5ff', '#0080ff'])(title)); console.log(chalk.cyan.bold('šŸ¤– AI-Powered Development Assistant')); console.log(chalk.gray('Setting up your intelligent coding companion...\n')); } async checkSystemRequirements() { const spinner = ora('šŸ” Checking system requirements...').start(); try { // Check Node.js const nodeVersion = process.version.slice(1); if (!this.compareVersions(nodeVersion, this.requirements.node)) { throw new Error(`Node.js ${this.requirements.node} or higher required. Found: ${nodeVersion}`); } // Check npm const npmVersion = execSync('npm --version', { encoding: 'utf8' }).trim(); if (!this.compareVersions(npmVersion, this.requirements.npm)) { throw new Error(`npm ${this.requirements.npm} or higher required. Found: ${npmVersion}`); } // Check internet connection await this.checkInternetConnection(); spinner.succeed('āœ… System requirements met'); } catch (error) { spinner.fail('āŒ System requirements check failed'); throw error; } } compareVersions(current, required) { const currentParts = current.split('.').map(Number); const requiredParts = required.split('.').map(Number); for (let i = 0; i < Math.max(currentParts.length, requiredParts.length); i++) { const currentPart = currentParts[i] || 0; const requiredPart = requiredParts[i] || 0; if (currentPart > requiredPart) return true; if (currentPart < requiredPart) return false; } return true; } async checkInternetConnection() { try { const https = require('https'); return new Promise((resolve, reject) => { const req = https.request('https://www.google.com', { timeout: 5000 }, (res) => { resolve(true); }); req.on('error', reject); req.on('timeout', () => reject(new Error('Internet connection timeout'))); req.end(); }); } catch (error) { throw new Error('Internet connection required for installation'); } } async installDependencies() { const spinner = ora('šŸ“¦ Installing dependencies...').start(); try { // Install production dependencies execSync('npm install --production', { stdio: 'pipe', cwd: process.cwd() }); spinner.succeed('āœ… Dependencies installed'); } catch (error) { spinner.fail('āŒ Failed to install dependencies'); throw new Error(`Dependency installation failed: ${error.message}`); } } async setupConfiguration() { console.log(chalk.cyan('\nāš™ļø Configuration Setup\n')); const { setupType } = await inquirer.prompt([{ type: 'list', name: 'setupType', message: 'Choose setup type:', choices: [ { name: 'šŸš€ Quick Setup (recommended)', value: 'quick' }, { name: 'šŸ”§ Custom Setup', value: 'custom' }, { name: 'ā­ļø Skip Configuration', value: 'skip' } ] }]); if (setupType === 'skip') { console.log(chalk.yellow('ā­ļø Configuration skipped. You can run "blue-beatle setup" later.')); return; } if (setupType === 'quick') { await this.quickSetup(); } else { await this.customSetup(); } } async quickSetup() { console.log(chalk.blue('šŸš€ Quick Setup - Using recommended settings\n')); const { apiKey } = await inquirer.prompt([{ type: 'confirm', name: 'apiKey', message: 'Do you have a Gemini API key to setup now?', default: false }]); if (apiKey) { const { key } = await inquirer.prompt([{ type: 'password', name: 'key', message: 'Enter your Gemini API key:', mask: '*' }]); // Save API key securely await this.saveApiKey(key); } // Create default configuration await this.createDefaultConfig(); } async customSetup() { console.log(chalk.blue('šŸ”§ Custom Setup\n')); const config = await inquirer.prompt([ { type: 'input', name: 'userName', message: 'Your name:', default: require('os').userInfo().username }, { type: 'input', name: 'userEmail', message: 'Your email (optional):' }, { type: 'confirm', name: 'safeMode', message: 'Enable safe mode for terminal commands?', default: true }, { type: 'confirm', name: 'autoUpdate', message: 'Enable automatic updates?', default: true }, { type: 'list', name: 'defaultTemplate', message: 'Default project template:', choices: ['react', 'node', 'vue', 'python', 'rust', 'go'], default: 'node' } ]); await this.createCustomConfig(config); } async saveApiKey(apiKey) { const ConfigManager = require('../src/config-manager'); const configManager = new ConfigManager(); await configManager.initialize(); await configManager.setSecret('geminiApiKey', apiKey); } async createDefaultConfig() { const ConfigManager = require('../src/config-manager'); const configManager = new ConfigManager(); await configManager.initialize(); // Default config is already created in ConfigManager } async createCustomConfig(config) { const ConfigManager = require('../src/config-manager'); const configManager = new ConfigManager(); await configManager.initialize(); await configManager.set('user.name', config.userName); if (config.userEmail) { await configManager.set('user.email', config.userEmail); } await configManager.set('terminal.safeMode', config.safeMode); await configManager.set('user.preferences.autoUpdate', config.autoUpdate); await configManager.set('project.defaultTemplate', config.defaultTemplate); } async createShortcuts() { const { createShortcuts } = await inquirer.prompt([{ type: 'confirm', name: 'createShortcuts', message: 'Create desktop shortcuts?', default: true }]); if (!createShortcuts) return; const spinner = ora('šŸ”— Creating shortcuts...').start(); try { if (this.isWindows) { await this.createWindowsShortcuts(); } else if (this.isMacOS) { await this.createMacOSShortcuts(); } else if (this.isLinux) { await this.createLinuxShortcuts(); } spinner.succeed('āœ… Shortcuts created'); } catch (error) { spinner.warn('āš ļø Could not create shortcuts'); console.log(chalk.yellow(`Warning: ${error.message}`)); } } async createWindowsShortcuts() { const os = require('os'); const desktopPath = path.join(os.homedir(), 'Desktop'); // Create PowerShell shortcut const shortcutContent = `$WshShell = New-Object -comObject WScript.Shell $Shortcut = $WshShell.CreateShortcut("${path.join(desktopPath, 'Blue Beatle.lnk')}") $Shortcut.TargetPath = "powershell.exe" $Shortcut.Arguments = "-NoExit -Command \\"blue-beatle\\"" $Shortcut.WorkingDirectory = "${process.cwd()}" $Shortcut.IconLocation = "powershell.exe,0" $Shortcut.Description = "Blue Beatle AI Development Assistant" $Shortcut.Save()`; const scriptPath = path.join(os.tmpdir(), 'create-shortcut.ps1'); await fs.writeFile(scriptPath, shortcutContent); try { execSync(`powershell -ExecutionPolicy Bypass -File "${scriptPath}"`, { stdio: 'ignore' }); } finally { await fs.remove(scriptPath); } } async createMacOSShortcuts() { const os = require('os'); const applicationsPath = path.join(os.homedir(), 'Applications'); await fs.ensureDir(applicationsPath); const appPath = path.join(applicationsPath, 'MacAdida.app'); const contentsPath = path.join(appPath, 'Contents'); const macOSPath = path.join(contentsPath, 'MacOS'); await fs.ensureDir(macOSPath); // Create Info.plist const infoPlist = `<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleExecutable</key> <string>blue-beatle</string> <key>CFBundleIdentifier</key> <string>com.engineermarcus.blue-beatle</string> <key>CFBundleName</key> <string>Blue Beatle</string> <key>CFBundleVersion</key> <string>1.0.0</string> </dict> </plist>`; await fs.writeFile(path.join(contentsPath, 'Info.plist'), infoPlist); // Create executable script const executable = `#!/bin/bash cd "${process.cwd()}" open -a Terminal.app "${process.cwd()}/bin/blue-beatle.js"`; await fs.writeFile(path.join(macOSPath, 'blue-beatle'), executable); await fs.chmod(path.join(macOSPath, 'blue-beatle'), '755'); } async createLinuxShortcuts() { const os = require('os'); const desktopPath = path.join(os.homedir(), 'Desktop'); const desktopEntry = `[Desktop Entry] Version=1.0 Type=Application Name=Blue Beatle Comment=AI-Powered Development Assistant Exec=gnome-terminal -- bash -c "cd '${process.cwd()}' && node bin/blue-beatle.js; exec bash" Icon=terminal Terminal=false Categories=Development;`; await fs.writeFile(path.join(desktopPath, 'blue-beatle.desktop'), desktopEntry); await fs.chmod(path.join(desktopPath, 'blue-beatle.desktop'), '755'); } async finalizeInstallation() { const spinner = ora('šŸŽÆ Finalizing installation...').start(); try { // Make binary executable await fs.chmod(path.join(process.cwd(), 'bin', 'blue-beatle.js'), '755'); // Create global link if possible try { execSync('npm link', { stdio: 'ignore' }); spinner.text = 'Global command "blue-beatle" is now available'; } catch (error) { // Global link failed, that's okay } // Test installation const { stdout } = require('child_process').spawnSync('node', [ path.join(process.cwd(), 'bin', 'blue-beatle.js'), '--version' ], { encoding: 'utf8' }); if (!stdout) { throw new Error('Installation test failed'); } spinner.succeed('āœ… Installation finalized'); } catch (error) { spinner.fail('āŒ Finalization failed'); throw error; } } showSuccess() { const boxen = require('boxen'); const successMessage = `šŸŽ‰ Blue Beatle Installation Complete! šŸš€ Quick Start: blue-beatle setup - Run setup wizard blue-beatle ai "help" - Ask AI for help blue-beatle interactive - Start chat mode blue-beatle analyze - Analyze your code šŸ“– Documentation: https://github.com/engineermarcus/marcus-alias šŸ’” Need help? Run: blue-beatle --help`; const box = boxen(successMessage, { padding: 1, margin: 1, borderStyle: 'round', borderColor: 'green', backgroundColor: 'black' }); console.log(box); console.log(chalk.cyan('\nšŸŽÆ Next Steps:')); console.log(chalk.gray('1. Setup your Gemini API key: blue-beatle config --setup-api')); console.log(chalk.gray('2. Try the interactive mode: blue-beatle interactive')); console.log(chalk.gray('3. Analyze your first project: blue-beatle analyze')); console.log(chalk.green('\n✨ Happy coding with Blue Beatle!')); } } // Run setup if called directly if (require.main === module) { const setup = new BlueBeatleSetup(); setup.run().catch(error => { console.error(chalk.red('āŒ Setup failed:'), error.message); process.exit(1); }); } module.exports = BlueBeatleSetup;