UNPKG

mira-consciousness

Version:

Memory & Intelligence Retention Archive - Preserving The Spark

1,040 lines • 46 kB
import { Command } from 'commander'; import chalk from 'chalk'; import ora from 'ora'; import fs from 'fs-extra'; import * as path from 'path'; import { execSync } from 'child_process'; import { getDirectPythonInterface } from '../core/DirectPythonInterface.js'; import { NameDetector } from '../core/NameDetector.js'; import { ProjectDetector } from '../core/ProjectDetector.js'; import { PatternAnalyzer } from '../core/PatternAnalyzer.js'; import { SecurityAnalyzer } from '../analyzers/SecurityAnalyzer.js'; import { PerformanceAnalyzer } from '../analyzers/PerformanceAnalyzer.js'; import { DocumentationAnalyzer } from '../analyzers/DocumentationAnalyzer.js'; import { CodeQualityAnalyzer } from '../analyzers/CodeQualityAnalyzer.js'; import { DependencyAnalyzer } from '../analyzers/DependencyAnalyzer.js'; import { UnifiedScoringSystem } from '../core/UnifiedScoring.js'; export function createAnalyzeCommand() { return new Command('analyze') .description('Comprehensive code analysis with unified scoring') .option('-c, --code <path>', 'Analyze specific code file or directory') .option('-i, --issue <description>', 'Analyze and solve specific issue') .option('-g, --git', 'Analyze recent git changes for commit suggestions') .option('-p, --pattern', 'Analyze patterns in current project') .option('--comprehensive', 'Run all analyzers with unified scoring') .option('--security', 'Run security analysis only') .option('--performance', 'Run performance analysis only') .option('--docs', 'Run documentation analysis only') .option('--quality', 'Run code quality analysis only') .option('--deps', 'Run dependency analysis only') .option('--recent <count>', 'Number of recent messages to analyze', '20') .option('--no-memory', 'Skip memory search') .option('-d, --deep', 'Perform deep analysis with all subsystems') .action(async (options) => { const pythonInterface = getDirectPythonInterface(); const nameDetector = new NameDetector(); const projectDetector = new ProjectDetector(process.cwd()); const patternAnalyzer = new PatternAnalyzer(process.cwd()); console.log(chalk.cyan('\n🧠 MIRA Intelligent Analysis\n')); // Get project identity and context const identity = await nameDetector.detect(); const developerRef = await nameDetector.getDeveloperReference(); const projectInfo = await projectDetector.detectProject(); console.log(chalk.gray(`Project: ${identity.projectName}`)); console.log(chalk.gray(`Type: ${projectInfo.type}`)); console.log(chalk.gray(`Developer: ${developerRef}\n`)); // Determine analysis focus let analysisType = 'context'; let analysisTarget = null; if (options.comprehensive) { analysisType = 'comprehensive'; } else if (options.security) { analysisType = 'security'; } else if (options.performance) { analysisType = 'performance'; } else if (options.docs) { analysisType = 'documentation'; } else if (options.quality) { analysisType = 'quality'; } else if (options.deps) { analysisType = 'dependencies'; } else if (options.code) { analysisType = 'code'; analysisTarget = options.code; } else if (options.issue) { analysisType = 'issue'; analysisTarget = options.issue; } else if (options.git) { analysisType = 'git'; } else if (options.pattern) { analysisType = 'patterns'; } const spinner = ora('Gathering analysis context...').start(); try { // Build comprehensive analysis context const context = { recentMessages: [], gitChanges: [], relatedMemories: [], patterns: [], projectContext: projectInfo }; // 1. Update conversation index and get recent context if (!options.noMemory) { spinner.text = 'Indexing recent conversations...'; try { await pythonInterface.indexConversations(); // Get recent conversation context using search (with timeout) const recentLimit = parseInt(options.recent) || 20; try { const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Conversation context timeout')), 10000)); context.recentMessages = await Promise.race([ getRecentConversationContext(pythonInterface, recentLimit), timeoutPromise ]); } catch (e) { console.log(chalk.gray('Note: Recent conversation analysis skipped')); context.recentMessages = []; } } catch (e) { console.log(chalk.gray('Note: Conversation analysis skipped')); } } // 2. Analyze git changes if requested or relevant if (options.git || analysisType === 'git') { spinner.text = 'Analyzing git changes...'; context.gitChanges = await analyzeGitChanges(); } // 3. Search for related memories based on context if (!options.noMemory && (analysisTarget || context.recentMessages.length > 0)) { spinner.text = 'Searching related memories...'; // Build search query from context const searchQuery = buildContextualSearchQuery(analysisTarget, context.recentMessages, analysisType); if (searchQuery) { try { const searchResult = await pythonInterface.searchConversations(searchQuery, 5); context.relatedMemories = searchResult.success && Array.isArray(searchResult.results) ? searchResult.results : []; } catch (e) { console.log(chalk.gray('Note: Memory search skipped')); context.relatedMemories = []; } } } // 4. Analyze patterns if deep analysis requested if (options.deep || analysisType === 'patterns') { spinner.text = 'Analyzing development patterns...'; context.patterns = await patternAnalyzer.analyzeGitPatterns(); } spinner.text = 'Generating intelligent insights...'; // 5. Generate analysis based on type and context let analysis; if (['comprehensive', 'security', 'performance', 'documentation', 'quality', 'dependencies'].includes(analysisType)) { analysis = await generateAnalyzerBasedAnalysis(analysisType, context, options.deep); } else { analysis = await generateContextualAnalysis(analysisType, analysisTarget, context, options.deep); } spinner.succeed('Analysis complete'); // Display results displayAnalysisResults(analysis, context); } catch (error) { spinner.fail('Analysis failed'); console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`)); console.log(chalk.yellow('\nšŸ’” Tips:')); console.log(chalk.gray(' • Run "mira index-conversations" first to build conversation database')); console.log(chalk.gray(' • Use --no-memory to skip memory integration')); console.log(chalk.gray(' • Use -g to focus on git changes')); console.log(chalk.gray(' • Add -d for deeper pattern analysis')); process.exit(1); } }); } /** * Get recent conversation context by searching for recent topics */ async function getRecentConversationContext(pythonInterface, limit) { try { // Search for recent development topics const recentTopics = [ 'recent work', 'current task', 'working on', 'implementing', 'fixing', 'debugging', 'feature', 'bug', 'issue' ]; const allResults = []; for (const topic of recentTopics.slice(0, 3)) { // Limit to avoid too many calls try { const searchResult = await pythonInterface.searchConversations(topic, Math.ceil(limit / 3)); if (searchResult.success && Array.isArray(searchResult.results)) { allResults.push(...searchResult.results); } } catch (e) { // Continue with next topic if one fails } } // Sort by relevance and return top results return allResults .sort((a, b) => (b.score || 0) - (a.score || 0)) .slice(0, limit); } catch (error) { return []; } } /** * Analyze recent git changes */ async function analyzeGitChanges() { try { // Check if we're in a git repository execSync('git rev-parse --git-dir', { stdio: 'ignore' }); // Get recent changes (staged and recent commits) const changes = []; // Staged changes try { const staged = execSync('git diff --cached --numstat', { encoding: 'utf-8' }); if (staged.trim()) { const stagedFiles = staged.trim().split('\n').map(line => { const [additions, deletions, file] = line.split('\t'); return { file, status: 'staged', additions: parseInt(additions) || 0, deletions: parseInt(deletions) || 0 }; }); changes.push(...stagedFiles); } } catch (e) { // No staged changes } // Recent unstaged changes try { const unstaged = execSync('git diff --numstat', { encoding: 'utf-8' }); if (unstaged.trim()) { const unstagedFiles = unstaged.trim().split('\n').map(line => { const [additions, deletions, file] = line.split('\t'); return { file, status: 'modified', additions: parseInt(additions) || 0, deletions: parseInt(deletions) || 0 }; }); changes.push(...unstagedFiles); } } catch (e) { // No unstaged changes } // Get actual diff for small changes to help with commit messages for (const change of changes) { if (change.additions + change.deletions < 50) { // Only for small changes try { const diff = execSync(`git diff ${change.status === 'staged' ? '--cached' : ''} -- "${change.file}"`, { encoding: 'utf-8' }); change.diff = diff; } catch (e) { // Skip if diff fails } } } return changes; } catch (error) { return []; } } /** * Build contextual search query from available information */ function buildContextualSearchQuery(target, recentMessages, analysisType) { let query = ''; if (target) { query = target; } else if (analysisType === 'git') { query = 'commit message git changes implementation'; } else if (recentMessages.length > 0) { // Extract key terms from recent messages const recentContent = recentMessages .slice(0, 5) .map(msg => msg.content || '') .join(' ') .toLowerCase(); // Look for technical terms, patterns, and topics const keywords = extractKeywords(recentContent); query = keywords.slice(0, 3).join(' '); // Top 3 keywords } return query.trim() || null; } /** * Extract keywords from text for search */ function extractKeywords(text) { const commonWords = new Set([ 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were', 'be', 'been', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'can', 'may', 'might', 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they', 'me', 'him', 'her', 'us', 'them', 'my', 'your', 'his', 'her', 'its', 'our', 'their' ]); return text .split(/\s+/) .map(word => word.replace(/[^\w]/g, '').toLowerCase()) .filter(word => word.length > 3 && !commonWords.has(word)) .filter((word, index, arr) => arr.indexOf(word) === index) // unique .slice(0, 10); // top 10 } /** * Generate analyzer-based analysis with unified scoring */ async function generateAnalyzerBasedAnalysis(analysisType, context, deep) { const projectRoot = process.cwd(); const results = {}; console.log(chalk.cyan('\nšŸ” Running Static Code Analysis\n')); try { if (analysisType === 'comprehensive' || analysisType === 'security') { const securityAnalyzer = new SecurityAnalyzer(projectRoot); const securitySpinner = ora('Analyzing security vulnerabilities...').start(); try { const securityResult = await securityAnalyzer.fullAnalysis(); results.security = { score: securityResult.securityScore, issues: securityResult.vulnerabilities.map((issue) => ({ type: issue.type, severity: issue.severity, confidence: 'high', impact: issue.severity === 'critical' ? 'major' : issue.severity === 'high' ? 'major' : 'moderate', message: issue.message, file: issue.file, line: issue.line, suggestion: issue.recommendation })), strengths: [], recommendations: securityResult.recommendations?.map((r) => r.description) || [] }; securitySpinner.succeed(`Security analysis complete (Score: ${securityResult.securityScore}/100)`); } catch (error) { securitySpinner.fail('Security analysis failed'); results.security = { score: 50, issues: [], strengths: [], recommendations: [] }; } } if (analysisType === 'comprehensive' || analysisType === 'performance') { const performanceAnalyzer = new PerformanceAnalyzer(projectRoot); const performanceSpinner = ora('Analyzing performance bottlenecks...').start(); try { const performanceResult = await performanceAnalyzer.analyze(); results.performance = { score: performanceResult.score, issues: performanceResult.issues.map(issue => ({ type: issue.type, severity: issue.impact === 'high' ? 'high' : issue.impact === 'medium' ? 'medium' : 'low', confidence: 'high', impact: issue.impact === 'high' ? 'major' : 'moderate', message: issue.message, file: issue.file, line: issue.line, suggestion: issue.recommendation })), strengths: [], recommendations: [] }; performanceSpinner.succeed(`Performance analysis complete (Score: ${performanceResult.score}/100)`); } catch (error) { performanceSpinner.fail('Performance analysis failed'); results.performance = { score: 50, issues: [], strengths: [], recommendations: [] }; } } if (analysisType === 'comprehensive' || analysisType === 'documentation') { const documentationAnalyzer = new DocumentationAnalyzer(projectRoot); const documentationSpinner = ora('Analyzing documentation quality...').start(); try { const documentationResult = await documentationAnalyzer.analyze(); results.documentation = { score: documentationResult.score, issues: documentationResult.issues.map(issue => ({ type: issue.type, severity: issue.severity, confidence: 'high', impact: issue.severity === 'critical' ? 'major' : 'moderate', message: issue.message, file: issue.file, line: issue.line, suggestion: issue.suggestion })), strengths: documentationResult.strengths || [], recommendations: documentationResult.recommendations?.map(r => r.title) || [] }; documentationSpinner.succeed(`Documentation analysis complete (Score: ${documentationResult.score}/100)`); } catch (error) { documentationSpinner.fail('Documentation analysis failed'); results.documentation = { score: 50, issues: [], strengths: [], recommendations: [] }; } } if (analysisType === 'comprehensive' || analysisType === 'quality') { const qualityAnalyzer = new CodeQualityAnalyzer(projectRoot); const qualitySpinner = ora('Analyzing code quality...').start(); try { const qualityResult = await qualityAnalyzer.quickScan(); results.quality = { score: qualityResult.score, issues: qualityResult.issues.map((issue) => ({ type: issue.rule, severity: issue.severity === 'error' ? 'high' : issue.severity === 'warning' ? 'medium' : 'low', confidence: 'medium', impact: issue.severity === 'error' ? 'major' : 'moderate', message: issue.message, file: issue.file, line: issue.line, suggestion: issue.message })), strengths: [], recommendations: qualityResult.suggestions || [] }; qualitySpinner.succeed(`Code quality analysis complete (Score: ${qualityResult.score}/100)`); } catch (error) { qualitySpinner.fail('Code quality analysis failed'); results.quality = { score: 50, issues: [], strengths: [], recommendations: [] }; } } if (analysisType === 'comprehensive' || analysisType === 'dependencies') { const dependencyAnalyzer = new DependencyAnalyzer(projectRoot); const dependencySpinner = ora('Analyzing dependencies...').start(); try { const dependencyResult = await dependencyAnalyzer.analyze(); const depScore = Math.max(0, 100 - (dependencyResult.vulnerabilities * 20) - (dependencyResult.outdated * 5) - (dependencyResult.unused.length * 2)); const issues = []; if (dependencyResult.vulnerabilities > 0) { issues.push({ type: 'vulnerabilities', severity: 'high', confidence: 'high', impact: 'major', message: `${dependencyResult.vulnerabilities} vulnerable dependencies detected`, file: 'package.json', suggestion: 'Update vulnerable dependencies to latest secure versions' }); } if (dependencyResult.outdated > 0) { issues.push({ type: 'outdated', severity: 'medium', confidence: 'medium', impact: 'moderate', message: `${dependencyResult.outdated} outdated dependencies detected`, file: 'package.json', suggestion: 'Update outdated dependencies for better security and features' }); } if (dependencyResult.unused.length > 0) { issues.push({ type: 'unused', severity: 'low', confidence: 'medium', impact: 'minor', message: `${dependencyResult.unused.length} unused dependencies: ${dependencyResult.unused.slice(0, 3).join(', ')}`, file: 'package.json', suggestion: 'Remove unused dependencies to reduce bundle size' }); } results.dependencies = { score: depScore, issues, strengths: dependencyResult.totalDependencies > 0 ? [`Managing ${dependencyResult.totalDependencies} dependencies`] : [], recommendations: issues.map(issue => issue.suggestion) }; dependencySpinner.succeed(`Dependency analysis complete (Score: ${depScore}/100)`); } catch (error) { dependencySpinner.fail('Dependency analysis failed'); results.dependencies = { score: 50, issues: [], strengths: [], recommendations: [] }; } } // Calculate unified score console.log(chalk.cyan('\nšŸ“Š Calculating Unified Score\n')); const unifiedScore = UnifiedScoringSystem.calculateUnifiedScore(results); return { type: analysisType, timestamp: new Date().toISOString(), unifiedScore, analyzerResults: results, summary: UnifiedScoringSystem.createScoringSummary(unifiedScore) }; } catch (error) { console.error(chalk.red(`Analysis failed: ${error instanceof Error ? error.message : String(error)}`)); return { type: analysisType, timestamp: new Date().toISOString(), error: error instanceof Error ? error.message : String(error) }; } } /** * Generate contextual analysis based on gathered information */ async function generateContextualAnalysis(analysisType, target, context, deep) { const analysis = { type: analysisType, target, timestamp: new Date().toISOString(), context: { hasRecentMessages: context.recentMessages.length > 0, hasGitChanges: context.gitChanges.length > 0, hasRelatedMemories: context.relatedMemories.length > 0, hasPatterns: context.patterns.length > 0 } }; switch (analysisType) { case 'git': analysis.gitAnalysis = analyzeGitContext(context.gitChanges, context.relatedMemories); break; case 'code': analysis.codeAnalysis = await analyzeCodeContext(target, context); break; case 'issue': analysis.issueAnalysis = analyzeIssueContext(target, context); break; case 'patterns': analysis.patternAnalysis = analyzePatternContext(context.patterns, context.relatedMemories); break; default: analysis.contextAnalysis = analyzeGeneralContext(context); } return analysis; } /** * Analyze git changes for commit message suggestions */ function analyzeGitContext(gitChanges, relatedMemories) { if (gitChanges.length === 0) { return { message: 'No git changes detected', suggestions: ['Make some changes first, then run analysis'] }; } const totalAdditions = gitChanges.reduce((sum, change) => sum + change.additions, 0); const totalDeletions = gitChanges.reduce((sum, change) => sum + change.deletions, 0); // Analyze change patterns const fileTypes = gitChanges.map(change => path.extname(change.file)).filter(ext => ext); const directories = gitChanges.map(change => path.dirname(change.file)); const changeType = determineChangeType(gitChanges); // Generate commit message suggestions const suggestions = generateCommitMessageSuggestions(gitChanges, changeType, relatedMemories); // Debug output removed return { summary: `${gitChanges.length} files changed, ${totalAdditions} insertions(+), ${totalDeletions} deletions(-)`, changeType, fileTypes: [...new Set(fileTypes)], directories: [...new Set(directories)], commitSuggestions: suggestions, relatedContext: relatedMemories.length > 0 ? `Found ${relatedMemories.length} related memories from past work` : null }; } /** * Determine the type of changes being made */ function determineChangeType(gitChanges) { const files = gitChanges.map(change => change.file.toLowerCase()); if (files.some(f => f.includes('test'))) return 'test'; if (files.some(f => f.includes('doc') || f.includes('readme'))) return 'docs'; if (files.some(f => f.includes('config') || f.includes('.json') || f.includes('.yml'))) return 'config'; if (files.some(f => f.includes('style') || f.includes('.css') || f.includes('.scss'))) return 'style'; if (gitChanges.every(change => change.additions === 0)) return 'refactor'; if (gitChanges.some(change => change.file.includes('fix') || change.file.includes('bug'))) return 'fix'; return 'feat'; } /** * Generate commit message suggestions based on changes and context */ function generateCommitMessageSuggestions(gitChanges, changeType, relatedMemories) { const suggestions = []; // Basic type-based suggestions const fileCount = gitChanges.length; const mainFiles = gitChanges.slice(0, 3).map(change => path.basename(change.file, path.extname(change.file))); if (changeType === 'feat') { suggestions.push(`feat: add ${mainFiles.join(', ')} implementation`); suggestions.push(`feat: implement ${mainFiles[0]} functionality`); } else if (changeType === 'fix') { suggestions.push(`fix: resolve issues in ${mainFiles.join(', ')}`); suggestions.push(`fix: correct ${mainFiles[0]} behavior`); } else if (changeType === 'docs') { suggestions.push(`docs: update ${mainFiles.join(', ')} documentation`); suggestions.push(`docs: improve project documentation`); } else if (changeType === 'test') { suggestions.push(`test: add tests for ${mainFiles.join(', ')}`); suggestions.push(`test: improve test coverage`); } else if (changeType === 'refactor') { suggestions.push(`refactor: restructure ${mainFiles.join(', ')}`); suggestions.push(`refactor: improve code organization`); } else if (changeType === 'config') { suggestions.push(`config: update ${mainFiles.join(', ')} configuration`); suggestions.push(`chore: update project configuration`); suggestions.push(`config: modify ${mainFiles[0]} settings`); } else if (changeType === 'style') { suggestions.push(`style: update ${mainFiles.join(', ')} styling`); suggestions.push(`style: improve visual appearance`); } // Context-aware suggestions from memory if (relatedMemories.length > 0) { const memoryContext = relatedMemories[0].content || ''; if (memoryContext.toLowerCase().includes('bug') || memoryContext.toLowerCase().includes('fix')) { suggestions.unshift(`fix: address ${memoryContext.split(' ').slice(0, 3).join(' ')}`); } else if (memoryContext.toLowerCase().includes('feature') || memoryContext.toLowerCase().includes('add')) { suggestions.unshift(`feat: ${memoryContext.split(' ').slice(0, 4).join(' ')}`); } } return suggestions.slice(0, 5); // Top 5 suggestions } /** * Analyze code context */ async function analyzeCodeContext(codePath, context) { const fullPath = path.resolve(codePath); if (!fs.existsSync(fullPath)) { return { error: `Path does not exist: ${codePath}`, suggestions: ['Check the file path and try again'] }; } const stats = fs.statSync(fullPath); const isDirectory = stats.isDirectory(); let analysis = { path: fullPath, type: isDirectory ? 'directory' : 'file', exists: true }; if (isDirectory) { // Analyze directory structure const files = fs.readdirSync(fullPath); analysis.fileCount = files.length; analysis.fileTypes = [...new Set(files.map(f => path.extname(f)).filter(ext => ext))]; } else { // Analyze individual file const content = fs.readFileSync(fullPath, 'utf-8'); analysis.lines = content.split('\n').length; analysis.size = stats.size; analysis.extension = path.extname(fullPath); // Basic code analysis if (['.js', '.ts', '.py', '.java', '.cpp', '.c'].includes(analysis.extension)) { analysis.codeMetrics = analyzeCodeMetrics(content); } } // Add memory context if (context.relatedMemories.length > 0) { analysis.relatedWork = context.relatedMemories.map(memory => ({ content: memory.content, relevance: memory.score })); } return analysis; } /** * Basic code metrics analysis */ function analyzeCodeMetrics(code) { const lines = code.split('\n'); const nonEmptyLines = lines.filter(line => line.trim().length > 0); const commentLines = lines.filter(line => { const trimmed = line.trim(); return trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*') || trimmed.startsWith('*'); }); return { totalLines: lines.length, codeLines: nonEmptyLines.length - commentLines.length, commentLines: commentLines.length, commentRatio: Math.round((commentLines.length / nonEmptyLines.length) * 100) || 0 }; } /** * Analyze issue context */ function analyzeIssueContext(issue, context) { const analysis = { issue, understanding: `Analyzing issue: "${issue}"`, suggestions: [] }; // Basic issue classification const issueLower = issue.toLowerCase(); if (issueLower.includes('error') || issueLower.includes('bug') || issueLower.includes('fail')) { analysis.type = 'bug'; analysis.suggestions.push('Check logs for error details'); analysis.suggestions.push('Reproduce the issue with minimal example'); } else if (issueLower.includes('feature') || issueLower.includes('add') || issueLower.includes('implement')) { analysis.type = 'feature'; analysis.suggestions.push('Define clear requirements'); analysis.suggestions.push('Break down into smaller tasks'); } else if (issueLower.includes('slow') || issueLower.includes('performance')) { analysis.type = 'performance'; analysis.suggestions.push('Profile the application'); analysis.suggestions.push('Identify bottlenecks'); } // Add related memory context if (context.relatedMemories.length > 0) { analysis.relatedExperience = context.relatedMemories.map(memory => ({ content: memory.content, relevance: memory.score, lesson: extractLessonFromMemory(memory.content) })); } return analysis; } /** * Extract potential lessons from memory content */ function extractLessonFromMemory(content) { const lessonIndicators = [ 'learned that', 'discovered that', 'found that', 'realized that', 'solution was', 'fix was', 'key was', 'important to' ]; for (const indicator of lessonIndicators) { const index = content.toLowerCase().indexOf(indicator); if (index !== -1) { // Extract sentence containing the lesson const sentences = content.split(/[.!?]/); const lessonSentence = sentences.find(s => s.toLowerCase().includes(indicator)); return lessonSentence?.trim() || null; } } return null; } /** * Analyze pattern context */ function analyzePatternContext(patterns, relatedMemories) { return { patternCount: patterns.length, patterns: patterns.slice(0, 5), // Top 5 patterns memoryPatterns: relatedMemories.length > 0 ? 'Found related patterns in historical memory' : null }; } /** * Analyze general context */ function analyzeGeneralContext(context) { const insights = []; if (context.recentMessages.length > 0) { insights.push(`Found ${context.recentMessages.length} recent conversation messages`); // Extract common themes from recent messages const allContent = context.recentMessages.map(msg => msg.content || '').join(' ').toLowerCase(); const keywords = extractKeywords(allContent); if (keywords.length > 0) { insights.push(`Recent focus areas: ${keywords.slice(0, 3).join(', ')}`); } } if (context.gitChanges.length > 0) { insights.push(`${context.gitChanges.length} uncommitted changes detected`); } if (context.relatedMemories.length > 0) { insights.push(`${context.relatedMemories.length} related memories found`); } return { summary: 'General project context analysis', insights, recommendations: generateGeneralRecommendations(context) }; } /** * Generate general recommendations based on context */ function generateGeneralRecommendations(context) { const recommendations = []; if (context.gitChanges.length > 0) { recommendations.push('Consider committing your current changes'); recommendations.push('Run tests before committing'); } if (context.recentMessages.length > 0) { recommendations.push('Document recent decisions in project notes'); } if (context.relatedMemories.length > 0) { recommendations.push('Review related memories for insights'); } else { recommendations.push('Store key insights in memory for future reference'); } return recommendations; } /** * Display unified analysis results */ function displayUnifiedAnalysisResults(analysis) { if (analysis.error) { console.log(chalk.red(`āŒ ${analysis.error}`)); return; } const { unifiedScore, analyzerResults } = analysis; // Display overall unified score console.log(chalk.cyan('šŸŽÆ Unified Analysis Results')); console.log(chalk.gray('─'.repeat(60))); const scoreColor = unifiedScore.overall >= 80 ? chalk.green : unifiedScore.overall >= 60 ? chalk.yellow : chalk.red; console.log(scoreColor(`\nšŸ“Š Overall Score: ${unifiedScore.overall}/100`)); console.log(chalk.gray(`Risk Level: ${unifiedScore.risk.level.toUpperCase()}`)); console.log(chalk.gray(`Time to Address: ${unifiedScore.risk.timeToAddress}`)); // Display component scores console.log(chalk.cyan('\nšŸ“ˆ Component Scores:')); console.log(chalk.gray(` Security: ${unifiedScore.security}/100`)); console.log(chalk.gray(` Performance: ${unifiedScore.performance}/100`)); console.log(chalk.gray(` Quality: ${unifiedScore.quality}/100`)); console.log(chalk.gray(` Maintainability: ${unifiedScore.maintainability}/100`)); console.log(chalk.gray(` Documentation: ${unifiedScore.documentation}/100`)); // Display critical issues const allIssues = Object.values(analyzerResults).flatMap((result) => result.issues || []); const criticalIssues = allIssues.filter((issue) => issue.severity === 'critical'); const highIssues = allIssues.filter((issue) => issue.severity === 'high'); if (criticalIssues.length > 0) { console.log(chalk.red('\n🚨 Critical Issues:')); criticalIssues.slice(0, 5).forEach((issue, index) => { console.log(chalk.red(` ${index + 1}. ${issue.message}`)); if (issue.file) { console.log(chalk.gray(` File: ${issue.file}${issue.line ? `:${issue.line}` : ''}`)); } if (issue.suggestion) { console.log(chalk.yellow(` šŸ’” ${issue.suggestion}`)); } }); } if (highIssues.length > 0) { console.log(chalk.yellow('\nāš ļø High Priority Issues:')); highIssues.slice(0, 3).forEach((issue, index) => { console.log(chalk.yellow(` ${index + 1}. ${issue.message}`)); if (issue.file) { console.log(chalk.gray(` File: ${issue.file}${issue.line ? `:${issue.line}` : ''}`)); } }); } // Display risk factors if (unifiedScore.risk.factors && unifiedScore.risk.factors.length > 0) { console.log(chalk.magenta('\n⚔ Risk Factors:')); unifiedScore.risk.factors.slice(0, 3).forEach((factor, index) => { console.log(chalk.magenta(` ${index + 1}. ${factor.description}`)); console.log(chalk.gray(` Type: ${factor.type}, Severity: ${factor.severity}`)); console.log(chalk.blue(` šŸ’” ${factor.mitigation}`)); }); } // Display recommendations if (unifiedScore.risk.recommendations && unifiedScore.risk.recommendations.length > 0) { console.log(chalk.green('\nšŸ“‹ Key Recommendations:')); unifiedScore.risk.recommendations.slice(0, 5).forEach((rec, index) => { console.log(chalk.green(` ${index + 1}. ${rec}`)); }); } // Display strengths const allStrengths = Object.values(analyzerResults).flatMap((result) => result.strengths || []); if (allStrengths.length > 0) { console.log(chalk.cyan('\nšŸ’Ŗ Project Strengths:')); [...new Set(allStrengths)].slice(0, 5).forEach((strength, index) => { console.log(chalk.cyan(` āœ“ ${strength}`)); }); } // Display summary console.log(chalk.white('\nšŸ“ Summary:')); console.log(analysis.summary); } /** * Display comprehensive analysis results */ function displayAnalysisResults(analysis, context) { // Check if this is a unified analysis result if (analysis.unifiedScore && analysis.analyzerResults) { displayUnifiedAnalysisResults(analysis); return; } // Display context summary if (context.recentMessages.length > 0 || context.gitChanges.length > 0 || context.relatedMemories.length > 0) { console.log(chalk.cyan('šŸ“Š Analysis Context')); console.log(chalk.gray('─'.repeat(50))); if (context.recentMessages.length > 0) { console.log(chalk.white(`šŸ—£ļø Recent conversations: ${context.recentMessages.length} messages`)); } if (context.gitChanges.length > 0) { console.log(chalk.white(`šŸ“ Git changes: ${context.gitChanges.length} files modified`)); } if (context.relatedMemories.length > 0) { console.log(chalk.white(`🧠 Related memories: ${context.relatedMemories.length} found`)); } console.log(''); } // Display type-specific analysis if (analysis.gitAnalysis) { displayGitAnalysis(analysis.gitAnalysis); } else if (analysis.codeAnalysis) { displayCodeAnalysis(analysis.codeAnalysis); } else if (analysis.issueAnalysis) { displayIssueAnalysis(analysis.issueAnalysis); } else if (analysis.patternAnalysis) { displayPatternAnalysis(analysis.patternAnalysis); } else if (analysis.contextAnalysis) { displayContextAnalysis(analysis.contextAnalysis); } // Display related memories if available if (context.relatedMemories.length > 0) { console.log(chalk.blue('\n🧠 Related Memories')); console.log(chalk.gray('─'.repeat(50))); context.relatedMemories.slice(0, 3).forEach((memory, index) => { const content = memory.content || ''; const preview = content.length > 100 ? content.substring(0, 100) + '...' : content; console.log(chalk.blue(`${index + 1}. ${preview}`)); if (memory.score) { console.log(chalk.gray(` Relevance: ${Math.round(memory.score * 100)}%`)); } }); } } /** * Display git analysis results */ function displayGitAnalysis(gitAnalysis) { console.log(chalk.cyan('šŸ”„ Git Analysis')); console.log(chalk.gray('─'.repeat(50))); console.log(chalk.white(gitAnalysis.summary)); if (gitAnalysis.changeType) { console.log(chalk.yellow(`\nšŸ“‹ Change Type: ${gitAnalysis.changeType}`)); } if (gitAnalysis.commitSuggestions && gitAnalysis.commitSuggestions.length > 0) { console.log(chalk.green('\nšŸ’” Commit Message Suggestions:')); gitAnalysis.commitSuggestions.forEach((suggestion, index) => { console.log(chalk.green(` ${index + 1}. ${suggestion}`)); }); } else if (gitAnalysis.message) { console.log(chalk.yellow(`\n${gitAnalysis.message}`)); if (gitAnalysis.suggestions) { gitAnalysis.suggestions.forEach((suggestion, index) => { console.log(chalk.gray(` ${index + 1}. ${suggestion}`)); }); } } if (gitAnalysis.relatedContext) { console.log(chalk.gray(`\n${gitAnalysis.relatedContext}`)); } } /** * Display code analysis results */ function displayCodeAnalysis(codeAnalysis) { console.log(chalk.cyan('šŸ“„ Code Analysis')); console.log(chalk.gray('─'.repeat(50))); if (codeAnalysis.error) { console.log(chalk.red(`āŒ ${codeAnalysis.error}`)); return; } console.log(chalk.white(`Path: ${codeAnalysis.path}`)); console.log(chalk.white(`Type: ${codeAnalysis.type}`)); if (codeAnalysis.codeMetrics) { const metrics = codeAnalysis.codeMetrics; console.log(chalk.yellow('\nšŸ“Š Code Metrics:')); console.log(chalk.gray(` Lines: ${metrics.totalLines} (${metrics.codeLines} code, ${metrics.commentLines} comments)`)); console.log(chalk.gray(` Comment ratio: ${metrics.commentRatio}%`)); } if (codeAnalysis.relatedWork && codeAnalysis.relatedWork.length > 0) { console.log(chalk.blue('\nšŸ”— Related Work:')); codeAnalysis.relatedWork.slice(0, 2).forEach((work, index) => { console.log(chalk.blue(` ${index + 1}. ${work.content.substring(0, 80)}...`)); }); } } /** * Display issue analysis results */ function displayIssueAnalysis(issueAnalysis) { console.log(chalk.cyan('šŸ” Issue Analysis')); console.log(chalk.gray('─'.repeat(50))); console.log(chalk.white(issueAnalysis.understanding)); if (issueAnalysis.type) { console.log(chalk.yellow(`\nšŸ·ļø Type: ${issueAnalysis.type}`)); } if (issueAnalysis.suggestions && issueAnalysis.suggestions.length > 0) { console.log(chalk.green('\nšŸ’” Suggestions:')); issueAnalysis.suggestions.forEach((suggestion, index) => { console.log(chalk.green(` ${index + 1}. ${suggestion}`)); }); } if (issueAnalysis.relatedExperience && issueAnalysis.relatedExperience.length > 0) { console.log(chalk.blue('\nšŸ“š Related Experience:')); issueAnalysis.relatedExperience.forEach((exp, index) => { console.log(chalk.blue(` ${index + 1}. ${exp.content.substring(0, 80)}...`)); if (exp.lesson) { console.log(chalk.gray(` šŸ’” Lesson: ${exp.lesson}`)); } }); } } /** * Display pattern analysis results */ function displayPatternAnalysis(patternAnalysis) { console.log(chalk.cyan('šŸ”® Pattern Analysis')); console.log(chalk.gray('─'.repeat(50))); console.log(chalk.white(`Found ${patternAnalysis.patternCount} patterns`)); if (patternAnalysis.patterns && patternAnalysis.patterns.length > 0) { console.log(chalk.yellow('\nšŸ“‹ Development Patterns:')); patternAnalysis.patterns.forEach((pattern, index) => { console.log(chalk.yellow(` ${index + 1}. ${pattern.name || 'Pattern'}: ${pattern.description || 'No description'}`)); }); } } /** * Display context analysis results */ function displayContextAnalysis(contextAnalysis) { console.log(chalk.cyan('šŸ—ļø Context Analysis')); console.log(chalk.gray('─'.repeat(50))); console.log(chalk.white(contextAnalysis.summary)); if (contextAnalysis.insights && contextAnalysis.insights.length > 0) { console.log(chalk.yellow('\nšŸ” Insights:')); contextAnalysis.insights.forEach((insight) => { console.log(chalk.yellow(` • ${insight}`)); }); } if (contextAnalysis.recommendations && contextAnalysis.recommendations.length > 0) { console.log(chalk.green('\nšŸ’” Recommendations:')); contextAnalysis.recommendations.forEach((rec, index) => { console.log(chalk.green(` ${index + 1}. ${rec}`)); }); } } //# sourceMappingURL=analyze.js.map