UNPKG

context-forge

Version:

AI orchestration platform with autonomous teams, enhancement planning, migration tools, 25+ slash commands, checkpoints & hooks. Multi-IDE: Claude, Cursor, Windsurf, Cline, Copilot

200 lines (193 loc) • 9.94 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.analyzeCommand = void 0; const commander_1 = require("commander"); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const path_1 = __importDefault(require("path")); const fs_extra_1 = __importDefault(require("fs-extra")); const adapters_1 = require("../../adapters"); const projectAnalyzer_1 = require("../../services/projectAnalyzer"); const apiKeyManager_1 = require("../../services/apiKeyManager"); const retrofit_1 = require("../prompts/retrofit"); const generators_1 = require("../../generators"); const package_json_1 = require("../../../package.json"); const errorRecoveryService_1 = require("../../services/errorRecoveryService"); exports.analyzeCommand = new commander_1.Command('analyze') .description('Analyze existing project and generate AI-optimized documentation') .option('-o, --output <path>', 'output directory for generated files', '.') .option('-i, --ide <ide>', 'target IDE (claude, cursor, windsurf, cline, roo, gemini, copilot)', (value) => { const validIDEs = (0, adapters_1.getSupportedIDEs)(); const ides = value.split(',').map((ide) => ide.trim()); for (const ide of ides) { if (!validIDEs.includes(ide)) { throw new Error(`Invalid IDE: ${ide}. Valid options: ${validIDEs.join(', ')}`); } } return ides; }) .option('--no-ai', 'skip AI analysis and use pattern-based analysis only') .option('--config-only', 'generate configuration file only without documentation') .action(async (options) => { console.log(chalk_1.default.blue.bold('\nšŸ” Context Forge Analyzer\n')); console.log(chalk_1.default.gray("Let's analyze your existing project and create AI-optimized documentation.\n")); const spinner = (0, ora_1.default)(); const projectPath = process.cwd(); const outputPath = path_1.default.resolve(options.output); const errorRecovery = new errorRecoveryService_1.ErrorRecoveryService(); let config; try { // Initialize services const analyzer = new projectAnalyzer_1.ProjectAnalyzer(projectPath); const apiKeyManager = new apiKeyManager_1.ApiKeyManager(projectPath); // Step 1: Basic Project Analysis spinner.start('Analyzing project structure...'); const basicAnalysis = await analyzer.analyzeBasic(); spinner.succeed(`Detected: ${basicAnalysis.summary}`); console.log(chalk_1.default.cyan('\nšŸ“Š Project Overview:')); console.log(` • Type: ${basicAnalysis.projectType}`); console.log(` • Tech Stack: ${basicAnalysis.techStack.join(', ')}`); console.log(` • Components: ${basicAnalysis.fileStats.components} files`); console.log(` • API Routes: ${basicAnalysis.fileStats.routes} files`); if (basicAnalysis.existingDocs.length > 0) { console.log(` • Documentation: ${basicAnalysis.existingDocs.join(', ')}`); } let detailedAnalysis = null; let apiConfig = null; // Step 2: AI Analysis (if requested) if (options.ai !== false) { const useAI = await analyzer.shouldUseAI(); if (useAI) { apiConfig = await apiKeyManager.setupApiKey(); if (apiConfig) { spinner.start('Analyzing with AI...'); detailedAnalysis = await analyzer.analyzeDeep(apiConfig); spinner.succeed('AI analysis complete'); if (detailedAnalysis.insights.length > 0) { console.log(chalk_1.default.cyan('\nšŸ¤– AI Insights:')); detailedAnalysis.insights.forEach((insight) => { console.log(` • ${insight}`); }); } } } } // Step 3: Retrofit Questions spinner.stop(); // Stop spinner before interactive prompts config = await (0, retrofit_1.runRetrofitPrompts)(basicAnalysis, detailedAnalysis, options.ide); console.log(chalk_1.default.green('āœ” Configuration complete')); // Step 4: Generate Documentation if (!options.configOnly) { spinner.start('Generating AI-optimized documentation...'); await (0, generators_1.generateDocumentation)(config, outputPath); spinner.succeed('Documentation generated successfully!'); console.log(chalk_1.default.green('\nāœ… Analysis and generation complete!')); // Show comprehensive summary console.log(chalk_1.default.blue.bold('\nšŸ“‹ Summary of Changes:\n')); // API Configuration if (apiConfig) { console.log(chalk_1.default.cyan('šŸ”‘ API Configuration:')); console.log(` • API key stored in: ${chalk_1.default.green('.context-forge-api')}`); console.log(` • Provider: ${chalk_1.default.green(apiConfig.provider)}`); console.log(` • Added to .gitignore: ${chalk_1.default.green('āœ“')}\n`); } // Generated Files console.log(chalk_1.default.cyan('šŸ“ Generated Files:')); console.log(chalk_1.default.gray(' ' + outputPath + '/')); // CLAUDE.md status const claudeMdPath = path_1.default.join(outputPath, 'CLAUDE.md'); if (await fs_extra_1.default.pathExists(claudeMdPath)) { console.log(chalk_1.default.yellow(' ā”œā”€ā”€ CLAUDE.md (UPDATED - appended retrofit section)')); } // Docs folder const docsPath = path_1.default.join(outputPath, 'Docs'); if (await fs_extra_1.default.pathExists(docsPath)) { console.log(' ā”œā”€ā”€ Docs/'); const docFiles = await fs_extra_1.default.readdir(docsPath); docFiles.forEach((file, index) => { const isLast = index === docFiles.length - 1; console.log(` │ ${isLast ? '└──' : 'ā”œā”€ā”€'} ${chalk_1.default.green(file)}`); }); } // PRPs folder const prpsPath = path_1.default.join(outputPath, 'PRPs'); if (await fs_extra_1.default.pathExists(prpsPath)) { console.log(' └── PRPs/'); const prpFiles = await fs_extra_1.default.readdir(prpsPath); prpFiles.forEach((file, index) => { const isLast = index === prpFiles.length - 1; console.log(` ${isLast ? '└──' : 'ā”œā”€ā”€'} ${chalk_1.default.green(file)}`); }); } console.log(chalk_1.default.gray('\nšŸ’” Next steps:')); console.log(chalk_1.default.gray(' 1. Review the updated CLAUDE.md file')); console.log(chalk_1.default.gray(' 2. Check the PRPs folder for feature-specific implementations')); console.log(chalk_1.default.gray(' 3. Use these files with Claude Code for development')); // Save summary to file let summaryContent = `# Context Forge Retrofit Summary Generated on: ${new Date().toLocaleString()} ## Project Analysis - **Type**: ${config.projectType} - **Tech Stack**: ${Object.values(config.techStack).filter(Boolean).join(', ')} - **Components**: ${basicAnalysis.fileStats.components} files - **API Routes**: ${basicAnalysis.fileStats.routes} files - **Test Coverage**: ${basicAnalysis.fileStats.tests} test files ## API Configuration ${apiConfig ? `- **Provider**: ${apiConfig.provider} - **Key Location**: .context-forge-api - **Added to .gitignore**: āœ“` : 'No API configuration used'} ## Generated Files ### Updated Files - **CLAUDE.md**: Appended retrofit section with date marker ### New Files Created `; // Add Docs files if (await fs_extra_1.default.pathExists(docsPath)) { summaryContent += '\n#### Docs/\n'; const docFiles = await fs_extra_1.default.readdir(docsPath); docFiles.forEach((file) => { summaryContent += `- ${file}\n`; }); } // Add PRP files if (await fs_extra_1.default.pathExists(prpsPath)) { summaryContent += '\n#### PRPs/\n'; const prpFiles = await fs_extra_1.default.readdir(prpsPath); prpFiles.forEach((file) => { summaryContent += `- ${file}\n`; }); } summaryContent += `\n## Planned Features ${config.plannedFeatures && config.plannedFeatures.length > 0 ? config.plannedFeatures.map((f) => `- ${f}`).join('\n') : 'No specific features documented'} ## Next Steps 1. Review the updated CLAUDE.md file 2. Check the PRPs folder for feature-specific implementations 3. Use these files with Claude Code for development --- *Generated by Context Forge v${package_json_1.version}* `; const summaryPath = path_1.default.join(outputPath, 'retrofit-summary.md'); await fs_extra_1.default.writeFile(summaryPath, summaryContent); console.log(chalk_1.default.gray(`\nšŸ“„ Summary saved to: ${chalk_1.default.green('retrofit-summary.md')}`)); } } catch (error) { spinner.fail('Analysis failed'); // Use error recovery service to provide intelligent suggestions await errorRecovery.handleError(error, { command: 'analyze', operation: 'project analysis', projectPath, config, }); throw error; } }); //# sourceMappingURL=analyze.js.map