UNPKG

blue-beatle

Version:

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

1,197 lines (998 loc) • 69.3 kB
/** * šŸ¤– AI Assistant - Gemini API Integration * Handles all AI-powered features and interactions */ const { GoogleGenerativeAI } = require('@google/generative-ai'); const chalk = require('chalk'); const ora = require('ora'); const inquirer = require('inquirer'); const fs = require('fs-extra'); const path = require('path'); const { execSync, spawn } = require('child_process'); class AIAssistant { constructor(configManager) { this.configManager = configManager; this.genAI = null; this.model = null; this.conversationHistory = []; this.currentContext = { workingDirectory: process.cwd(), projectType: null, files: [], recentCommands: [], openFiles: [], workspaceStructure: null, gitInfo: null, dependencies: null }; this.fileWatcher = null; this.pendingChanges = new Map(); this.initialize(); } async initialize() { try { const apiKey = await this.configManager.get('gemini.apiKey'); if (!apiKey) { console.log(chalk.yellow('āš ļø Gemini API key not found. Run "blue-beatle config --setup-api" to configure.')); return false; } this.genAI = new GoogleGenerativeAI(apiKey); // Use the most advanced model with enhanced configuration this.model = this.genAI.getGenerativeModel({ model: 'gemini-2.0-flash', generationConfig: { temperature: 0.7, topK: 40, topP: 0.95, maxOutputTokens: 8192, }, safetySettings: [ { category: 'HARM_CATEGORY_HARASSMENT', threshold: 'BLOCK_MEDIUM_AND_ABOVE' }, { category: 'HARM_CATEGORY_HATE_SPEECH', threshold: 'BLOCK_MEDIUM_AND_ABOVE' } ] }); // Initialize context await this.updateContext(); // Validate AI connection with a test query await this.validateAIConnection(); return true; } catch (error) { console.error(chalk.red('āŒ Failed to initialize AI Assistant:'), error.message); return false; } } async validateAIConnection() { try { const testPrompt = "Respond with exactly: 'Blue Beatle AI is connected and operational.'"; const result = await this.model.generateContent(testPrompt); const response = result.response.text().trim(); if (!response.includes('Blue Beatle AI is connected and operational')) { console.log(chalk.yellow('āš ļø AI connection validated but response format may vary.')); } return true; } catch (error) { console.error(chalk.red('āŒ AI validation failed:'), error.message); throw new Error('AI connection could not be validated'); } } async updateContext() { try { // Detect project type this.currentContext.projectType = await this.detectProjectType(); // Get file list this.currentContext.files = await this.getProjectFiles(); // Update working directory this.currentContext.workingDirectory = process.cwd(); // Analyze workspace structure this.currentContext.workspaceStructure = await this.analyzeWorkspaceStructure(); // Get Git information this.currentContext.gitInfo = await this.getGitInfo(); // Analyze dependencies this.currentContext.dependencies = await this.analyzeDependencies(); // Setup file watcher await this.setupFileWatcher(); } catch (error) { console.error(chalk.red('āŒ Failed to update context:'), error.message); } } async detectProjectType() { const cwd = process.cwd(); if (await fs.pathExists(path.join(cwd, 'package.json'))) { const pkg = await fs.readJson(path.join(cwd, 'package.json')); if (pkg.dependencies?.react) return 'React'; if (pkg.dependencies?.vue) return 'Vue'; if (pkg.dependencies?.angular) return 'Angular'; if (pkg.dependencies?.express) return 'Express/Node.js'; return 'Node.js'; } if (await fs.pathExists(path.join(cwd, 'requirements.txt')) || await fs.pathExists(path.join(cwd, 'pyproject.toml'))) { return 'Python'; } if (await fs.pathExists(path.join(cwd, 'Cargo.toml'))) return 'Rust'; if (await fs.pathExists(path.join(cwd, 'go.mod'))) return 'Go'; if (await fs.pathExists(path.join(cwd, 'pom.xml'))) return 'Java/Maven'; if (await fs.pathExists(path.join(cwd, 'build.gradle'))) return 'Java/Gradle'; if (await fs.pathExists(path.join(cwd, 'Makefile'))) return 'C/C++'; return 'Unknown'; } async getProjectFiles(maxFiles = 50) { try { const files = []; const extensions = ['.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.cpp', '.c', '.go', '.rs', '.php', '.rb']; const walkDir = async (dir, depth = 0) => { if (depth > 3 || files.length >= maxFiles) return; const items = await fs.readdir(dir); for (const item of items) { if (item.startsWith('.') || item === 'node_modules') continue; const fullPath = path.join(dir, item); const stat = await fs.stat(fullPath); if (stat.isDirectory()) { await walkDir(fullPath, depth + 1); } else if (extensions.some(ext => item.endsWith(ext))) { files.push({ name: item, path: fullPath, relativePath: path.relative(process.cwd(), fullPath), size: stat.size, modified: stat.mtime }); } } }; await walkDir(process.cwd()); return files.slice(0, maxFiles); } catch (error) { console.error(chalk.red('āŒ Failed to get project files:'), error.message); return []; } } async processPrompt(prompt, options = {}) { if (!this.model) { console.log(chalk.red('āŒ AI Assistant not initialized. Please check your API key.')); return; } // Check if this is an authentication-related query const authKeywords = /auth|login|register|password|session|jwt|security|vulnerability|bcrypt/i; if (authKeywords.test(prompt) && !options.skipAuthAudit) { console.log(chalk.cyan('šŸ” Detected authentication-related query. Performing real-time code analysis...')); await this.performAuthenticationAudit(); console.log(chalk.cyan('\nšŸ¤– Now providing AI analysis based on your actual code:\n')); } const spinner = ora('šŸ¤– AI is analyzing your code...').start(); try { // Build context for the AI let contextualPrompt = await this.buildContextualPrompt(prompt, options); // Get AI response const result = await this.model.generateContent(contextualPrompt); const response = result.response.text(); spinner.stop(); // Display response this.displayAIResponse(response, options); // Extract and execute commands if requested if (options.execute) { await this.executeAISuggestions(response); } // Add to conversation history this.conversationHistory.push({ prompt: prompt, response: response, timestamp: new Date(), context: { ...this.currentContext } }); } catch (error) { spinner.stop(); console.error(chalk.red('āŒ AI request failed:'), error.message); } } async buildContextualPrompt(prompt, options) { let contextualPrompt = `You are Blue Beatle, a sophisticated AI development assistant with deep expertise in software engineering, architecture, and best practices. You provide intelligent, context-aware solutions with professional-grade analysis. ## Your Capabilities: - Advanced code analysis and optimization - Architecture design and patterns - Security vulnerability assessment - Performance optimization strategies - Best practices enforcement - Cross-platform development guidance - Modern development workflows ## Current Development Context: - Working Directory: ${this.currentContext.workingDirectory} - Project Type: ${this.currentContext.projectType || 'Auto-detecting...'} - Operating System: ${process.platform} - Project Files: ${this.currentContext.files.slice(0, 10).map(f => f.relativePath).join(', ')} - Recent Commands: ${this.currentContext.recentCommands.slice(-3).join(', ') || 'None'} ## Response Guidelines: - Provide detailed, actionable solutions - Include code examples with explanations - Consider security and performance implications - Suggest modern best practices - Explain the reasoning behind recommendations - Offer alternative approaches when applicable `; // Add file content if specified if (options.file) { try { const filePath = path.resolve(options.file); const content = await fs.readFile(filePath, 'utf8'); contextualPrompt += `\nFile Content (${options.file}):\n\`\`\`\n${content}\n\`\`\`\n`; } catch (error) { contextualPrompt += `\nError reading file ${options.file}: ${error.message}\n`; } } // Add directory analysis if specified if (options.directory) { const dirAnalysis = await this.analyzeDirectory(options.directory); contextualPrompt += `\nDirectory Analysis (${options.directory}):\n${dirAnalysis}\n`; } // Add full project context if requested if (options.context) { const projectContext = await this.getFullProjectContext(); contextualPrompt += `\nFull Project Context:\n${projectContext}\n`; } // Add conversation history if (this.conversationHistory.length > 0) { const recentHistory = this.conversationHistory.slice(-3); contextualPrompt += `\nRecent Conversation:\n${recentHistory.map(h => `User: ${h.prompt}\nAssistant: ${h.response.substring(0, 200)}...` ).join('\n\n')}\n`; } contextualPrompt += `\nUser Request: ${prompt} CRITICAL INSTRUCTIONS: - ALWAYS read and analyze actual files from the user's project - Provide specific feedback based on the actual code you find - Show real-time analysis with file paths and line numbers - When suggesting changes, provide exact code replacements - Use the file reading capabilities to examine the codebase thoroughly - Never provide generic examples - always work with the user's actual code Response Format: 1. Start by reading relevant files from the project 2. Analyze the actual code found 3. Identify specific issues with file paths and line numbers 4. Provide exact code fixes for the user's files 5. Show before/after comparisons when making changes IMPORTANT: This is a real codebase analysis, not a tutorial. Read the files and work with the actual code.`; return contextualPrompt; } async analyzeDirectory(dirPath) { try { const fullPath = path.resolve(dirPath); const files = await fs.readdir(fullPath); let analysis = `Directory: ${dirPath}\n`; analysis += `Files: ${files.length}\n`; const fileTypes = {}; for (const file of files) { const ext = path.extname(file); fileTypes[ext] = (fileTypes[ext] || 0) + 1; } analysis += `File Types: ${Object.entries(fileTypes).map(([ext, count]) => `${ext || 'no-ext'}: ${count}`).join(', ')}\n`; return analysis; } catch (error) { return `Error analyzing directory: ${error.message}`; } } async getFullProjectContext() { try { let context = `Project Type: ${this.currentContext.projectType}\n`; context += `Total Files: ${this.currentContext.files.length}\n`; // Add package.json info if available const pkgPath = path.join(process.cwd(), 'package.json'); if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); context += `\nPackage.json:\n`; context += `- Name: ${pkg.name}\n`; context += `- Version: ${pkg.version}\n`; context += `- Dependencies: ${Object.keys(pkg.dependencies || {}).join(', ')}\n`; context += `- Scripts: ${Object.keys(pkg.scripts || {}).join(', ')}\n`; } // Add recent git commits if available try { const gitLog = execSync('git log --oneline -5', { encoding: 'utf8', cwd: process.cwd() }); context += `\nRecent Git Commits:\n${gitLog}`; } catch (error) { // Git not available or not a git repo } return context; } catch (error) { return `Error getting project context: ${error.message}`; } } displayAIResponse(response, options) { const boxen = require('boxen'); const gradient = require('gradient-string'); // Create a professional header const header = gradient.cristal('šŸ¤– Blue Beatle AI Assistant'); console.log('\n' + boxen(header, { padding: 1, margin: 1, borderStyle: 'round', borderColor: 'cyan' })); // Parse and format the response with classic, clean styling const sections = response.split('\n\n'); sections.forEach((section, index) => { if (section.includes('```')) { // Clean code block formatting const lines = section.split('\n'); let inCodeBlock = false; let language = ''; lines.forEach(line => { if (line.startsWith('```')) { inCodeBlock = !inCodeBlock; if (inCodeBlock) { language = line.replace('```', '').trim(); console.log(chalk.cyan(`\n${language ? language.toUpperCase() + ' ' : ''}CODE:`)); console.log(chalk.gray('─'.repeat(50))); } else { console.log(chalk.gray('─'.repeat(50))); } } else if (inCodeBlock) { console.log(chalk.green(line)); } else if (line.trim()) { console.log(chalk.white(line)); } }); } else if (section.match(/^\d+\./)) { // Numbered list items - clean formatting console.log(chalk.white('\n' + section)); } else if (section.includes('SOLUTION:') || section.includes('EXPLANATION:') || section.includes('STEPS:')) { // Section headers - clean and professional console.log(chalk.bold.cyan('\n' + section.toUpperCase())); console.log(chalk.gray('─'.repeat(30))); } else if (section.includes('Terminal Commands:') || section.includes('Commands:') || section.includes('$ ')) { // Command section with clean formatting console.log(chalk.yellow('\nCOMMANDS:')); console.log(chalk.gray('─'.repeat(30))); console.log(chalk.white(section)); } else if (section.includes('Warning') || section.includes('IMPORTANT') || section.includes('Note:')) { // Important information with clean formatting console.log(chalk.red.bold('\nIMPORTANT:')); console.log(chalk.gray('─'.repeat(30))); console.log(chalk.white(section)); } else if (section.includes('Recommendation') || section.includes('Best Practice')) { // Recommendations with clean formatting console.log(chalk.green.bold('\nRECOMMENDATION:')); console.log(chalk.gray('─'.repeat(30))); console.log(chalk.white(section)); } else if (section.trim()) { // Regular text with clean formatting - remove asterisks and format cleanly const cleanText = section.replace(/\*\*(.*?)\*\*/g, '$1').replace(/\*(.*?)\*/g, '$1'); console.log(chalk.white('\n' + cleanText)); } }); // Add a professional footer console.log(chalk.gray('\n' + '─'.repeat(60))); console.log(chalk.cyan('šŸ’” Need more help? Use "blue-beatle interactive" for detailed assistance')); console.log(''); } async executeAISuggestions(response) { // Extract terminal commands from the response const commandRegex = /```(?:bash|shell|cmd)?\n(.*?)\n```/gs; const commands = []; let match; while ((match = commandRegex.exec(response)) !== null) { const command = match[1].trim(); if (command && !command.startsWith('#') && !command.startsWith('//')) { commands.push(command); } } if (commands.length === 0) { console.log(chalk.yellow('ā„¹ļø No executable commands found in AI response.')); return; } console.log(chalk.cyan(`\nšŸ”§ Found ${commands.length} command(s) to execute:\n`)); commands.forEach((cmd, i) => { console.log(chalk.gray(`${i + 1}. ${cmd}`)); }); const { shouldExecute } = await inquirer.prompt([{ type: 'confirm', name: 'shouldExecute', message: 'Do you want to execute these commands?', default: false }]); if (!shouldExecute) { console.log(chalk.yellow('ā­ļø Command execution skipped.')); return; } for (const command of commands) { console.log(chalk.blue(`\nā–¶ļø Executing: ${command}`)); try { const result = execSync(command, { encoding: 'utf8', cwd: process.cwd(), stdio: 'inherit' }); this.currentContext.recentCommands.push({ command, timestamp: new Date(), success: true }); } catch (error) { console.error(chalk.red(`āŒ Command failed: ${error.message}`)); this.currentContext.recentCommands.push({ command, timestamp: new Date(), success: false, error: error.message }); const { continueExecution } = await inquirer.prompt([{ type: 'confirm', name: 'continueExecution', message: 'Continue with remaining commands?', default: false }]); if (!continueExecution) break; } } } async startInteractiveMode(options = {}) { const boxen = require('boxen'); const gradient = require('gradient-string'); // Professional welcome message const welcomeMsg = gradient.pastel.multiline([ 'šŸŽÆ Blue Beatle Interactive AI Assistant', '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'Advanced AI-powered development assistance', 'Context-aware • Intelligent • Professional' ].join('\n')); console.log('\n' + boxen(welcomeMsg, { padding: 1, margin: 1, borderStyle: 'double', borderColor: 'cyan' })); console.log(chalk.gray('šŸ’” Commands: exit, help, clear, context, analyze, security, performance, read, suggest, workspace')); console.log(chalk.gray('šŸ” Powerful features: Real-time analysis, File editing, Code intelligence, Git integration\n')); while (true) { try { const { input } = await inquirer.prompt([{ type: 'input', name: 'input', message: chalk.cyan('Blue Beatle āÆ'), prefix: '' }]); if (input.toLowerCase() === 'exit') { console.log(chalk.yellow('šŸ‘‹ Goodbye!')); break; } if (input.toLowerCase() === 'clear') { this.conversationHistory = []; console.log(chalk.green('āœ… Conversation history cleared.')); continue; } if (input.toLowerCase() === 'help') { this.showInteractiveHelp(); continue; } if (input.toLowerCase() === 'context') { await this.updateContext(); console.log(chalk.green('āœ… Context updated.')); console.log(chalk.gray(`Project: ${this.currentContext.projectType}, Files: ${this.currentContext.files.length}`)); continue; } if (input.toLowerCase() === 'analyze') { await this.processPrompt('Perform a comprehensive analysis of this project including code quality, architecture, and potential improvements', { context: true }); continue; } if (input.toLowerCase() === 'security') { await this.processPrompt('Conduct a security audit of this project and identify potential vulnerabilities', { context: true }); continue; } if (input.toLowerCase() === 'performance') { await this.processPrompt('Analyze the performance characteristics of this project and suggest optimizations', { context: true }); continue; } if (input.toLowerCase().startsWith('review ')) { const filePath = input.substring(7).trim(); await this.processPrompt(`Please review this file for code quality, best practices, and potential improvements`, { file: filePath }); continue; } if (input.toLowerCase().startsWith('read ')) { const filePath = input.substring(5).trim(); try { const fileInfo = await this.readFileWithContext(filePath); console.log(chalk.cyan(`\nšŸ“„ FILE: ${fileInfo.path}`)); console.log(chalk.gray(`Size: ${fileInfo.size} bytes | Lines: ${fileInfo.lines} | Language: ${fileInfo.language}`)); console.log(chalk.gray('─'.repeat(50))); console.log(chalk.white(fileInfo.content)); console.log(chalk.gray('─'.repeat(50))); } catch (error) { console.log(chalk.red(`āŒ ${error.message}`)); } continue; } if (input.toLowerCase().startsWith('analyze-file ')) { const filePath = input.substring(13).trim(); try { const analysis = await this.analyzeCodeFile(filePath); console.log(chalk.cyan(`\nšŸ” CODE ANALYSIS: ${analysis.path}`)); console.log(chalk.gray('─'.repeat(50))); console.log(chalk.white(`Language: ${analysis.language}`)); console.log(chalk.white(`Lines: ${analysis.lines}`)); console.log(chalk.white(`Complexity: ${analysis.complexity}`)); console.log(chalk.white(`Functions: ${analysis.metrics.functions}`)); console.log(chalk.white(`Classes: ${analysis.metrics.classes}`)); console.log(chalk.white(`Imports: ${analysis.metrics.imports}`)); if (analysis.issues.length > 0) { console.log(chalk.red(`Issues: ${analysis.issues.join(', ')}`)); } console.log(chalk.gray('─'.repeat(50))); } catch (error) { console.log(chalk.red(`āŒ ${error.message}`)); } continue; } if (input.toLowerCase().startsWith('suggest ')) { const parts = input.substring(8).trim().split(' '); const filePath = parts[0]; const requirements = parts.slice(1).join(' ') || 'general improvements'; try { console.log(chalk.cyan(`\nšŸ¤– Analyzing ${filePath} and generating suggestions...`)); const suggestions = await this.suggestFileChanges(filePath, requirements); console.log(chalk.cyan(`\nšŸ’” SUGGESTIONS FOR: ${suggestions.filePath}`)); console.log(chalk.gray('─'.repeat(50))); this.displayAIResponse(suggestions.suggestions, {}); if (suggestions.canAutoApply.length > 0) { console.log(chalk.yellow(`\n⚔ Found ${suggestions.canAutoApply.length} auto-applicable changes`)); const { apply } = await inquirer.prompt([{ type: 'confirm', name: 'apply', message: 'Would you like to apply these changes automatically?', default: false }]); if (apply) { // This would need more sophisticated implementation console.log(chalk.green('āœ… Changes would be applied (implementation needed)')); } } } catch (error) { console.log(chalk.red(`āŒ ${error.message}`)); } continue; } if (input.toLowerCase().startsWith('check-auth')) { const projectPath = input.substring(10).trim() || process.cwd(); await this.performAuthenticationAudit(projectPath); continue; } if (input.toLowerCase() === 'workspace') { console.log(chalk.cyan('\nšŸ—ļø WORKSPACE ANALYSIS')); console.log(chalk.gray('─'.repeat(50))); if (this.currentContext.workspaceStructure) { const ws = this.currentContext.workspaceStructure; console.log(chalk.white(`Total Files: ${ws.totalFiles}`)); console.log(chalk.white(`Total Directories: ${ws.directories.length}`)); console.log(chalk.white(`Total Size: ${(ws.totalSize / 1024).toFixed(2)} KB`)); console.log(chalk.white(`Complexity: ${ws.complexity}`)); console.log(chalk.cyan('\nFile Types:')); Object.entries(ws.fileTypes).forEach(([ext, count]) => { console.log(chalk.gray(` ${ext || 'no-ext'}: ${count} files`)); }); } if (this.currentContext.gitInfo?.isRepo) { const git = this.currentContext.gitInfo; console.log(chalk.cyan('\nGit Information:')); console.log(chalk.white(`Branch: ${git.branch || 'unknown'}`)); console.log(chalk.white(`Status: ${git.status || 'unknown'}`)); if (git.lastCommit) { console.log(chalk.white(`Last Commit: ${git.lastCommit}`)); } } if (this.currentContext.dependencies) { const deps = this.currentContext.dependencies; console.log(chalk.cyan('\nDependencies:')); console.log(chalk.white(`Production: ${Object.keys(deps.production).length}`)); console.log(chalk.white(`Development: ${Object.keys(deps.development).length}`)); if (deps.vulnerabilities.length > 0) { console.log(chalk.red(`Potential Issues: ${deps.vulnerabilities.length}`)); } } continue; } if (input.trim()) { await this.processPrompt(input, options); } } catch (error) { if (error.isTtyError) { console.log(chalk.yellow('šŸ‘‹ Interactive mode ended.')); break; } else { console.error(chalk.red('āŒ Error:'), error.message); } } } } showInteractiveHelp() { const Table = require('cli-table3'); console.log(chalk.cyan('\nšŸ“– Blue Beatle Interactive Commands\n')); const table = new Table({ head: [chalk.cyan('Command'), chalk.cyan('Description'), chalk.cyan('Example')], colWidths: [15, 35, 25], style: { head: ['cyan'], border: ['gray'] } }); table.push( ['exit', 'Exit interactive mode', 'exit'], ['clear', 'Clear conversation history', 'clear'], ['context', 'Update project context', 'context'], ['analyze', 'Full project analysis', 'analyze'], ['security', 'Security audit', 'security'], ['performance', 'Performance analysis', 'performance'], ['review <file>', 'Review specific file', 'review src/app.js'], ['read <file>', 'Read and display file content', 'read package.json'], ['analyze-file <file>', 'Analyze code file metrics', 'analyze-file src/app.js'], ['suggest <file> [req]', 'AI-powered file improvements', 'suggest app.js performance'], ['check-auth [path]', 'Real-time authentication audit', 'check-auth ./server'], ['workspace', 'Show workspace analysis', 'workspace'], ['help', 'Show this help', 'help'] ); console.log(table.toString()); console.log(chalk.yellow('\nšŸŽÆ Powerful Features:')); console.log(chalk.gray('• Real-time workspace analysis and monitoring')); console.log(chalk.gray('• Intelligent code reading and understanding')); console.log(chalk.gray('• AI-powered file editing suggestions')); console.log(chalk.gray('• Automatic code quality assessment')); console.log(chalk.gray('• Security vulnerability detection')); console.log(chalk.gray('• Performance optimization recommendations')); console.log(chalk.gray('• Git integration and project insights')); console.log(chalk.gray('• Dependency analysis and management')); console.log(chalk.blue('\nšŸ’” Pro Tips:')); console.log(chalk.gray('• Use "read filename" to view any file with syntax highlighting')); console.log(chalk.gray('• Use "analyze-file filename" for detailed code metrics')); console.log(chalk.gray('• Use "suggest filename requirements" for AI improvements')); console.log(chalk.gray('• Use "workspace" to see complete project overview')); console.log(chalk.gray('• Ask specific questions for context-aware responses\n')); } async learnMode(topic, options = {}) { const spinner = ora(`šŸ“š Preparing learning material for: ${topic}`).start(); try { const learningPrompt = `You are an expert programming tutor. Create a comprehensive learning guide for the topic: "${topic}". Learning Level: ${options.level} Include Examples: ${options.examples ? 'Yes' : 'No'} Interactive Quiz: ${options.quiz ? 'Yes' : 'No'} Please provide: 1. Clear explanation of the concept 2. Key points and principles 3. ${options.examples ? 'Practical code examples' : 'Theoretical overview'} 4. Common pitfalls and how to avoid them 5. Best practices 6. ${options.quiz ? 'Interactive quiz questions' : 'Further reading suggestions'} Format the response with clear sections and use markdown for code blocks.`; const result = await this.model.generateContent(learningPrompt); const response = result.response.text(); spinner.stop(); this.displayAIResponse(response, options); if (options.quiz) { await this.runInteractiveQuiz(response); } } catch (error) { spinner.stop(); console.error(chalk.red('āŒ Learning mode failed:'), error.message); } } async runInteractiveQuiz(learningContent) { console.log(chalk.cyan('\nšŸŽ“ Starting Interactive Quiz!\n')); // Extract quiz questions from the learning content const quizRegex = /(?:Quiz|Question)\s*\d*[:.]\s*(.*?)(?=(?:Quiz|Question)\s*\d*[:.|\n\n]|$)/gs; const questions = []; let match; while ((match = quizRegex.exec(learningContent)) !== null) { questions.push(match[1].trim()); } if (questions.length === 0) { console.log(chalk.yellow('ā„¹ļø No quiz questions found in the learning content.')); return; } let score = 0; for (let i = 0; i < questions.length; i++) { console.log(chalk.blue(`\nQuestion ${i + 1}: ${questions[i]}`)); const { answer } = await inquirer.prompt([{ type: 'input', name: 'answer', message: 'Your answer:' }]); // Get AI evaluation of the answer const evaluationPrompt = `Evaluate this answer to the question: "${questions[i]}" Student Answer: "${answer}" Please provide: 1. Whether the answer is correct (Yes/No) 2. Brief explanation 3. Correct answer if the student was wrong 4. Encouragement or tips Keep the response concise and educational.`; try { const evaluation = await this.model.generateContent(evaluationPrompt); const feedback = evaluation.response.text(); console.log(chalk.green('\nšŸ“ Feedback:')); console.log(feedback); // Simple scoring based on AI feedback if (feedback.toLowerCase().includes('correct') || feedback.toLowerCase().includes('yes')) { score++; console.log(chalk.green('āœ… Correct!')); } else { console.log(chalk.red('āŒ Incorrect')); } } catch (error) { console.log(chalk.yellow('āš ļø Could not evaluate answer automatically.')); } } console.log(chalk.cyan(`\nšŸŽ‰ Quiz Complete! Score: ${score}/${questions.length}`)); if (score === questions.length) { console.log(chalk.green('šŸ† Perfect score! Excellent work!')); } else if (score >= questions.length * 0.7) { console.log(chalk.yellow('šŸ‘ Good job! Keep practicing!')); } else { console.log(chalk.blue('šŸ“š Keep learning! Review the material and try again.')); } } async debugMode(file, options = {}) { console.log(chalk.cyan('šŸ› Starting Debug Mode')); let debugContext = `Debug Session Started Working Directory: ${process.cwd()} Target File: ${file || 'Not specified'} `; if (file) { try { const content = await fs.readFile(file, 'utf8'); debugContext += `\nFile Content:\n\`\`\`\n${content}\n\`\`\`\n`; } catch (error) { debugContext += `\nError reading file: ${error.message}\n`; } } if (options.error) { debugContext += `\nError Message: ${options.error}\n`; } if (options.logs) { try { const logs = await fs.readFile(options.logs, 'utf8'); debugContext += `\nLog File Content:\n\`\`\`\n${logs.slice(-2000)}\n\`\`\`\n`; } catch (error) { debugContext += `\nError reading log file: ${error.message}\n`; } } const debugPrompt = `${debugContext} You are an expert debugger. Please analyze the provided information and help debug the issue. Provide: 1. Problem identification 2. Possible causes 3. Step-by-step debugging approach 4. Suggested fixes 5. Prevention strategies Be specific and actionable in your recommendations.`; await this.processPrompt(debugPrompt, { execute: false }); } async generateCode(type, options = {}) { const spinner = ora(`šŸŽØ Generating ${type} code...`).start(); try { let generationPrompt = `Generate ${type} code with the following specifications: Type: ${type} Name: ${options.name || 'Unnamed'} Framework: ${options.framework || 'None specified'} Language: ${options.language || 'Auto-detect from project'} Template: ${options.template || 'Standard'} Project Context: - Project Type: ${this.currentContext.projectType} - Working Directory: ${this.currentContext.workingDirectory} Please provide: 1. Complete, working code 2. Explanation of the code structure 3. Usage examples 4. Any required dependencies 5. Setup instructions if needed Make the code production-ready with proper error handling, comments, and best practices.`; const result = await this.model.generateContent(generationPrompt); const response = result.response.text(); spinner.stop(); this.displayAIResponse(response, options); // Offer to save the generated code const { shouldSave } = await inquirer.prompt([{ type: 'confirm', name: 'shouldSave', message: 'Would you like to save the generated code to a file?', default: true }]); if (shouldSave) { await this.saveGeneratedCode(response, type, options); } } catch (error) { spinner.stop(); console.error(chalk.red('āŒ Code generation failed:'), error.message); } } async saveGeneratedCode(response, type, options) { // Extract code blocks from the response const codeRegex = /```(?:(\w+))?\n(.*?)\n```/gs; const codeBlocks = []; let match; while ((match = codeRegex.exec(response)) !== null) { codeBlocks.push({ language: match[1] || 'text', code: match[2] }); } if (codeBlocks.length === 0) { console.log(chalk.yellow('ā„¹ļø No code blocks found to save.')); return; } for (let i = 0; i < codeBlocks.length; i++) { const block = codeBlocks[i]; const extension = this.getFileExtension(block.language); const defaultName = `${options.name || type}-${i + 1}${extension}`; const { filename } = await inquirer.prompt([{ type: 'input', name: 'filename', message: `Enter filename for code block ${i + 1}:`, default: defaultName }]); try { await fs.writeFile(filename, block.code); console.log(chalk.green(`āœ… Code saved to: ${filename}`)); } catch (error) { console.error(chalk.red(`āŒ Failed to save ${filename}:`), error.message); } } } getFileExtension(language) { const extensions = { javascript: '.js', typescript: '.ts', python: '.py', java: '.java', cpp: '.cpp', c: '.c', go: '.go', rust: '.rs', php: '.php', ruby: '.rb', html: '.html', css: '.css', json: '.json', yaml: '.yml', xml: '.xml', sql: '.sql', bash: '.sh', powershell: '.ps1' }; return extensions[language.toLowerCase()] || '.txt'; } // ===== POWERFUL WORKSPACE ANALYSIS METHODS ===== async analyzeWorkspaceStructure() { try { const structure = { directories: [], fileTypes: {}, totalFiles: 0, totalSize: 0, complexity: 'low' }; const walkDir = async (dir, depth = 0) => { if (depth > 5) return; // Prevent infinite recursion const items = await fs.readdir(dir); for (const item of items) { if (item.startsWith('.') || item === 'node_modules') continue; const fullPath = path.join(dir, item); const stat = await fs.stat(fullPath); if (stat.isDirectory()) { structure.directories.push({ name: item, path: fullPath, relativePath: path.relative(process.cwd(), fullPath), depth }); await walkDir(fullPath, depth + 1); } else { const ext = path.extname(item); structure.fileTypes[ext] = (structure.fileTypes[ext] || 0) + 1; structure.totalFiles++; structure.totalSize += stat.size; } } }; await walkDir(process.cwd()); // Determine complexity if (structure.totalFiles > 100 || structure.directories.length > 20) { structure.complexity = 'high'; } else if (structure.totalFiles > 50 || structure.directories.length > 10) { structure.complexity = 'medium'; } return structure; } catch (error) { console.error(chalk.red('āŒ Failed to analyze workspace structure:'), error.message); return null; } } async getGitInfo() { try { const { execSync } = require('child_process'); const gitInfo = { isRepo: false, branch: null, remoteUrl: null, lastCommit: null, status: null }; // Check if it's a git repository try { execSync('git rev-parse --git-dir', { stdio: 'ignore' }); gitInfo.isRepo = true; } catch { return gitInfo; } // Get current branch try { gitInfo.branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim(); } catch {} // Get remote URL try { gitInfo.remoteUrl = execSync('git config --get remote.origin.url', { encoding: 'utf8' }).trim(); } catch {} // Get last commit try { gitInfo.lastCommit = execSync('git log -1 --pretty=format:"%h - %s (%cr)"', { encoding: 'utf8' }).trim(); } catch {} // Get status try { const status = execSync('git status --porcelain', { encoding: 'utf8' }); gitInfo.status = status ? 'dirty' : 'clean'; } catch {} return gitInfo; } catch (error) { return { isRepo: false, error: error.message }; } } async analyzeDependencies() { try { const dependencies = { production: {}, development: {}, outdated: [], vulnerabilities: [], totalCount: 0 }; // Analyze package.json const pkgPath = path.join(process.cwd(), 'package.json'); if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); dependencies.production = pkg.dependencies || {}; dependencies.development = pkg.devDependencies || {}; dependencies.totalCount = Object.keys(dependencies.production).length + Object.keys(dependencies.development).length; // Check for common vulnerable packages const vulnerablePackages = ['lodash', 'moment', 'request', 'node-sass']; for (const vuln of vulnerablePackages) { if (dependencies.production[vuln] || dependencies.development[vuln]) { dependencies.vulnerabilities.push({ package: vuln, reason: 'Known security issues - consider alternatives' }); } } } return dependencies; } catch (error) { console.error(chalk.red('āŒ Failed to analyze dependencies:'), error.message); return null; } } async setupFileWatcher() { try { if (this.fileWatcher) { this.fileWatcher.close(); } const chokidar = require('chokidar'); this.fileWatcher = chokidar.watch(process.cwd(), { ignored: /(^|[\/\\])\../, // ignore dotfiles ignoreInitial: true, depth: 3 }); this.fileWatcher.on('change', (filePath) => { this.currentContext.recentCommands.unshift(`File changed: ${path.relative(process.cwd(), filePath)}`); if (this.currentContext.recentCommands.length > 10) { this.currentContext.recentCommands.pop();