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

314 lines 12.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProjectAnalyzer = void 0; const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const inquirer_1 = __importDefault(require("inquirer")); const chalk_1 = __importDefault(require("chalk")); class ProjectAnalyzer { constructor(projectPath) { this.projectPath = projectPath; } async analyzeBasic() { const files = await this.getAllFiles(this.projectPath); const packageJson = await this.readPackageJson(); const analysis = { projectType: this.detectProjectType(files, packageJson), techStack: this.detectTechStack(files, packageJson), fileStats: this.calculateFileStats(files), summary: '', existingDocs: this.findExistingDocs(files), packageManagers: this.detectPackageManagers(), frameworks: this.detectFrameworks(files, packageJson), }; analysis.summary = this.generateSummary(analysis); return analysis; } async shouldUseAI() { const { useAI } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'useAI', message: 'Enable AI-powered analysis for deeper insights?', default: true, }, ]); if (!useAI) { console.log(chalk_1.default.gray('Using pattern-based analysis only.')); } return useAI; } async analyzeDeep(_apiConfig) { // This would integrate with AI providers for deeper analysis // For now, return mock analysis based on basic patterns const basicAnalysis = await this.analyzeBasic(); return { insights: [ `Detected ${basicAnalysis.techStack.join(' + ')} architecture`, `Found ${basicAnalysis.fileStats.components} components - good modular structure`, `${basicAnalysis.fileStats.tests} test files found - consider increasing coverage`, ], recommendations: [ 'Add comprehensive README with setup instructions', 'Consider adding TypeScript for better type safety', 'Implement error boundary components for React apps', 'Add API documentation for backend routes', ], architecture: { patterns: this.detectArchitecturalPatterns(basicAnalysis), structure: this.analyzeStructure(basicAnalysis), complexity: this.assessComplexity(basicAnalysis), }, codeQuality: { score: this.calculateQualityScore(basicAnalysis), issues: this.identifyIssues(basicAnalysis), suggestions: this.generateSuggestions(basicAnalysis), }, }; } async getAllFiles(dir) { const files = []; const items = await fs_extra_1.default.readdir(dir); for (const item of items) { if (item.startsWith('.') && item !== '.env.example') continue; if (item === 'node_modules' || item === 'dist' || item === 'build') continue; const fullPath = path_1.default.join(dir, item); const stat = await fs_extra_1.default.stat(fullPath); if (stat.isDirectory()) { const subFiles = await this.getAllFiles(fullPath); files.push(...subFiles); } else { files.push(fullPath); } } return files; } async readPackageJson() { try { const packagePath = path_1.default.join(this.projectPath, 'package.json'); if (await fs_extra_1.default.pathExists(packagePath)) { return await fs_extra_1.default.readJson(packagePath); } } catch { // Package.json not found or invalid } return null; } detectProjectType(files, packageJson) { if (packageJson) { const deps = { ...packageJson.dependencies, ...packageJson.devDependencies, }; if (deps.next || deps['@next/core-web-vitals']) return 'Next.js'; if (deps.react) return 'React'; if (deps.vue) return 'Vue.js'; if (deps.angular || deps['@angular/core']) return 'Angular'; if (deps.express) return 'Express.js'; if (deps.fastapi) return 'FastAPI'; if (deps.django) return 'Django'; } const extensions = files.map((f) => path_1.default.extname(f)); if (extensions.includes('.tsx') || extensions.includes('.jsx')) return 'React/JSX'; if (extensions.includes('.vue')) return 'Vue.js'; if (extensions.includes('.py')) return 'Python'; if (extensions.includes('.rs')) return 'Rust'; if (extensions.includes('.go')) return 'Go'; if (extensions.includes('.java')) return 'Java'; if (extensions.includes('.ts') || extensions.includes('.js')) return 'JavaScript/TypeScript'; return 'Mixed/Unknown'; } detectTechStack(files, packageJson) { const stack = []; if (packageJson) { const deps = { ...packageJson.dependencies, ...packageJson.devDependencies, }; // Frontend frameworks if (deps.next) stack.push('Next.js'); else if (deps.react) stack.push('React'); if (deps.vue) stack.push('Vue.js'); if (deps['@angular/core']) stack.push('Angular'); // Backend frameworks if (deps.express) stack.push('Express.js'); if (deps.fastify) stack.push('Fastify'); // Databases if (deps.mongoose || deps.mongodb) stack.push('MongoDB'); if (deps.pg || deps.postgres) stack.push('PostgreSQL'); if (deps.mysql2 || deps.mysql) stack.push('MySQL'); if (deps.sqlite3) stack.push('SQLite'); // Tools if (deps.typescript) stack.push('TypeScript'); if (deps.tailwindcss) stack.push('Tailwind CSS'); if (deps.prisma) stack.push('Prisma'); } // Detect from file extensions and names const extensions = files.map((f) => path_1.default.extname(f)); const filenames = files.map((f) => path_1.default.basename(f)); if (extensions.includes('.py')) stack.push('Python'); if (extensions.includes('.rs')) stack.push('Rust'); if (extensions.includes('.go')) stack.push('Go'); if (filenames.includes('Dockerfile')) stack.push('Docker'); if (filenames.includes('docker-compose.yml')) stack.push('Docker Compose'); return [...new Set(stack)]; } calculateFileStats(files) { return { total: files.length, components: files.filter((f) => f.includes('component') || /\.(jsx|tsx)$/.test(f) || (f.includes('/src/') && /\.(js|ts)$/.test(f))).length, routes: files.filter((f) => f.includes('route') || f.includes('api/') || f.includes('pages/') || (f.includes('app/') && f.includes('route.'))).length, tests: files.filter((f) => f.includes('.test.') || f.includes('.spec.') || f.includes('__tests__')).length, config: files.filter((f) => f.includes('config') || /\.(json|yaml|yml|toml|ini)$/.test(f)) .length, }; } findExistingDocs(files) { return files .filter((f) => /\.(md|txt|rst)$/i.test(f)) .map((f) => path_1.default.basename(f)) .filter((f) => !f.startsWith('.')); } detectPackageManagers() { const managers = []; const lockFiles = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb']; lockFiles.forEach((lockFile) => { if (fs_extra_1.default.pathExistsSync(path_1.default.join(this.projectPath, lockFile))) { managers.push(lockFile.split('-')[0] || lockFile.split('.')[0]); } }); return managers.length > 0 ? managers : ['npm']; } detectFrameworks(files, packageJson) { const frameworks = []; if (packageJson) { const deps = { ...packageJson.dependencies, ...packageJson.devDependencies, }; Object.keys(deps).forEach((dep) => { if (dep.startsWith('@angular/')) frameworks.push('Angular'); if (dep === 'vue') frameworks.push('Vue.js'); if (dep === 'react') frameworks.push('React'); if (dep === 'next') frameworks.push('Next.js'); }); } return [...new Set(frameworks)]; } generateSummary(analysis) { const { projectType, techStack, fileStats } = analysis; return `${projectType} project with ${techStack.join(', ')} (${fileStats.total} files)`; } detectArchitecturalPatterns(analysis) { const patterns = []; if (analysis.techStack.includes('React')) patterns.push('Component-based'); if (analysis.fileStats.routes > 0) patterns.push('Route-based'); if (analysis.techStack.includes('Prisma')) patterns.push('ORM-based'); if (analysis.techStack.includes('Next.js')) patterns.push('Full-stack'); return patterns; } analyzeStructure(analysis) { if (analysis.fileStats.components > 20) return 'Large modular structure'; if (analysis.fileStats.components > 5) return 'Medium modular structure'; return 'Small/simple structure'; } assessComplexity(analysis) { const score = analysis.fileStats.total + analysis.techStack.length * 5; if (score > 100) return 'high'; if (score > 30) return 'medium'; return 'low'; } calculateQualityScore(analysis) { let score = 50; // Base score if (analysis.techStack.includes('TypeScript')) score += 20; if (analysis.fileStats.tests > 0) score += 15; if (analysis.existingDocs.length > 0) score += 10; if (analysis.techStack.includes('Prisma')) score += 5; return Math.min(100, score); } identifyIssues(analysis) { const issues = []; if (analysis.fileStats.tests === 0) issues.push('No test files found'); if (analysis.existingDocs.length === 0) issues.push('No documentation files found'); if (!analysis.techStack.includes('TypeScript') && analysis.projectType.includes('JavaScript')) { issues.push('Consider TypeScript for better type safety'); } return issues; } generateSuggestions(analysis) { const suggestions = []; suggestions.push('Add comprehensive README.md'); suggestions.push('Create API documentation'); if (analysis.fileStats.tests === 0) { suggestions.push('Add unit and integration tests'); } if (!analysis.techStack.includes('TypeScript')) { suggestions.push('Consider migrating to TypeScript'); } return suggestions; } } exports.ProjectAnalyzer = ProjectAnalyzer; //# sourceMappingURL=projectAnalyzer.js.map