UNPKG

repository-analyzer

Version:

Transform code repositories into strategic intelligence using extensible AI agents. Analyze technical debt, business value, and deployment readiness automatically.

330 lines • 15 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentOrchestrator = exports.AgentDiscovery = exports.RepositoryAnalyzer = void 0; const commander_1 = require("commander"); const inquirer_1 = __importDefault(require("inquirer")); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const AgentOrchestrator_1 = require("./AgentOrchestrator"); Object.defineProperty(exports, "AgentOrchestrator", { enumerable: true, get: function () { return AgentOrchestrator_1.AgentOrchestrator; } }); const AgentDiscovery_1 = require("./AgentDiscovery"); Object.defineProperty(exports, "AgentDiscovery", { enumerable: true, get: function () { return AgentDiscovery_1.AgentDiscovery; } }); class RepositoryAnalyzer { constructor() { this.orchestrator = new AgentOrchestrator_1.AgentOrchestrator(); this.discovery = new AgentDiscovery_1.AgentDiscovery(); this.program = new commander_1.Command(); this.setupCLI(); } setupCLI() { this.program .name('repo-analyze') .description('Transform code repositories into strategic intelligence using extensible AI agents') .version(this.getVersion()) .argument('[path]', 'Path to repository or directory containing repositories') .option('--config', 'Interactive configuration setup') .option('--validate', 'Validate system setup') .option('--list-agents', 'List all available agents') .option('--agents <list>', 'Comma-separated list of agents to use') .option('--quick', 'Quick analysis mode (core agents only)') .option('--deep', 'Deep analysis mode (all available agents)') .option('--output <dir>', 'Custom output directory') .option('--jobs <number>', 'Number of parallel jobs (1-8)', '3') .option('--preview', 'Preview what would be analyzed') .option('--no-open', 'Don\'t auto-open results') .option('--claude-cmd <command>', 'Claude command to use', 'claude') .option('--verbose', 'Verbose output'); } getVersion() { try { const packagePath = path.join(__dirname, '..', 'package.json'); const packageJson = require(packagePath); return packageJson.version; } catch { return '1.0.0'; } } async main() { try { this.program.parse(); const options = this.program.opts(); const [targetPath] = this.program.args; this.printBanner(); // Handle special commands if (options.validate) { const valid = await this.orchestrator.validateSetup(options.claudeCmd); return valid ? 0 : 1; } if (options.listAgents) { await this.orchestrator.listAgents(); return 0; } if (options.config) { await this.interactiveConfig(); if (!targetPath) return 0; } // Validate setup first const setupValid = await this.orchestrator.validateSetup(options.claudeCmd); if (!setupValid) { console.log(chalk_1.default.red('\\nāŒ Setup validation failed. Run with --validate for details.')); return 1; } // Get target path const analysisPath = targetPath || await this.promptForPath(); if (!analysisPath) { console.log(chalk_1.default.red('āŒ No path provided for analysis')); return 1; } // Validate path exists if (!await fs.pathExists(analysisPath)) { console.log(chalk_1.default.red(`āŒ Path does not exist: ${analysisPath}`)); return 1; } // Determine output directory const outputDir = options.output || this.getDefaultOutputDir(analysisPath); await fs.ensureDir(outputDir); // Determine which agents to use const selectedAgents = await this.determineAgents(options); // Show preview if requested if (options.preview) { await this.showPreview(analysisPath, selectedAgents, outputDir); return 0; } // Confirm execution if (!await this.confirmExecution(analysisPath, selectedAgents, outputDir)) { console.log(chalk_1.default.yellow('Analysis cancelled')); return 0; } // Execute analysis const results = await this.orchestrator.executeAnalysis({ repositoryPath: analysisPath, outputDir, selectedAgents, parallelJobs: Math.min(Math.max(parseInt(options.jobs), 1), 8), verbose: options.verbose, claudeCommand: options.claudeCmd }); // Display results this.displayResults(results, outputDir); // Auto-open results if requested if (!options.noOpen) { await this.openResults(outputDir); } const successCount = results.filter(r => r.success).length; console.log(chalk_1.default.green(`\\nšŸŽ‰ Analysis complete! ${successCount}/${results.length} agents succeeded`)); return results.every(r => r.success) ? 0 : 1; } catch (error) { console.error(chalk_1.default.red(`\\nāŒ Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); if (this.program.opts().verbose) { console.error(chalk_1.default.gray(error instanceof Error ? error.stack : 'No stack trace')); } return 1; } } printBanner() { console.log(chalk_1.default.blue(` ╔══════════════════════════════════════════════════════════════╗ ā•‘ šŸš€ Repository Analyzer v${this.getVersion().padEnd(17)}ā•‘ ā•‘ Transform Code into Strategic Intelligence ā•‘ ā•‘ Extensible AI Agents ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• `)); } async promptForPath() { const { path: targetPath } = await inquirer_1.default.prompt([ { type: 'input', name: 'path', message: 'šŸ“‚ Enter path to repository or directory:', validate: (input) => { if (!input.trim()) return 'Path is required'; return true; } } ]); return targetPath.trim(); } getDefaultOutputDir(analysisPath) { const baseName = path.basename(analysisPath); const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0]; return path.join(process.cwd(), 'analysis', `${baseName}-${timestamp}`); } async determineAgents(options) { if (options.agents) { return options.agents.split(',').map((s) => s.trim()); } if (options.quick) { const coreAgents = await this.discovery.getAgentsByCategory('core'); return coreAgents.slice(0, 2).map(a => a.id); // Only first 2 core agents for quick mode } if (options.deep) { const allAgents = await this.discovery.discoverAgents(); return allAgents.map(a => a.id); } // Default: use all core agents const coreAgents = await this.discovery.getAgentsByCategory('core'); return coreAgents.map(a => a.id); } async showPreview(analysisPath, selectedAgents, outputDir) { console.log(chalk_1.default.blue('\\nšŸ” Analysis Preview:')); console.log(chalk_1.default.gray('═'.repeat(50))); console.log(`šŸ“‚ Target: ${analysisPath}`); console.log(`šŸ“ Output: ${outputDir}`); if (selectedAgents) { console.log(`šŸ¤– Agents: ${selectedAgents.length}`); const agents = await this.discovery.discoverAgents(); const agentMap = new Map(agents.map(a => [a.id, a])); for (const agentId of selectedAgents) { const agent = agentMap.get(agentId); if (agent) { console.log(` • ${agent.name} (${agent.id})`); } } } // Estimate time const agentCount = selectedAgents?.length || 4; const estimatedMinutes = Math.ceil(agentCount * 2); // 2 minutes per agent average console.log(`ā±ļø Estimated time: ~${estimatedMinutes} minutes`); } async confirmExecution(analysisPath, selectedAgents, outputDir) { console.log(chalk_1.default.blue('\\nšŸ“‹ Analysis Plan:')); console.log(chalk_1.default.gray('═'.repeat(50))); await this.showPreview(analysisPath, selectedAgents, outputDir); const { proceed } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'proceed', message: 'šŸ¤” Proceed with analysis?', default: true } ]); return proceed; } displayResults(results, outputDir) { console.log(chalk_1.default.blue('\\nšŸ“Š Analysis Results:')); console.log(chalk_1.default.gray('═'.repeat(50))); const successful = results.filter(r => r.success); const failed = results.filter(r => !r.success); if (successful.length > 0) { console.log(chalk_1.default.green(`\\nāœ… Successful Agents (${successful.length}):`)); for (const result of successful) { const time = (result.executionTime / 1000).toFixed(1); console.log(` • ${result.agentId} (${time}s)`); } } if (failed.length > 0) { console.log(chalk_1.default.red(`\\nāŒ Failed Agents (${failed.length}):`)); for (const result of failed) { console.log(` • ${result.agentId}: ${result.error}`); } } console.log(chalk_1.default.blue(`\\nšŸ“ Results saved to: ${outputDir}`)); } async openResults(outputDir) { try { const { execa } = await Promise.resolve().then(() => __importStar(require('execa'))); // Look for main report file const reportFile = path.join(outputDir, 'analysis-report.md'); const fileToOpen = await fs.pathExists(reportFile) ? reportFile : outputDir; if (process.platform === 'darwin') { await execa('open', [fileToOpen]); } else if (process.platform === 'win32') { await execa('start', [fileToOpen], { shell: true }); } else { await execa('xdg-open', [fileToOpen]); } } catch { // Silently ignore if we can't open console.log(chalk_1.default.gray(`\\nOpen manually: ${outputDir}`)); } } async interactiveConfig() { console.log(chalk_1.default.blue('\\nāš™ļø Interactive Configuration')); console.log(chalk_1.default.gray('═'.repeat(50))); const agents = await this.discovery.discoverAgents(); const coreAgents = agents.filter(a => a.category === 'core'); const customAgents = agents.filter(a => a.category !== 'core'); console.log(`\\nšŸ”§ Found ${coreAgents.length} core agents`); if (customAgents.length > 0) { console.log(`šŸŽØ Found ${customAgents.length} custom agents`); } const { showAgents } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'showAgents', message: 'Would you like to see available agents?', default: true } ]); if (showAgents) { this.discovery.printAgentList(agents); } const { claudeCommand } = await inquirer_1.default.prompt([ { type: 'input', name: 'claudeCommand', message: 'Claude command (if not "claude"):', default: 'claude' } ]); // Test Claude command const spinner = (0, ora_1.default)('Testing Claude CLI...').start(); const setupValid = await this.orchestrator.validateSetup(claudeCommand); if (setupValid) { spinner.succeed('Claude CLI is working!'); } else { spinner.fail('Claude CLI test failed'); console.log(chalk_1.default.yellow('Please ensure Claude CLI is installed: https://claude.ai/code')); } console.log(chalk_1.default.green('\\nāœ… Configuration complete!')); console.log(chalk_1.default.blue('Now you can run: repo-analyze <path-to-analyze>')); } } exports.RepositoryAnalyzer = RepositoryAnalyzer; //# sourceMappingURL=index.js.map