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