UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

884 lines 188 kB
import { promises as fs } from 'fs'; import path from 'path'; import { ContextCuratorLLMService } from './llm-integration.js'; import { ContextCuratorConfigLoader } from './config-loader.js'; import { OutputFormatterService } from './output-formatter.js'; import { jobManager, JobStatus } from '../../../services/job-manager/index.js'; import { executeCodeMapGeneration } from '../../code-map-generator/index.js'; import { contextPackageSchema, PRIORITY_THRESHOLDS } from '../types/context-curator.js'; import { ContextCuratorError } from '../utils/error-handling.js'; import { TokenEstimator } from '../utils/token-estimator.js'; import { languageConfigurations } from '../../code-map-generator/parser.js'; import logger from '../../../logger.js'; function getPackageFilesIncluded(pkg) { return pkg.metadata.filesIncluded; } function getPackageTotalTokenEstimate(pkg) { return pkg.metadata.totalTokenEstimate; } function getMaxFilesFromContext(context) { if (context && typeof context === 'object' && 'maxFiles' in context) { const maxFiles = context.maxFiles; return typeof maxFiles === 'number' ? maxFiles : undefined; } return undefined; } export var WorkflowPhase; (function (WorkflowPhase) { WorkflowPhase["INITIALIZATION"] = "initialization"; WorkflowPhase["INTENT_ANALYSIS"] = "intent_analysis"; WorkflowPhase["PROMPT_REFINEMENT"] = "prompt_refinement"; WorkflowPhase["FILE_DISCOVERY"] = "file_discovery"; WorkflowPhase["RELEVANCE_SCORING"] = "relevance_scoring"; WorkflowPhase["META_PROMPT_GENERATION"] = "meta_prompt_generation"; WorkflowPhase["PACKAGE_ASSEMBLY"] = "package_assembly"; WorkflowPhase["OUTPUT_GENERATION"] = "output_generation"; WorkflowPhase["COMPLETED"] = "completed"; })(WorkflowPhase || (WorkflowPhase = {})); export class ContextCuratorService { static instance = null; llmService; configLoader; outputFormatter; constructor() { this.llmService = ContextCuratorLLMService.getInstance(); this.configLoader = ContextCuratorConfigLoader.getInstance(); this.outputFormatter = OutputFormatterService.getInstance(); } static getInstance() { if (!ContextCuratorService.instance) { ContextCuratorService.instance = new ContextCuratorService(); } return ContextCuratorService.instance; } async executeWorkflow(jobId, input, config) { const context = { jobId, input, config, currentPhase: WorkflowPhase.INITIALIZATION, startTime: Date.now(), totalPhases: 8, completedPhases: 0, errors: [], warnings: [] }; logger.info({ jobId, userPrompt: input.userPrompt.substring(0, 100) + '...', projectPath: input.projectPath, taskType: input.taskType }, 'Starting Context Curator workflow execution'); try { jobManager.updateJobStatus(jobId, JobStatus.RUNNING, 'Context Curator workflow execution started', 0, { currentStage: 'initialization', diagnostics: [`Starting 8-phase workflow for ${input.taskType} task`], metadata: { taskType: input.taskType, projectPath: input.projectPath, totalPhases: 8 } }); await this.executeInitialization(context); await this.executeIntentAnalysis(context); await this.executePromptRefinement(context); await this.executeFileDiscovery(context); await this.executeRelevanceScoring(context); await this.executeMetaPromptGeneration(context); await this.executePackageAssembly(context); await this.executeOutputGeneration(context); context.currentPhase = WorkflowPhase.COMPLETED; const executionTime = Date.now() - context.startTime; logger.info({ jobId, executionTime, totalFiles: context.contextPackage?.files.length || 0, totalTokens: context.contextPackage?.statistics.totalTokens || 0 }, 'Context Curator workflow completed successfully'); jobManager.updateJobStatus(jobId, JobStatus.COMPLETED, 'Context Curator workflow completed successfully', 100, { currentStage: 'workflow_complete', diagnostics: [ `All 8 phases completed successfully`, `Total execution time: ${executionTime}ms`, `Total files processed: ${context.contextPackage?.files.length || 0}`, `Total tokens generated: ${context.contextPackage?.statistics.totalTokens || 0}`, `Task type: ${input.taskType}`, `Project: ${input.projectPath}` ], subProgress: 100, metadata: { executionTimeMs: executionTime, totalFiles: context.contextPackage?.files.length || 0, totalTokens: context.contextPackage?.statistics.totalTokens || 0, taskType: input.taskType, projectPath: input.projectPath, allPhasesCompleted: true, phase: 'complete' } }); return context.contextPackage; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; logger.error({ jobId, error: errorMessage, phase: context.currentPhase }, 'Context Curator workflow failed'); jobManager.updateJobStatus(jobId, JobStatus.FAILED, `Workflow failed in ${context.currentPhase}: ${errorMessage}`, Math.round((context.completedPhases / context.totalPhases) * 100)); throw new ContextCuratorError(`Workflow failed in ${context.currentPhase}: ${errorMessage}`); } } async executeInitialization(context) { context.currentPhase = WorkflowPhase.INITIALIZATION; logger.info({ jobId: context.jobId }, 'Executing initialization phase'); try { const configResult = await this.configLoader.loadConfig(); if (!configResult.success) { context.warnings.push(`Configuration warning: ${configResult.error}`); } context.contextCuratorConfig = this.configLoader.getConfig() || undefined; const allowedReadDirectory = process.env.CODE_MAP_ALLOWED_DIR || process.env.VIBE_TASK_MANAGER_READ_DIR || context.input.projectPath || process.cwd(); const allowedWriteDirectory = process.env.VIBE_CODER_OUTPUT_DIR || path.join(process.cwd(), 'VibeCoderOutput'); context.securityConfig = { allowedReadDirectory, allowedWriteDirectory, securityMode: process.env.VIBE_TASK_MANAGER_SECURITY_MODE || 'strict', allowedDirectories: [allowedReadDirectory, allowedWriteDirectory], performanceThresholdMs: 50, enablePermissionChecking: true, enableBlacklist: true, enableExtensionFiltering: true, maxPathLength: 4096, allowedDir: allowedReadDirectory, outputDir: allowedWriteDirectory, serviceBoundaries: { vibeTaskManager: { readDir: allowedReadDirectory, writeDir: allowedWriteDirectory }, codeMapGenerator: { allowedDir: allowedReadDirectory, outputDir: allowedWriteDirectory }, contextCurator: { readDir: allowedReadDirectory, outputDir: allowedWriteDirectory } } }; logger.info({ allowedReadDirectory, allowedWriteDirectory, securityMode: context.securityConfig?.securityMode || 'strict', configSource: process.env.CODE_MAP_ALLOWED_DIR ? 'CODE_MAP_ALLOWED_DIR' : process.env.VIBE_TASK_MANAGER_READ_DIR ? 'VIBE_TASK_MANAGER_READ_DIR' : context.input.projectPath ? 'input.projectPath' : 'process.cwd()' }, 'Context Curator security configuration initialized'); logger.debug({ jobId: context.jobId, projectPath: context.input.projectPath, useCache: context.input.useCodeMapCache, maxAgeMinutes: context.input.codeMapCacheMaxAgeMinutes }, 'Checking for cached codemap'); let codemapContent = ''; let codemapPath = ''; let fromCache = false; if (context.input.useCodeMapCache) { try { const { CodemapCacheManager } = await import('../utils/codemap-cache.js'); const cachedResult = await CodemapCacheManager.findRecentCodemap(context.input.codeMapCacheMaxAgeMinutes, context.securityConfig?.allowedWriteDirectory); if (cachedResult) { codemapContent = cachedResult.content; codemapPath = cachedResult.path; fromCache = true; logger.info({ jobId: context.jobId, codemapPath, ageMinutes: Math.round((Date.now() - cachedResult.timestamp.getTime()) / (60 * 1000)), contentLength: codemapContent.length }, 'Using cached codemap - skipping generation'); } else { logger.debug({ jobId: context.jobId }, 'No recent cached codemap found, generating fresh'); } } catch (cacheError) { logger.warn({ jobId: context.jobId, error: cacheError instanceof Error ? cacheError.message : 'Unknown cache error' }, 'Cache check failed, falling back to fresh generation'); } } else { logger.debug({ jobId: context.jobId }, 'Codemap cache disabled, generating fresh'); } if (!fromCache) { logger.debug({ jobId: context.jobId, projectPath: context.input.projectPath }, 'Generating fresh codemap'); const maxContentLength = context.contextCuratorConfig?.contentDensity?.maxContentLength ?? 0; const enhancedConfig = { ...context.config, config: { ...context.config.config, 'map-codebase': { allowedMappingDirectory: context.securityConfig?.allowedReadDirectory, outputDirectory: context.securityConfig?.allowedWriteDirectory } } }; const codemapResult = await executeCodeMapGeneration({ allowedMappingDirectory: context.securityConfig?.allowedReadDirectory, maxOptimizationLevel: 'aggressive', contentDensity: { maxContentLength, preserveComments: context.contextCuratorConfig?.contentDensity?.preserveComments ?? true, preserveTypes: context.contextCuratorConfig?.contentDensity?.preserveTypes ?? true, optimizationThreshold: context.contextCuratorConfig?.contentDensity?.optimizationThreshold ?? 1000 } }, enhancedConfig, { sessionId: `context-curator-${context.jobId}`, transportType: 'stdio' }, context.jobId); if (codemapResult.isError) { const errorMessage = codemapResult.content?.[0]?.text || 'Unknown error'; throw new Error(`Codemap generation failed: ${errorMessage}`); } try { const resultText = codemapResult.content[0]?.text; logger.debug({ resultTextType: typeof resultText, resultTextLength: typeof resultText === 'string' ? resultText.length : 0, resultTextPreview: typeof resultText === 'string' ? resultText.substring(0, 200) : 'NOT_STRING' }, 'Analyzing codemap result text'); if (typeof resultText === 'string') { const outputPathMatch = resultText.match(/\*\*Output saved to:\*\*\s*(.+\.md)/); if (outputPathMatch) { codemapPath = outputPathMatch[1].trim(); logger.debug({ extractedPath: codemapPath, matchedText: outputPathMatch[0] }, 'Extracted codemap path from summary text'); const fs = await import('fs/promises'); const fsExtra = await import('fs-extra'); if (await fsExtra.pathExists(codemapPath)) { codemapContent = await fs.readFile(codemapPath, 'utf-8'); logger.info({ codemapPath, codemapSize: codemapContent.length }, 'Codemap file read successfully'); } else { logger.warn({ codemapPath }, 'Codemap file does not exist'); codemapContent = resultText; } } else { logger.warn({ resultText: resultText.substring(0, 500) }, 'No codemap output path found in summary text'); codemapContent = resultText; } } else { logger.warn('Codemap result text is not a string'); throw new Error('Invalid codemap result format'); } } catch (parseError) { logger.warn({ parseError: parseError instanceof Error ? parseError.message : 'Unknown error', parseErrorStack: parseError instanceof Error ? parseError.stack : undefined }, 'Failed to extract codemap path from summary, using raw content'); if (codemapResult.content && codemapResult.content.length > 0) { const firstContent = codemapResult.content[0]; if (firstContent.type === 'text' && typeof firstContent.text === 'string') { codemapContent = firstContent.text; } else { throw new Error('Invalid codemap content format'); } } else { throw new Error('No codemap content generated'); } } } context.codemapContent = codemapContent; context.codemapPath = codemapPath; logger.info({ codemapContentLength: codemapContent.length, codemapContentPreview: codemapContent.substring(0, 500), codemapContentType: typeof codemapContent, fromCache }, 'About to extract file contents from codemap'); context.fileContents = await this.extractFileContentsWithOptimization(codemapContent); context.completedPhases++; const progress = Math.round((context.completedPhases / context.totalPhases) * 100); const statusMessage = fromCache ? 'Initialization completed - using cached codemap' : 'Initialization completed - codemap generated'; jobManager.updateJobStatus(context.jobId, JobStatus.RUNNING, statusMessage, progress, { currentStage: 'initialization_complete', diagnostics: [ fromCache ? `Cached codemap loaded with ${codemapContent.length} characters` : `Codemap generated with ${codemapContent.length} characters`, `File contents extracted for ${context.fileContents?.size || 0} files`, fromCache ? 'Cache hit - performance optimized' : 'Fresh generation completed' ], subProgress: 100, metadata: { codemapSize: codemapContent.length, fileContentsCount: context.fileContents?.size || 0, phase: 'initialization', fromCache, cacheEnabled: context.input.useCodeMapCache, maxCacheAgeMinutes: context.input.codeMapCacheMaxAgeMinutes } }); logger.info({ jobId: context.jobId, codemapLength: codemapContent.length, fileContentsCount: context.fileContents?.size || 0, fromCache, cacheEnabled: context.input.useCodeMapCache }, 'Initialization phase completed'); } catch (error) { throw new Error(`Initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async executeIntentAnalysis(context) { context.currentPhase = WorkflowPhase.INTENT_ANALYSIS; logger.info({ jobId: context.jobId }, 'Executing intent analysis phase'); try { const patternAnalysis = this.extractArchitecturalPatterns(context.codemapContent); const projectAnalysis = this.detectProjectType(context.codemapContent); const languageAnalysis = await this.detectPrimaryLanguages(context.codemapContent); const additionalContext = { projectType: projectAnalysis.projectType, projectAnalysis, languageAnalysis, existingPatterns: patternAnalysis.patterns, patternConfidence: patternAnalysis.confidence, patternEvidence: patternAnalysis.evidence, technicalConstraints: [] }; const baseIntentAnalysis = await this.llmService.performIntentAnalysis(context.input.userPrompt, context.codemapContent, context.config, additionalContext); context.intentAnalysis = { ...baseIntentAnalysis, projectAnalysis, languageAnalysis, patternAnalysis: { patterns: patternAnalysis.patterns, confidence: patternAnalysis.confidence, evidence: patternAnalysis.evidence } }; context.completedPhases++; const progress = Math.round((context.completedPhases / context.totalPhases) * 100); jobManager.updateJobStatus(context.jobId, JobStatus.RUNNING, `Enhanced intent analysis completed - detected ${context.intentAnalysis.taskType} task`, progress, { currentStage: 'intent_analysis_complete', diagnostics: [ `Task type detected: ${context.intentAnalysis.taskType}`, `Project type: ${context.intentAnalysis.projectAnalysis?.projectType || 'unknown'}`, `Primary language: ${context.intentAnalysis.languageAnalysis?.primaryLanguage || 'unknown'}`, `Patterns detected: ${context.intentAnalysis.patternAnalysis?.patterns.length || 0}` ], subProgress: 100, metadata: { taskType: context.intentAnalysis.taskType, projectType: context.intentAnalysis.projectAnalysis?.projectType, primaryLanguage: context.intentAnalysis.languageAnalysis?.primaryLanguage, patternsCount: context.intentAnalysis.patternAnalysis?.patterns.length || 0, phase: 'intent_analysis' } }); logger.info({ jobId: context.jobId, taskType: context.intentAnalysis.taskType, confidence: context.intentAnalysis.confidence, enhancedAnalysis: { projectType: projectAnalysis.projectType, projectConfidence: projectAnalysis.confidence, secondaryTypes: projectAnalysis.secondaryTypes.length, primaryLanguage: languageAnalysis.primaryLanguage, detectedLanguages: languageAnalysis.languages.length, frameworkStack: projectAnalysis.frameworkStack.length, architecturalPatterns: patternAnalysis.patterns.length, averagePatternConfidence: patternAnalysis.patterns.length > 0 ? Object.values(patternAnalysis.confidence).reduce((sum, conf) => sum + conf, 0) / patternAnalysis.patterns.length : 0 } }, 'Enhanced intent analysis phase completed with comprehensive project understanding'); } catch (error) { throw new Error(`Intent analysis failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async executePromptRefinement(context) { context.currentPhase = WorkflowPhase.PROMPT_REFINEMENT; logger.info({ jobId: context.jobId }, 'Executing prompt refinement phase'); try { const patternAnalysis = this.extractArchitecturalPatterns(context.codemapContent); const additionalContext = { projectAnalysis: context.intentAnalysis?.projectAnalysis, languageAnalysis: context.intentAnalysis?.languageAnalysis, existingPatterns: context.intentAnalysis?.patternAnalysis?.patterns || patternAnalysis.patterns, patternConfidence: context.intentAnalysis?.patternAnalysis?.confidence || patternAnalysis.confidence, patternEvidence: context.intentAnalysis?.patternAnalysis?.evidence || patternAnalysis.evidence, technicalConstraints: this.deriveConstraintsFromProject(context.intentAnalysis?.projectAnalysis), qualityRequirements: this.deriveQualityRequirements(context.intentAnalysis?.languageAnalysis), timelineConstraints: undefined, teamExpertise: this.inferTeamExpertise(context.intentAnalysis?.projectAnalysis) }; context.promptRefinement = await this.llmService.performPromptRefinement(context.input.userPrompt, context.intentAnalysis, context.codemapContent, context.config, additionalContext); context.completedPhases++; const progress = Math.round((context.completedPhases / context.totalPhases) * 100); jobManager.updateJobStatus(context.jobId, JobStatus.RUNNING, 'Enhanced prompt refinement completed', progress); logger.info({ jobId: context.jobId, originalLength: context.input.userPrompt.length, refinedLength: context.promptRefinement.refinedPrompt.length, projectType: context.intentAnalysis?.projectAnalysis?.projectType, primaryLanguage: context.intentAnalysis?.languageAnalysis?.primaryLanguage }, 'Enhanced prompt refinement phase completed with project context'); } catch (error) { throw new Error(`Prompt refinement failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } } detectProjectType(codemapContent) { try { return this.enhancedProjectTypeDetection(codemapContent); } catch (error) { logger.warn({ err: error }, 'Enhanced project type detection failed, falling back to legacy method'); return this.legacyProjectTypeDetection(codemapContent); } } enhancedProjectTypeDetection(codemapContent) { const languageProfile = this.buildLanguageProfileFromCodemap(codemapContent); const packageManagers = this.detectPackageManagersFromCodemap(codemapContent); const structureAnalysis = this.analyzeUniversalProjectStructure(codemapContent); const technologyProfile = this.performSemanticTechnologyInference(codemapContent); const projectTypeScores = this.calculateMultiDimensionalScores(languageProfile, packageManagers, structureAnalysis, technologyProfile, codemapContent); const bestMatch = this.selectAndValidateProjectType(projectTypeScores, languageProfile, packageManagers, structureAnalysis); return this.buildProjectTypeAnalysisResult(bestMatch, projectTypeScores, languageProfile, packageManagers, structureAnalysis, technologyProfile, codemapContent); } legacyProjectTypeDetection(codemapContent) { const content = codemapContent.toLowerCase(); const projectTypes = []; this.analyzeWebFrontendProject(content, projectTypes); this.analyzeBackendProject(content, projectTypes); this.analyzeMobileProject(content, projectTypes); this.analyzeDesktopProject(content, projectTypes); this.analyzeDataMLProject(content, projectTypes); this.analyzeDevOpsProject(content, projectTypes); this.analyzeGameProject(content, projectTypes); this.analyzeBlockchainProject(content, projectTypes); projectTypes.sort((a, b) => b.confidence - a.confidence); const primaryType = projectTypes[0] || { type: 'General Application', confidence: 0.5, evidence: ['Unknown project structure'] }; const secondaryTypes = projectTypes.slice(1, 4).map(p => p.type); const frameworkStack = this.detectFrameworkStack(content); const architectureStyle = this.detectArchitectureStyle(content); const developmentEnvironment = this.detectDevelopmentEnvironment(content); return { projectType: primaryType.type, secondaryTypes, confidence: primaryType.confidence, evidence: primaryType.evidence, frameworkStack, architectureStyle, developmentEnvironment }; } buildLanguageProfileFromCodemap(codemapContent) { const fileExtensions = this.extractFileExtensionsFromCodemap(codemapContent); const languageDistribution = new Map(); let totalFiles = 0; for (const [extension, count] of fileExtensions) { const config = languageConfigurations[extension]; if (config) { const languageName = config.name; languageDistribution.set(languageName, (languageDistribution.get(languageName) || 0) + count); totalFiles += count; } } const sortedLanguages = Array.from(languageDistribution.entries()) .map(([lang, count]) => ({ language: lang, count, percentage: count / totalFiles })) .sort((a, b) => b.count - a.count); const primary = sortedLanguages[0]?.language || 'Unknown'; const secondary = sortedLanguages.slice(1, 4).map(l => l.language); const primaryPercentage = sortedLanguages[0]?.percentage || 0; const confidence = Math.min(primaryPercentage + 0.2, 1.0); return { primary, secondary, distribution: languageDistribution, totalFiles, confidence }; } extractFileExtensionsFromCodemap(codemapContent) { const extensionCounts = new Map(); const filePatterns = [ /^[\s]*[├│└─\-*•]\s*(.+\.[a-zA-Z0-9]+)/gm, /^[\s]*([a-zA-Z0-9_\-/\\]+\.[a-zA-Z0-9]+)[\s]*$/gm, /^#+\s+(.+\.[a-zA-Z0-9]+)/gm, /([a-zA-Z0-9_-]+\.[a-zA-Z0-9]+)/g ]; for (const pattern of filePatterns) { let match; while ((match = pattern.exec(codemapContent)) !== null) { const filePath = match[1]; const extension = this.extractExtension(filePath); if (extension && this.isValidFileExtension(extension)) { extensionCounts.set(extension, (extensionCounts.get(extension) || 0) + 1); } } } const explicitFilePattern = /\b([a-zA-Z0-9_-]+\.(ts|tsx|js|jsx|py|java|kt|swift|dart|rs|go|rb|php|cs|cpp|c|h|vue|html|css|scss|sass|less|json|yaml|yml|toml|xml|md|txt|sql|sh|bat|ps1|dockerfile|makefile))\b/gi; let explicitMatch; while ((explicitMatch = explicitFilePattern.exec(codemapContent)) !== null) { const fileName = explicitMatch[1]; const extension = this.extractExtension(fileName); if (extension) { extensionCounts.set(extension, (extensionCounts.get(extension) || 0) + 1); } } return extensionCounts; } isValidFileExtension(extension) { const validExtensions = [ '.ts', '.tsx', '.js', '.jsx', '.py', '.java', '.kt', '.swift', '.dart', '.rs', '.go', '.rb', '.php', '.cs', '.cpp', '.c', '.h', '.hpp', '.cc', '.vue', '.html', '.css', '.scss', '.sass', '.less', '.json', '.yaml', '.yml', '.toml', '.xml', '.md', '.txt', '.sql', '.sh', '.bat', '.ps1', '.dockerfile', '.makefile', '.gradle', '.maven', '.sbt', '.clj', '.cljs', '.elm', '.ex', '.exs', '.erl', '.hrl', '.hs', '.lhs', '.ml', '.mli', '.fs', '.fsx', '.fsi', '.scala', '.groovy', '.lua', '.r', '.jl', '.nim', '.zig', '.odin', '.v', '.cr', '.d', '.pas', '.pp', '.ada', '.adb', '.ads' ]; return validExtensions.includes(extension.toLowerCase()); } extractExtension(filePath) { const match = filePath.match(/\.([a-zA-Z0-9]+)$/); return match ? `.${match[1].toLowerCase()}` : null; } detectPackageManagersFromCodemap(codemapContent) { const packageManagerPatterns = new Map([ ['package.json', { manager: 'npm/yarn/pnpm', ecosystem: 'JavaScript', languages: ['JavaScript', 'TypeScript'] }], ['yarn.lock', { manager: 'yarn', ecosystem: 'JavaScript', languages: ['JavaScript', 'TypeScript'] }], ['pnpm-lock.yaml', { manager: 'pnpm', ecosystem: 'JavaScript', languages: ['JavaScript', 'TypeScript'] }], ['requirements.txt', { manager: 'pip', ecosystem: 'Python', languages: ['Python'] }], ['pyproject.toml', { manager: 'poetry/pip', ecosystem: 'Python', languages: ['Python'] }], ['Pipfile', { manager: 'pipenv', ecosystem: 'Python', languages: ['Python'] }], ['conda.yaml', { manager: 'conda', ecosystem: 'Python', languages: ['Python'] }], ['environment.yml', { manager: 'conda', ecosystem: 'Python', languages: ['Python'] }], ['pom.xml', { manager: 'maven', ecosystem: 'Java', languages: ['Java', 'Scala', 'Kotlin'] }], ['build.gradle', { manager: 'gradle', ecosystem: 'Java', languages: ['Java', 'Scala', 'Kotlin'] }], ['build.gradle.kts', { manager: 'gradle', ecosystem: 'Kotlin', languages: ['Kotlin', 'Java'] }], ['build.sbt', { manager: 'sbt', ecosystem: 'Scala', languages: ['Scala', 'Java'] }], ['.csproj', { manager: 'nuget', ecosystem: 'C#', languages: ['C#'] }], ['.sln', { manager: 'nuget', ecosystem: 'C#', languages: ['C#'] }], ['packages.config', { manager: 'nuget', ecosystem: 'C#', languages: ['C#'] }], ['go.mod', { manager: 'go modules', ecosystem: 'Go', languages: ['Go'] }], ['go.sum', { manager: 'go modules', ecosystem: 'Go', languages: ['Go'] }], ['Cargo.toml', { manager: 'cargo', ecosystem: 'Rust', languages: ['Rust'] }], ['Cargo.lock', { manager: 'cargo', ecosystem: 'Rust', languages: ['Rust'] }], ['Gemfile', { manager: 'bundler', ecosystem: 'Ruby', languages: ['Ruby'] }], ['Gemfile.lock', { manager: 'bundler', ecosystem: 'Ruby', languages: ['Ruby'] }], ['.gemspec', { manager: 'gem', ecosystem: 'Ruby', languages: ['Ruby'] }], ['composer.json', { manager: 'composer', ecosystem: 'PHP', languages: ['PHP'] }], ['composer.lock', { manager: 'composer', ecosystem: 'PHP', languages: ['PHP'] }], ['Package.swift', { manager: 'swift package manager', ecosystem: 'Swift', languages: ['Swift'] }], ['Podfile', { manager: 'cocoapods', ecosystem: 'iOS', languages: ['Swift', 'Objective-C'] }], ['pubspec.yaml', { manager: 'pub', ecosystem: 'Dart', languages: ['Dart'] }], ['pubspec.lock', { manager: 'pub', ecosystem: 'Dart', languages: ['Dart'] }], ['mix.exs', { manager: 'mix', ecosystem: 'Elixir', languages: ['Elixir'] }], ['mix.lock', { manager: 'mix', ecosystem: 'Elixir', languages: ['Elixir'] }], ['DESCRIPTION', { manager: 'R packages', ecosystem: 'R', languages: ['R'] }], ['renv.lock', { manager: 'renv', ecosystem: 'R', languages: ['R'] }], ['rockspec', { manager: 'luarocks', ecosystem: 'Lua', languages: ['Lua'] }], ['dune-project', { manager: 'dune', ecosystem: 'OCaml', languages: ['OCaml'] }], ['opam', { manager: 'opam', ecosystem: 'OCaml', languages: ['OCaml'] }], ['elm.json', { manager: 'elm', ecosystem: 'Elm', languages: ['Elm'] }], ['build.zig', { manager: 'zig build', ecosystem: 'Zig', languages: ['Zig'] }] ]); const detectedManagers = []; for (const [pattern, info] of packageManagerPatterns) { if (codemapContent.includes(pattern)) { detectedManagers.push({ pattern, manager: info.manager, ecosystem: info.ecosystem, supportedLanguages: info.languages, confidence: this.calculatePackageManagerConfidence(pattern, codemapContent) }); } } return detectedManagers; } calculatePackageManagerConfidence(pattern, codemapContent) { let confidence = 0.7; const commonPatterns = ['package.json', 'requirements.txt', 'pom.xml', 'Cargo.toml', 'go.mod']; if (commonPatterns.includes(pattern)) { confidence += 0.2; } const relatedFiles = { 'package.json': ['yarn.lock', 'package-lock.json', 'node_modules'], 'requirements.txt': ['setup.py', 'pyproject.toml', '__pycache__'], 'pom.xml': ['target/', 'src/main/java'], 'Cargo.toml': ['Cargo.lock', 'src/main.rs', 'target/'], 'go.mod': ['go.sum', 'main.go', 'cmd/'] }; const related = relatedFiles[pattern]; if (related) { const foundRelated = related.filter(file => codemapContent.includes(file)); confidence += foundRelated.length * 0.05; } return Math.min(confidence, 1.0); } analyzeUniversalProjectStructure(codemapContent) { const universalPatterns = [ { pattern: /src\/components/i, types: ['React App', 'Vue App', 'Angular App'], weight: 0.9 }, { pattern: /public\/.*\.(html|css|js)/i, types: ['Web Application'], weight: 0.8 }, { pattern: /dist\/|build\/|out\//i, types: ['Build-based Project'], weight: 0.7 }, { pattern: /pages\/.*\.(js|ts|jsx|tsx)/i, types: ['Next.js App', 'Nuxt.js App'], weight: 0.9 }, { pattern: /routes\/|controllers\/|handlers\//i, types: ['Web API', 'REST API'], weight: 0.9 }, { pattern: /models\/|entities\/|schemas\//i, types: ['Database-driven App'], weight: 0.8 }, { pattern: /middleware\/|interceptors\//i, types: ['Web Framework App'], weight: 0.8 }, { pattern: /api\/|endpoints\//i, types: ['API Service'], weight: 0.8 }, { pattern: /android\/.*\.(java|kt)/i, types: ['Android App'], weight: 0.95 }, { pattern: /ios\/.*\.(swift|m)/i, types: ['iOS App'], weight: 0.95 }, { pattern: /lib\/.*\.dart/i, types: ['Flutter App'], weight: 0.9 }, { pattern: /src\/.*\.(swift|kt|java)/i, types: ['Mobile App'], weight: 0.7 }, { pattern: /src-tauri\//i, types: ['Tauri Desktop App'], weight: 0.95 }, { pattern: /electron\/|main\.(js|ts)/i, types: ['Electron App'], weight: 0.9 }, { pattern: /\.desktop|\.app\//i, types: ['Desktop Application'], weight: 0.8 }, { pattern: /notebooks\/.*\.ipynb/i, types: ['Jupyter Project', 'Data Science'], weight: 0.9 }, { pattern: /models\/.*\.(pkl|h5|pt|onnx)/i, types: ['ML Project'], weight: 0.9 }, { pattern: /data\/.*\.(csv|json|parquet|h5)/i, types: ['Data Analysis'], weight: 0.8 }, { pattern: /experiments\/|research\//i, types: ['Research Project'], weight: 0.7 }, { pattern: /docker\/|Dockerfile/i, types: ['Containerized App'], weight: 0.8 }, { pattern: /k8s\/|kubernetes\//i, types: ['Kubernetes App'], weight: 0.9 }, { pattern: /terraform\/.*\.tf/i, types: ['Infrastructure as Code'], weight: 0.9 }, { pattern: /ansible\/.*\.yml/i, types: ['Configuration Management'], weight: 0.8 }, { pattern: /\.github\/workflows\//i, types: ['CI/CD Project'], weight: 0.7 }, { pattern: /assets\/.*\.(png|jpg|wav|ogg)/i, types: ['Game Project'], weight: 0.7 }, { pattern: /scenes\/|levels\//i, types: ['Game Project'], weight: 0.8 }, { pattern: /unity\/|unreal\//i, types: ['Game Engine Project'], weight: 0.9 }, { pattern: /contracts\/.*\.sol/i, types: ['Smart Contract Project'], weight: 0.95 }, { pattern: /migrations\/|deploy\//i, types: ['Blockchain Project'], weight: 0.8 }, { pattern: /lib\/|library\//i, types: ['Library Project'], weight: 0.7 }, { pattern: /examples\/|demo\//i, types: ['Example/Demo Project'], weight: 0.6 }, { pattern: /docs\/|documentation\//i, types: ['Documentation Project'], weight: 0.6 }, { pattern: /tests?\/|spec\/|__tests__\//i, types: ['Test Suite'], weight: 0.5 }, { pattern: /e2e\/|integration\//i, types: ['Testing Framework'], weight: 0.6 }, { pattern: /services\/.*\//i, types: ['Microservices'], weight: 0.8 }, { pattern: /packages\/.*\//i, types: ['Monorepo'], weight: 0.8 } ]; const matchedPatterns = universalPatterns .filter(p => p.pattern.test(codemapContent)) .map(p => ({ pattern: p.pattern.source, types: p.types, weight: p.weight, evidence: this.extractPatternEvidence(codemapContent, p.pattern) })); return { patterns: matchedPatterns, projectTypes: this.aggregateProjectTypes(matchedPatterns), confidence: this.calculateStructureConfidence(matchedPatterns) }; } extractPatternEvidence(codemapContent, pattern) { const matches = codemapContent.match(pattern); return matches ? matches.slice(0, 5) : []; } aggregateProjectTypes(patterns) { const typeScores = new Map(); for (const pattern of patterns) { for (const type of pattern.types) { typeScores.set(type, (typeScores.get(type) || 0) + pattern.weight); } } return Array.from(typeScores.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([type]) => type); } calculateStructureConfidence(patterns) { if (patterns.length === 0) return 0.3; const totalWeight = patterns.reduce((sum, p) => sum + p.weight, 0); const averageWeight = totalWeight / patterns.length; return Math.min(averageWeight + (patterns.length * 0.1), 1.0); } extractArchitecturalPatterns(codemapContent) { const content = codemapContent.toLowerCase(); const detectedPatterns = []; const confidence = {}; const evidence = {}; this.detectLayeredArchitecture(content, detectedPatterns, confidence, evidence); this.detectMicroservicesArchitecture(content, detectedPatterns, confidence, evidence); this.detectEventDrivenArchitecture(content, detectedPatterns, confidence, evidence); this.detectCQRSPattern(content, detectedPatterns, confidence, evidence); this.detectHexagonalArchitecture(content, detectedPatterns, confidence, evidence); this.detectCleanArchitecture(content, detectedPatterns, confidence, evidence); this.detectMVCPattern(content, detectedPatterns, confidence, evidence); this.detectMVVMPattern(content, detectedPatterns, confidence, evidence); this.detectMicrokernelArchitecture(content, detectedPatterns, confidence, evidence); this.detectSpaceBasedArchitecture(content, detectedPatterns, confidence, evidence); this.detectSingletonPattern(content, detectedPatterns, confidence, evidence); this.detectFactoryPattern(content, detectedPatterns, confidence, evidence); this.detectObserverPattern(content, detectedPatterns, confidence, evidence); this.detectRepositoryPattern(content, detectedPatterns, confidence, evidence); this.detectStrategyPattern(content, detectedPatterns, confidence, evidence); this.detectAdapterPattern(content, detectedPatterns, confidence, evidence); this.detectDecoratorPattern(content, detectedPatterns, confidence, evidence); this.detectCommandPattern(content, detectedPatterns, confidence, evidence); this.detectBuilderPattern(content, detectedPatterns, confidence, evidence); this.detectFacadePattern(content, detectedPatterns, confidence, evidence); return { patterns: detectedPatterns, confidence, evidence }; } detectLayeredArchitecture(content, patterns, confidence, evidence) { const indicators = [ 'layers/', 'layer', 'presentation', 'business', 'data', 'dal', 'bll', 'ui', 'controller', 'service', 'repository', 'model', 'view', 'dto', 'entity' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 3) { patterns.push('Layered Architecture'); confidence['Layered Architecture'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Layered Architecture'] = foundIndicators; } } detectMicroservicesArchitecture(content, patterns, confidence, evidence) { const indicators = [ 'microservice', 'microservices', 'service-', 'api-gateway', 'docker', 'kubernetes', 'k8s', 'helm', 'istio', 'consul', 'eureka', 'circuit-breaker', 'load-balancer' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 2) { patterns.push('Microservices Architecture'); confidence['Microservices Architecture'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Microservices Architecture'] = foundIndicators; } } detectEventDrivenArchitecture(content, patterns, confidence, evidence) { const indicators = [ 'event', 'events', 'eventbus', 'event-driven', 'publish', 'subscribe', 'pubsub', 'kafka', 'rabbitmq', 'redis', 'message', 'queue', 'broker' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 2) { patterns.push('Event-Driven Architecture'); confidence['Event-Driven Architecture'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Event-Driven Architecture'] = foundIndicators; } } detectCQRSPattern(content, patterns, confidence, evidence) { const indicators = [ 'cqrs', 'command', 'query', 'commandhandler', 'queryhandler', 'readmodel', 'writemodel', 'eventstore', 'projection' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 2) { patterns.push('CQRS'); confidence['CQRS'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['CQRS'] = foundIndicators; } } detectHexagonalArchitecture(content, patterns, confidence, evidence) { const indicators = [ 'hexagonal', 'ports', 'adapters', 'port', 'adapter', 'domain', 'infrastructure', 'application', 'primary', 'secondary' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 3) { patterns.push('Hexagonal Architecture'); confidence['Hexagonal Architecture'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Hexagonal Architecture'] = foundIndicators; } } detectCleanArchitecture(content, patterns, confidence, evidence) { const indicators = [ 'clean', 'entities', 'usecases', 'use-cases', 'gateways', 'presenters', 'frameworks', 'drivers', 'interface-adapters', 'enterprise' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 3) { patterns.push('Clean Architecture'); confidence['Clean Architecture'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Clean Architecture'] = foundIndicators; } } detectMVCPattern(content, patterns, confidence, evidence) { const indicators = [ 'mvc', 'model-view-controller', 'models/', 'views/', 'controllers/', 'model.', 'view.', 'controller.', '@controller', '@model' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 2) { patterns.push('MVC'); confidence['MVC'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['MVC'] = foundIndicators; } } detectMVVMPattern(content, patterns, confidence, evidence) { const indicators = [ 'mvvm', 'model-view-viewmodel', 'viewmodel', 'databinding', 'binding', 'observable', 'command', 'inotifypropertychanged', 'wpf', 'xaml' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 2) { patterns.push('MVVM'); confidence['MVVM'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['MVVM'] = foundIndicators; } } detectMicrokernelArchitecture(content, patterns, confidence, evidence) { const indicators = [ 'plugin', 'plugins', 'microkernel', 'extension', 'extensions', 'addon', 'addons', 'module', 'modules', 'kernel', 'core' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 2) { patterns.push('Microkernel Architecture'); confidence['Microkernel Architecture'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Microkernel Architecture'] = foundIndicators; } } detectSpaceBasedArchitecture(content, patterns, confidence, evidence) { const indicators = [ 'space-based', 'grid', 'distributed', 'cache', 'hazelcast', 'coherence', 'ignite', 'gemfire', 'tuple', 'space' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 2) { patterns.push('Space-based Architecture'); confidence['Space-based Architecture'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Space-based Architecture'] = foundIndicators; } } detectSingletonPattern(content, patterns, confidence, evidence) { const indicators = [ 'singleton', 'getinstance', 'instance', 'static instance', 'private constructor', 'lazy initialization' ]; const foundIndicators = indicators.filter(indicator => content.includes(indicator)); if (foundIndicators.length >= 1) { patterns.push('Singleton Pattern'); confidence['Singleton Pattern'] = Math.min(foundIndicators.length / indicators.length, 1.0); evidence['Singleton Pattern'] = foundIndicators; } } detectFactoryPattern(content, patterns, confidence, evidence) { const indicators = [ 'factory', 'factories', 'create', 'builder', 'abstractfactory', 'factorymethod', 'creational', 'instantiate' ]; const foundIndicators = indicators.filter(indicator => cont