UNPKG

mega-minds

Version:

Enhanced multi-agent workflow system for Claude Code projects with automated handoff management and Claude Code hooks integration

1,111 lines (977 loc) 35.4 kB
/** * Project Context Analyzer for Mega-Minds Variable-Driven Agent System * Automatically detects technology stack, project structure, and context * Enables universal compatibility across different tech stacks */ const fs = require('fs').promises; const path = require('path'); class ProjectContextAnalyzer { constructor(projectPath, config = {}) { this.projectPath = projectPath; this.config = { enableCaching: config.enableCaching !== false, cacheTimeout: config.cacheTimeout || 300000, // 5 minutes enableDeepAnalysis: config.enableDeepAnalysis !== false, ...config }; this.analysisCache = new Map(); this.stackProfiles = this.initializeStackProfiles(); } /** * Analyze complete project context * @param {Object} options - Analysis options * @returns {Object} Complete project context analysis */ async analyzeProject(options = {}) { try { const cacheKey = `full_analysis_${this.projectPath}`; // Check cache first if (this.config.enableCaching && this.analysisCache.has(cacheKey)) { const cached = this.analysisCache.get(cacheKey); if (!this.isCacheExpired(cached)) { return cached.analysis; } } console.log('🔍 Analyzing project context...'); // Perform comprehensive analysis const analysis = { metadata: await this.getProjectMetadata(), techStack: await this.detectTechStack(), structure: await this.analyzeStructure(), agents: await this.discoverAgents(), quality: await this.extractQualityStandards(), infrastructure: await this.detectInfrastructure(), workflow: await this.analyzeWorkflow(), projectMode: await this.detectProjectMode(), // Analysis metadata analyzedAt: new Date().toISOString(), analyzer: 'ProjectContextAnalyzer', version: '2.1.0' }; // Apply stack profile if match found const matchedProfile = this.matchStackProfile(analysis.techStack); if (matchedProfile) { analysis.stackProfile = matchedProfile; analysis.variables = this.generateVariables(analysis, matchedProfile); } else { analysis.variables = this.generateVariables(analysis); } // Cache the analysis this.cacheAnalysis(cacheKey, analysis); console.log(`✅ Project analysis complete: ${analysis.stackProfile?.name || 'Custom Stack'}`); return analysis; } catch (error) { console.error('❌ Project analysis failed:', error.message); return this.getFallbackAnalysis(); } } /** * Detect technology stack from project files * @returns {Object} Technology stack information */ async detectTechStack() { const techStack = { languages: [], frameworks: {}, databases: [], infrastructure: [], tools: [], confidence: 'unknown' }; try { // Check for JavaScript/Node.js stack const jsStack = await this.detectJavaScriptStack(); if (jsStack.detected) { techStack.languages.push('JavaScript'); if (jsStack.typescript) techStack.languages.push('TypeScript'); techStack.frameworks = { ...techStack.frameworks, ...jsStack.frameworks }; techStack.tools.push(...jsStack.tools); } // Check for Python stack const pythonStack = await this.detectPythonStack(); if (pythonStack.detected) { techStack.languages.push('Python'); techStack.frameworks = { ...techStack.frameworks, ...pythonStack.frameworks }; techStack.tools.push(...pythonStack.tools); } // Check for Java stack const javaStack = await this.detectJavaStack(); if (javaStack.detected) { techStack.languages.push('Java'); techStack.frameworks = { ...techStack.frameworks, ...javaStack.frameworks }; techStack.tools.push(...javaStack.tools); } // Check for other languages await this.detectOtherLanguages(techStack); // Detect databases techStack.databases = await this.detectDatabases(); // Detect infrastructure techStack.infrastructure = await this.detectInfrastructureTools(); // Calculate confidence score techStack.confidence = this.calculateTechStackConfidence(techStack); return techStack; } catch (error) { console.error('Tech stack detection error:', error.message); return this.getFallbackTechStack(); } } /** * Detect JavaScript/Node.js technology stack * @returns {Object} JavaScript stack information */ async detectJavaScriptStack() { const result = { detected: false, typescript: false, frameworks: {}, tools: [] }; try { // Check package.json const packageJson = await this.readPackageJson(); if (!packageJson) return result; result.detected = true; // Check for TypeScript if (packageJson.devDependencies?.typescript || packageJson.dependencies?.typescript) { result.typescript = true; } // Detect frontend frameworks if (packageJson.dependencies?.react) { result.frameworks.frontend = 'React'; result.frameworks.frontendVersion = packageJson.dependencies.react; } else if (packageJson.dependencies?.vue) { result.frameworks.frontend = 'Vue'; result.frameworks.frontendVersion = packageJson.dependencies.vue; } else if (packageJson.dependencies?.angular) { result.frameworks.frontend = 'Angular'; result.frameworks.frontendVersion = packageJson.dependencies.angular; } else if (packageJson.dependencies?.svelte) { result.frameworks.frontend = 'Svelte'; result.frameworks.frontendVersion = packageJson.dependencies.svelte; } // Detect meta frameworks if (packageJson.dependencies?.next) { result.frameworks.metaFramework = 'Next.js'; result.frameworks.metaFrameworkVersion = packageJson.dependencies.next; } else if (packageJson.dependencies?.nuxt) { result.frameworks.metaFramework = 'Nuxt'; result.frameworks.metaFrameworkVersion = packageJson.dependencies.nuxt; } else if (packageJson.dependencies?.gatsby) { result.frameworks.metaFramework = 'Gatsby'; result.frameworks.metaFrameworkVersion = packageJson.dependencies.gatsby; } // Detect backend frameworks if (packageJson.dependencies?.express) { result.frameworks.backend = 'Express'; result.frameworks.backendVersion = packageJson.dependencies.express; } else if (packageJson.dependencies?.fastify) { result.frameworks.backend = 'Fastify'; result.frameworks.backendVersion = packageJson.dependencies.fastify; } else if (packageJson.dependencies?.koa) { result.frameworks.backend = 'Koa'; result.frameworks.backendVersion = packageJson.dependencies.koa; } // Detect CSS frameworks if (packageJson.dependencies?.['tailwindcss'] || packageJson.devDependencies?.['tailwindcss']) { result.frameworks.css = 'Tailwind CSS'; } else if (packageJson.dependencies?.bootstrap) { result.frameworks.css = 'Bootstrap'; } else if (packageJson.dependencies?.['@mui/material']) { result.frameworks.css = 'Material-UI'; } // Detect state management if (packageJson.dependencies?.redux) { result.frameworks.stateManagement = 'Redux'; } else if (packageJson.dependencies?.zustand) { result.frameworks.stateManagement = 'Zustand'; } else if (packageJson.dependencies?.mobx) { result.frameworks.stateManagement = 'MobX'; } // Detect testing frameworks if (packageJson.devDependencies?.jest) { result.frameworks.testing = 'Jest'; result.tools.push('Jest'); } else if (packageJson.devDependencies?.vitest) { result.frameworks.testing = 'Vitest'; result.tools.push('Vitest'); } // Detect E2E frameworks if (packageJson.devDependencies?.playwright) { result.frameworks.e2e = 'Playwright'; result.tools.push('Playwright'); } else if (packageJson.devDependencies?.cypress) { result.frameworks.e2e = 'Cypress'; result.tools.push('Cypress'); } // Detect build tools if (packageJson.devDependencies?.vite) { result.frameworks.buildTool = 'Vite'; result.tools.push('Vite'); } else if (packageJson.devDependencies?.webpack) { result.frameworks.buildTool = 'Webpack'; result.tools.push('Webpack'); } return result; } catch (error) { console.error('JavaScript stack detection error:', error.message); return result; } } /** * Detect Python technology stack * @returns {Object} Python stack information */ async detectPythonStack() { const result = { detected: false, frameworks: {}, tools: [] }; try { // Check for Python files const pythonFiles = await this.findFiles(['*.py']); if (pythonFiles.length === 0) return result; result.detected = true; // Check requirements.txt const requirements = await this.readRequirements(); if (requirements) { // Detect Django if (requirements.includes('django')) { result.frameworks.backend = 'Django'; result.frameworks.language = 'Python'; } // Detect FastAPI else if (requirements.includes('fastapi')) { result.frameworks.backend = 'FastAPI'; result.frameworks.language = 'Python'; } // Detect Flask else if (requirements.includes('flask')) { result.frameworks.backend = 'Flask'; result.frameworks.language = 'Python'; } // Detect testing frameworks if (requirements.includes('pytest')) { result.frameworks.testing = 'pytest'; result.tools.push('pytest'); } // Detect databases if (requirements.includes('psycopg2') || requirements.includes('psycopg')) { result.frameworks.database = 'PostgreSQL'; } } // Check pyproject.toml const pyproject = await this.readPyprojectToml(); if (pyproject) { // Additional framework detection from pyproject.toml result.tools.push('Poetry'); } return result; } catch (error) { console.error('Python stack detection error:', error.message); return result; } } /** * Detect Java technology stack * @returns {Object} Java stack information */ async detectJavaStack() { const result = { detected: false, frameworks: {}, tools: [] }; try { // Check for Java files const javaFiles = await this.findFiles(['*.java']); if (javaFiles.length === 0) return result; result.detected = true; result.frameworks.language = 'Java'; // Check pom.xml (Maven) const pomExists = await this.fileExists('pom.xml'); if (pomExists) { result.frameworks.buildTool = 'Maven'; result.tools.push('Maven'); // Read pom.xml to detect Spring const pomContent = await this.readFile('pom.xml'); if (pomContent.includes('spring-boot')) { result.frameworks.backend = 'Spring Boot'; } else if (pomContent.includes('springframework')) { result.frameworks.backend = 'Spring Framework'; } } // Check build.gradle (Gradle) const gradleExists = await this.fileExists('build.gradle') || await this.fileExists('build.gradle.kts'); if (gradleExists) { result.frameworks.buildTool = 'Gradle'; result.tools.push('Gradle'); } return result; } catch (error) { console.error('Java stack detection error:', error.message); return result; } } /** * Analyze project structure * @returns {Object} Project structure information */ async analyzeStructure() { const structure = { type: 'unknown', directories: {}, patterns: {}, conventions: {} }; try { const rootDirs = await this.getRootDirectories(); // Detect Next.js App Router structure if (rootDirs.includes('app') && await this.fileExists('next.config.js')) { structure.type = 'nextjs-app-router'; structure.directories = { frontend: 'app', components: 'components', lib: 'lib', utils: 'utils', public: 'public', styles: 'styles' }; } // Detect Next.js Pages Router structure else if (rootDirs.includes('pages') && await this.fileExists('next.config.js')) { structure.type = 'nextjs-pages-router'; structure.directories = { frontend: 'pages', components: 'components', lib: 'lib', utils: 'utils', public: 'public', styles: 'styles' }; } // Detect Django structure else if (rootDirs.includes('manage.py') || rootDirs.some(dir => dir.endsWith('settings.py'))) { structure.type = 'django'; structure.directories = { backend: '.', apps: this.findDjangoApps(rootDirs), static: 'static', templates: 'templates' }; } // Detect generic React structure else if (rootDirs.includes('src') && await this.detectReactInSrc()) { structure.type = 'react-spa'; structure.directories = { frontend: 'src', components: 'src/components', utils: 'src/utils', public: 'public' }; } // Detect Java Maven structure else if (rootDirs.includes('src') && await this.fileExists('pom.xml')) { structure.type = 'maven-java'; structure.directories = { backend: 'src/main/java', resources: 'src/main/resources', tests: 'src/test/java' }; } // Detect file patterns structure.patterns = await this.detectFilePatterns(); return structure; } catch (error) { console.error('Structure analysis error:', error.message); return structure; } } /** * Generate variables based on analysis * @param {Object} analysis - Project analysis * @param {Object} stackProfile - Matched stack profile * @returns {Object} Generated variables */ generateVariables(analysis, stackProfile = null) { const variables = { // Apply stack profile variables first ...(stackProfile?.variables || {}), // Core tech stack variables '{{LANGUAGE_PRIMARY}}': analysis.techStack.languages[0] || 'JavaScript', '{{LANGUAGES_ALL}}': analysis.techStack.languages.join(', '), // Framework variables '{{FRONTEND_FRAMEWORK}}': analysis.techStack.frameworks.frontend || 'React', '{{BACKEND_FRAMEWORK}}': analysis.techStack.frameworks.backend || 'Express', '{{META_FRAMEWORK}}': analysis.techStack.frameworks.metaFramework || '', '{{CSS_FRAMEWORK}}': analysis.techStack.frameworks.css || 'CSS', '{{STATE_MANAGEMENT}}': analysis.techStack.frameworks.stateManagement || 'React State', '{{BUILD_TOOL}}': analysis.techStack.frameworks.buildTool || 'Webpack', // Testing variables '{{TESTING_FRAMEWORK}}': analysis.techStack.frameworks.testing || 'Jest', '{{E2E_FRAMEWORK}}': analysis.techStack.frameworks.e2e || 'Playwright', // Project structure variables '{{PROJECT_TYPE}}': analysis.structure.type, '{{FRONTEND_DIR}}': analysis.structure.directories.frontend || 'src', '{{BACKEND_DIR}}': analysis.structure.directories.backend || 'api', '{{COMPONENTS_DIR}}': analysis.structure.directories.components || 'components', '{{UTILS_DIR}}': analysis.structure.directories.utils || 'utils', '{{TESTS_DIR}}': analysis.structure.directories.tests || '__tests__', '{{PUBLIC_DIR}}': analysis.structure.directories.public || 'public', // File extension variables '{{FILE_EXTENSION}}': analysis.structure.patterns.primaryExtension || '.jsx', '{{STYLE_EXTENSION}}': analysis.structure.patterns.styleExtension || '.css', // Database variables '{{DATABASE_TYPE}}': analysis.techStack.databases[0] || 'PostgreSQL', '{{DATABASE_SERVICE}}': this.detectDatabaseService(analysis.techStack), // Quality standards (can be overridden by project config) '{{TEST_COVERAGE_MIN}}': '80', '{{CRITICAL_COVERAGE}}': '90', '{{COMPLEXITY_THRESHOLD}}': '10', // Infrastructure variables '{{DEPLOYMENT_TARGET}}': this.detectDeploymentTarget(analysis.techStack), '{{CI_CD_PLATFORM}}': this.detectCiCdPlatform(), '{{CONTAINER_PLATFORM}}': this.detectContainerPlatform(), // Analysis metadata '{{STACK_CONFIDENCE}}': analysis.techStack.confidence, '{{ANALYSIS_VERSION}}': analysis.version, '{{ANALYZED_AT}}': analysis.analyzedAt }; return variables; } /** * Initialize predefined stack profiles * @returns {Object} Stack profiles */ initializeStackProfiles() { return { 'react-nextjs-supabase': { name: 'React + Next.js + Supabase', match: (techStack) => techStack.frameworks.frontend === 'React' && techStack.frameworks.metaFramework === 'Next.js' && (techStack.databases.includes('PostgreSQL') || techStack.tools.includes('Supabase')), variables: { '{{FRONTEND_FRAMEWORK}}': 'React', '{{META_FRAMEWORK}}': 'Next.js', '{{CSS_FRAMEWORK}}': 'Tailwind CSS', '{{STATE_MANAGEMENT}}': 'Zustand', '{{DATABASE_SERVICE}}': 'Supabase', '{{DEPLOYMENT_TARGET}}': 'Vercel', '{{FILE_EXTENSION}}': '.tsx' } }, 'vue-nuxt': { name: 'Vue + Nuxt', match: (techStack) => techStack.frameworks.frontend === 'Vue' && techStack.frameworks.metaFramework === 'Nuxt', variables: { '{{FRONTEND_FRAMEWORK}}': 'Vue', '{{META_FRAMEWORK}}': 'Nuxt', '{{CSS_FRAMEWORK}}': 'UnoCSS', '{{STATE_MANAGEMENT}}': 'Pinia', '{{FILE_EXTENSION}}': '.vue' } }, 'python-django': { name: 'Python + Django', match: (techStack) => techStack.languages.includes('Python') && techStack.frameworks.backend === 'Django', variables: { '{{LANGUAGE_PRIMARY}}': 'Python', '{{BACKEND_FRAMEWORK}}': 'Django', '{{TESTING_FRAMEWORK}}': 'pytest', '{{DATABASE_TYPE}}': 'PostgreSQL', '{{FILE_EXTENSION}}': '.py' } }, 'java-spring': { name: 'Java + Spring Boot', match: (techStack) => techStack.languages.includes('Java') && techStack.frameworks.backend?.includes('Spring'), variables: { '{{LANGUAGE_PRIMARY}}': 'Java', '{{BACKEND_FRAMEWORK}}': 'Spring Boot', '{{BUILD_TOOL}}': 'Maven', '{{TESTING_FRAMEWORK}}': 'JUnit', '{{FILE_EXTENSION}}': '.java' } } }; } // Helper methods async readPackageJson() { try { const content = await this.readFile('package.json'); return JSON.parse(content); } catch { return null; } } async readRequirements() { try { return await this.readFile('requirements.txt'); } catch { return null; } } async readPyprojectToml() { try { return await this.readFile('pyproject.toml'); } catch { return null; } } async readFile(filePath) { const fullPath = path.join(this.projectPath, filePath); return await fs.readFile(fullPath, 'utf8'); } async fileExists(filePath) { try { const fullPath = path.join(this.projectPath, filePath); await fs.access(fullPath); return true; } catch { return false; } } async hasFiles(pattern) { try { const files = await this.findFiles([pattern]); return files.length > 0; } catch { return false; } } async readJsonFile(filePath) { try { const content = await this.readFile(filePath); return JSON.parse(content); } catch { return null; } } async getRootDirectories() { try { const entries = await fs.readdir(this.projectPath, { withFileTypes: true }); return entries.filter(entry => entry.isDirectory()).map(entry => entry.name); } catch { return []; } } async findFiles(patterns) { // Simple file pattern matching - would use glob in production try { const allFiles = await this.getAllFiles(this.projectPath); return allFiles.filter(file => patterns.some(pattern => file.endsWith(pattern.replace('*.', '.')) ) ); } catch { return []; } } async getAllFiles(dir, files = []) { try { const entries = await fs.readdir(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory() && !entry.name.startsWith('.')) { await this.getAllFiles(fullPath, files); } else if (entry.isFile()) { files.push(fullPath); } } } catch { // Ignore errors } return files; } matchStackProfile(techStack) { for (const [key, profile] of Object.entries(this.stackProfiles)) { if (profile.match(techStack)) { return { key, ...profile }; } } return null; } // Placeholder methods for additional analysis async detectDatabases() { // Would analyze config files, dependencies, etc. return ['PostgreSQL']; // Default } async detectInfrastructureTools() { // Would check for Docker, K8s configs, etc. return []; } async detectOtherLanguages(techStack) { try { // Detect Go if (await this.fileExists('go.mod') || await this.fileExists('go.sum')) { techStack.languages.push('Go'); techStack.frameworks.backend = 'Go Standard Library'; } // Detect Rust if (await this.fileExists('Cargo.toml')) { techStack.languages.push('Rust'); techStack.frameworks.backend = 'Rust'; } // Detect C#/.NET if (await this.fileExists('*.csproj') || await this.fileExists('*.sln')) { techStack.languages.push('C#'); techStack.frameworks.backend = '.NET'; } // Detect PHP if (await this.fileExists('composer.json') || await this.hasFiles('*.php')) { techStack.languages.push('PHP'); // Check for common PHP frameworks const composerJson = await this.readJsonFile('composer.json'); if (composerJson?.require) { if (composerJson.require['laravel/framework']) { techStack.frameworks.backend = 'Laravel'; } else if (composerJson.require['symfony/symfony']) { techStack.frameworks.backend = 'Symfony'; } else { techStack.frameworks.backend = 'PHP'; } } } // Detect Ruby if (await this.fileExists('Gemfile') || await this.hasFiles('*.rb')) { techStack.languages.push('Ruby'); const gemfile = await this.readFile('Gemfile'); if (gemfile?.includes('rails')) { techStack.frameworks.backend = 'Ruby on Rails'; } else { techStack.frameworks.backend = 'Ruby'; } } // Detect Swift (iOS) if (await this.hasFiles('*.swift') || await this.fileExists('Package.swift')) { techStack.languages.push('Swift'); techStack.frameworks.mobile = 'SwiftUI'; } // Detect Kotlin (Android) if (await this.hasFiles('*.kt') || await this.hasFiles('*.kts')) { techStack.languages.push('Kotlin'); techStack.frameworks.mobile = 'Android'; } } catch (error) { console.warn('Error detecting other languages:', error.message); } } /** * Detect project mode (new, existing, brownfield) * @returns {Object} Project mode analysis */ async detectProjectMode() { try { const hasSourceCode = await this.hasSourceFiles(); const hasDocumentation = await this.hasProjectDocumentation(); const hasConfigFiles = await this.hasConfigurationFiles(); const hasGitHistory = await this.hasGitHistory(); const lastModified = await this.getLastModificationTime(); // New project detection if (!hasSourceCode && !hasDocumentation && !hasConfigFiles) { return { mode: 'new-project', confidence: 'high', description: 'Empty project ready for new development', instructions: 'Tell me what you want to build and I\'ll coordinate the entire development process.', quickStart: '@project-orchestrator-agent "I want to build [describe your project]"', examples: [ 'I want to build a STIG search tool', 'I want to create a React dashboard app', 'I want to build an API for user management' ] }; } // Brownfield project (code exists, missing documentation) if (hasSourceCode && !hasDocumentation) { return { mode: 'brownfield-analysis', confidence: 'medium', description: 'Existing codebase detected but missing documentation', instructions: 'I\'ll analyze your existing codebase and create documentation to help continue development.', quickStart: '@project-orchestrator-agent "Analyze this existing codebase and continue development"', examples: [ 'Analyze this project and suggest next steps', 'Help me understand this codebase structure', 'Document this project and continue development' ] }; } // Active project (code + documentation) if (hasSourceCode && hasDocumentation) { const daysSinceModified = this.getDaysSinceModified(lastModified); const isRecent = daysSinceModified <= 7; return { mode: 'existing-project', confidence: 'high', description: `Active project with ${isRecent ? 'recent' : 'older'} development activity`, instructions: 'Ready to continue development on your existing project.', quickStart: '@project-orchestrator-agent "Show me project status and suggest next steps"', examples: [ 'What should I work on next?', 'Help me add a new feature', 'Review recent changes and plan improvements' ], metadata: { lastModified: lastModified, daysSinceModified: daysSinceModified, hasGitHistory: hasGitHistory } }; } // Configuration-only project (package.json but no code) if (!hasSourceCode && hasConfigFiles) { return { mode: 'configured-new', confidence: 'medium', description: 'Project initialized with configuration files but no source code yet', instructions: 'Configuration detected. Ready to start building your application.', quickStart: '@project-orchestrator-agent "I want to start building [describe what you want to build]"', examples: [ 'I want to start building the frontend', 'Help me create the initial project structure', 'Let\'s begin development based on the existing configuration' ] }; } // Fallback return { mode: 'unknown', confidence: 'low', description: 'Unable to determine project state clearly', instructions: 'Let me know what type of project this is so I can help you effectively.', quickStart: '@project-orchestrator-agent "This is a [new/existing] project for [description]"', examples: [ 'This is a new project for building a web application', 'This is an existing project that needs continued development' ] }; } catch (error) { console.warn('Project mode detection error:', error.message); return { mode: 'error', confidence: 'low', description: 'Error analyzing project state', instructions: 'Please specify your project type manually.', quickStart: '@project-orchestrator-agent "Help me get started with this project"', examples: [] }; } } // Helper methods for project mode detection async hasSourceFiles() { const sourceExtensions = ['.js', '.jsx', '.ts', '.tsx', '.py', '.java', '.go', '.rs', '.php', '.rb', '.swift', '.kt']; for (const ext of sourceExtensions) { if (await this.hasFiles(`*${ext}`)) { return true; } } return false; } async hasProjectDocumentation() { const docFiles = ['README.md', 'README.txt', 'REQUIREMENTS.md', 'docs/', 'documentation/']; for (const docFile of docFiles) { if (await this.fileExists(docFile)) { return true; } } return false; } async hasConfigurationFiles() { const configFiles = ['package.json', 'requirements.txt', 'pom.xml', 'Cargo.toml', 'go.mod', 'composer.json', 'Gemfile']; for (const configFile of configFiles) { if (await this.fileExists(configFile)) { return true; } } return false; } async hasGitHistory() { return await this.fileExists('.git'); } async getLastModificationTime() { try { const fs = require('fs').promises; const files = await fs.readdir(this.projectPath); let latestTime = 0; for (const file of files) { if (file.startsWith('.')) continue; try { const stats = await fs.stat(path.join(this.projectPath, file)); if (stats.mtime.getTime() > latestTime) { latestTime = stats.mtime.getTime(); } } catch (error) { // Skip files we can't access } } return latestTime > 0 ? new Date(latestTime) : null; } catch { return null; } } getDaysSinceModified(modifiedDate) { if (!modifiedDate) return Infinity; const now = new Date(); const diffTime = Math.abs(now - modifiedDate); return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); } async discoverAgents() { // Would scan for available agents return { available: ['project-orchestrator-agent', 'frontend-development-agent', 'backend-development-agent'], workflow: 'standard' }; } async extractQualityStandards() { // Would parse config files for quality standards return { coverage: { minimum: 80, critical: 90 }, complexity: { threshold: 10 } }; } async detectInfrastructure() { // Would detect cloud providers, CI/CD, etc. return { cloud: 'unknown', cicd: 'github-actions', deployment: 'vercel' }; } async analyzeWorkflow() { // Would analyze workflow patterns return { type: 'standard', handoffPattern: 'sequential' }; } calculateTechStackConfidence(techStack) { const score = techStack.languages.length + Object.keys(techStack.frameworks).length + techStack.tools.length; if (score >= 5) return 'high'; if (score >= 3) return 'medium'; return 'low'; } // Fallback methods getFallbackAnalysis() { return { techStack: this.getFallbackTechStack(), structure: { type: 'unknown', directories: {} }, variables: this.generateFallbackVariables() }; } getFallbackTechStack() { return { languages: ['JavaScript'], frameworks: { frontend: 'React', backend: 'Express' }, databases: ['PostgreSQL'], infrastructure: [], tools: ['Jest'], confidence: 'low' }; } generateFallbackVariables() { return { '{{LANGUAGE_PRIMARY}}': 'JavaScript', '{{FRONTEND_FRAMEWORK}}': 'React', '{{BACKEND_FRAMEWORK}}': 'Express', '{{TESTING_FRAMEWORK}}': 'Jest', '{{FILE_EXTENSION}}': '.jsx' }; } // Cache management cacheAnalysis(key, analysis) { if (this.config.enableCaching) { this.analysisCache.set(key, { analysis, timestamp: Date.now() }); // Cleanup old entries if (this.analysisCache.size > 10) { const oldestKey = this.analysisCache.keys().next().value; this.analysisCache.delete(oldestKey); } } } isCacheExpired(cached) { return (Date.now() - cached.timestamp) > this.config.cacheTimeout; } // Additional helper methods for specific detections detectDatabaseService(techStack) { if (techStack.tools.includes('Supabase')) return 'Supabase'; if (techStack.tools.includes('Firebase')) return 'Firebase'; if (techStack.databases.includes('PostgreSQL')) return 'Custom PostgreSQL'; return 'Unknown'; } detectDeploymentTarget(techStack) { if (techStack.frameworks.metaFramework === 'Next.js') return 'Vercel'; if (techStack.frameworks.backend === 'Django') return 'AWS'; return 'Custom'; } detectCiCdPlatform() { // Would check for .github/workflows, .gitlab-ci.yml, etc. return 'GitHub Actions'; } detectContainerPlatform() { // Would check for Dockerfile, docker-compose.yml, etc. return 'Docker'; } async getProjectMetadata() { const packageJson = await this.readPackageJson(); return { name: packageJson?.name || path.basename(this.projectPath), version: packageJson?.version || '1.0.0', description: packageJson?.description || '' }; } async detectFilePatterns() { // Simplified pattern detection const hasTypeScript = await this.fileExists('tsconfig.json'); const hasJSX = await this.findFiles(['*.jsx', '*.tsx']); return { primaryExtension: hasTypeScript ? '.tsx' : '.jsx', styleExtension: '.css', hasTypeScript, hasJSX: hasJSX.length > 0 }; } async detectReactInSrc() { const packageJson = await this.readPackageJson(); return packageJson?.dependencies?.react || packageJson?.devDependencies?.react; } findDjangoApps(rootDirs) { // Would scan for Django app directories return rootDirs.filter(dir => !['static', 'templates', 'media'].includes(dir)); } /** * Get analysis summary for display * @returns {Object} Summary information */ async getAnalysisSummary() { try { const analysis = await this.analyzeProject(); return { projectName: analysis.metadata.name, primaryLanguage: analysis.techStack.languages[0], stack: analysis.stackProfile?.name || 'Custom Stack', confidence: analysis.techStack.confidence, variableCount: Object.keys(analysis.variables).length }; } catch (error) { return { error: error.message, status: 'analysis-failed' }; } } } module.exports = { ProjectContextAnalyzer };