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
JavaScript
;
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