@versatil/sdlc-framework
Version:
🚀 AI-Native SDLC framework with 11-MCP ecosystem, RAG memory, OPERA orchestration, and 6 specialized agents achieving ZERO CONTEXT LOSS. Features complete CI/CD pipeline with 7 GitHub workflows (MCP testing, security scanning, performance benchmarking),
445 lines • 18.8 kB
JavaScript
/**
* VERSATIL SDLC Framework - Agent Orchestrator Layer
*
* Coordinates the three-tier intelligence system:
* - Level 1: Pattern Analysis (no AI needed)
* - Level 2: Prompt Generation (for IDE execution)
* - Level 3: Optional AI API (when configured)
*/
import { PatternAnalyzer } from './pattern-analyzer.js';
import { PromptGenerator } from './prompt-generator.js';
import { createFromEnv } from './ai-integration.js';
import { AgentRegistry } from '../agents/agent-registry.js';
export class AgentOrchestrator {
constructor(aiIntegration, vectorMemoryStore) {
this.agentRegistry = new AgentRegistry();
this.aiIntegration = aiIntegration || createFromEnv();
this.vectorMemoryStore = vectorMemoryStore;
this.ragEnabled = !!vectorMemoryStore;
}
/**
* Orchestrate complete analysis for a file with RAG-enhanced intelligence
*/
async analyzeFile(context) {
// Step 1: Select appropriate agent
const agent = this.selectAgent(context);
// Step 2: Retrieve RAG context if enabled
let ragContext;
if (this.ragEnabled && this.vectorMemoryStore) {
ragContext = await this.retrieveRAGContext(context, agent);
}
// Step 3: Run Level 1 - Pattern Analysis (enhanced with RAG context)
const level1 = this.runPatternAnalysis(agent, context, ragContext);
// Step 4: Run Level 2 - Prompt Generation (enhanced with RAG examples)
const language = context.language || this.detectLanguage(context.filePath);
const promptContext = {
filePath: context.filePath,
content: context.content,
language,
projectName: context.projectName || 'Unknown Project',
userRequest: context.userRequest,
analysisResult: level1,
ragContext // Add RAG context to prompt generation
};
const level2 = PromptGenerator.generatePrompt(agent, promptContext);
// Step 5: Optionally run Level 3 - AI API
const analysis = await this.aiIntegration.executeAnalysis(level1, level2);
// Step 6: Store successful patterns and solutions back to vector memory
if (this.ragEnabled && this.vectorMemoryStore && analysis.level1) {
await this.storeSuccessfulPatterns(context, agent, analysis.level1, ragContext);
}
// Step 7: Determine next steps (enhanced with RAG insights)
const nextSteps = this.determineNextSteps(level1, level2, analysis.mode, ragContext);
const mode = this.ragEnabled && ragContext ? 'rag-enhanced' : analysis.mode;
return {
agent,
filePath: context.filePath,
level1: analysis.level1,
level2: analysis.level2,
level3: analysis.level3,
ragContext,
mode,
nextSteps,
executionRecommendation: this.getExecutionRecommendation(mode, level2, ragContext)
};
}
/**
* Retrieve RAG context for enhanced analysis
*/
async retrieveRAGContext(context, agent) {
if (!this.vectorMemoryStore) {
return {
similarPatterns: [],
relevantSolutions: [],
projectConventions: [],
agentExpertise: []
};
}
const language = this.detectLanguage(context.filePath);
const fileType = context.filePath.split('.').pop() || '';
// Create a semantic query from the file content
const queryText = this.createSemanticQuery(context.content, context.filePath);
try {
// Retrieve similar patterns for this agent domain
const similarPatternsQuery = {
query: queryText,
queryType: 'semantic',
agentId: agent,
topK: 5,
filters: {
tags: [language, fileType, 'pattern'],
contentTypes: ['code']
}
};
// Retrieve relevant solutions from previous fixes
const solutionsQuery = {
query: queryText,
queryType: 'semantic',
agentId: agent,
topK: 3,
filters: {
tags: [language, fileType, 'solution'],
contentTypes: ['code']
}
};
// Retrieve project conventions and standards
const conventionsQuery = {
query: `${language} conventions standards`,
queryType: 'semantic',
topK: 3,
filters: {
tags: [language, 'convention', 'standard'],
contentTypes: ['text', 'code']
}
};
// Retrieve agent-specific expertise
const expertiseQuery = {
query: queryText,
queryType: 'semantic',
agentId: agent,
topK: 5,
filters: {
tags: [agent, 'expertise', language],
contentTypes: ['code', 'text']
}
};
// Execute all queries in parallel
const [similarPatterns, relevantSolutions, projectConventions, agentExpertise] = await Promise.all([
this.vectorMemoryStore.queryMemories(similarPatternsQuery),
this.vectorMemoryStore.queryMemories(solutionsQuery),
this.vectorMemoryStore.queryMemories(conventionsQuery),
this.vectorMemoryStore.queryMemories(expertiseQuery)
]);
return {
similarPatterns: similarPatterns.documents || [],
relevantSolutions: relevantSolutions.documents || [],
projectConventions: projectConventions.documents || [],
agentExpertise: agentExpertise.documents || []
};
}
catch (error) {
console.warn('Failed to retrieve RAG context:', error);
return {
similarPatterns: [],
relevantSolutions: [],
projectConventions: [],
agentExpertise: []
};
}
}
/**
* Create a semantic query from file content
*/
createSemanticQuery(content, filePath) {
// Extract key concepts, function names, and patterns
const lines = content.split('\n');
const keywords = [];
// Extract function/class/component names
const functionMatches = content.match(/(?:function|class|const|let|var)\s+(\w+)/g);
if (functionMatches) {
keywords.push(...functionMatches.map(match => match.split(/\s+/)[1]));
}
// Extract import/require statements
const importMatches = content.match(/(?:import|require|from)\s+['"`]([^'"`]+)['"`]/g);
if (importMatches) {
keywords.push(...importMatches.map(match => match.match(/['"`]([^'"`]+)['"`]/)?.[1] || ''));
}
// Add file path context
const pathParts = filePath.split('/').filter(part => part && !part.includes('.'));
keywords.push(...pathParts);
// Create a concise semantic query
const uniqueKeywords = [...new Set(keywords)].filter(k => k && k.length > 2).slice(0, 10);
return uniqueKeywords.join(' ') || content.slice(0, 200);
}
/**
* Store successful patterns and solutions back to vector memory
*/
async storeSuccessfulPatterns(context, agent, analysisResult, ragContext) {
if (!this.vectorMemoryStore)
return;
try {
const language = this.detectLanguage(context.filePath);
const fileType = context.filePath.split('.').pop() || '';
// Store high-quality code patterns (score >= 80)
if (analysisResult.score >= 80) {
const patternDoc = {
id: `pattern_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
content: context.content,
contentType: 'code',
metadata: {
agentId: agent,
timestamp: Date.now(),
fileType,
projectContext: context.projectName || 'Unknown',
tags: [language, fileType, 'pattern', 'high-quality', agent],
relevanceScore: analysisResult.score / 100,
language,
framework: this.detectFramework(context.content)
}
};
await this.vectorMemoryStore.storeMemory(patternDoc);
}
// Store detected patterns for learning
if (analysisResult.patterns && analysisResult.patterns.length > 0) {
for (const pattern of analysisResult.patterns) {
const patternDoc = {
id: `detected_pattern_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
content: pattern.suggestion || pattern.message,
contentType: 'text',
metadata: {
agentId: agent,
timestamp: Date.now(),
fileType,
projectContext: context.projectName || 'Unknown',
tags: [language, fileType, pattern.type, pattern.category, agent],
relevanceScore: pattern.severity === 'critical' ? 1.0 :
pattern.severity === 'high' ? 0.8 :
pattern.severity === 'medium' ? 0.6 : 0.4,
language
}
};
await this.vectorMemoryStore.storeMemory(patternDoc);
}
}
}
catch (error) {
console.warn('Failed to store patterns to vector memory:', error);
}
}
/**
* Detect framework from code content
*/
detectFramework(content) {
if (content.includes('react') || content.includes('useState') || content.includes('useEffect')) {
return 'React';
}
if (content.includes('vue') || content.includes('Vue')) {
return 'Vue';
}
if (content.includes('angular') || content.includes('Angular')) {
return 'Angular';
}
if (content.includes('express') || content.includes('app.get') || content.includes('app.post')) {
return 'Express';
}
if (content.includes('fastify')) {
return 'Fastify';
}
if (content.includes('jest') || content.includes('describe') || content.includes('it(')) {
return 'Jest';
}
return '';
}
/**
* Select appropriate agent based on file context
*/
selectAgent(context) {
const { filePath, content, userRequest } = context;
// Priority 1: User explicitly requests an agent
if (userRequest) {
if (userRequest.toLowerCase().includes('test') || userRequest.toLowerCase().includes('qa')) {
return 'enhanced-maria';
}
if (userRequest.toLowerCase().includes('frontend') || userRequest.toLowerCase().includes('ui')) {
return 'enhanced-james';
}
if (userRequest.toLowerCase().includes('backend') || userRequest.toLowerCase().includes('api')) {
return 'enhanced-marcus';
}
if (userRequest.toLowerCase().includes('project') || userRequest.toLowerCase().includes('plan')) {
return 'sarah-pm';
}
}
// Priority 2: File path patterns
if (filePath.includes('test') || filePath.includes('spec') || filePath.includes('__tests__')) {
return 'enhanced-maria';
}
if (filePath.match(/\.(jsx|tsx|vue|svelte)$/)) {
return 'enhanced-james';
}
if (filePath.includes('component') || filePath.includes('ui/') || filePath.includes('pages/')) {
return 'enhanced-james';
}
if (filePath.includes('api') || filePath.includes('server') || filePath.includes('backend')) {
return 'enhanced-marcus';
}
if (filePath.match(/\.(md|txt)$/) || filePath.includes('README')) {
return 'sarah-pm';
}
// Priority 3: Content analysis
if (content.includes('describe(') || content.includes('it(') || content.includes('test(')) {
return 'enhanced-maria';
}
if (content.includes('useState') || content.includes('useEffect') || content.includes('<')) {
return 'enhanced-james';
}
if (content.includes('app.get') || content.includes('app.post') || content.includes('router.')) {
return 'enhanced-marcus';
}
// Default: Use Maria for QA analysis
return 'enhanced-maria';
}
/**
* Run pattern analysis based on agent (enhanced with RAG context)
*/
runPatternAnalysis(agent, context, ragContext) {
switch (agent) {
case 'enhanced-maria':
case 'maria-qa':
return PatternAnalyzer.analyzeQA(context.content, context.filePath, ragContext);
case 'enhanced-james':
case 'james-frontend':
return PatternAnalyzer.analyzeFrontend(context.content, context.filePath, ragContext);
case 'enhanced-marcus':
case 'marcus-backend':
return PatternAnalyzer.analyzeBackend(context.content, context.filePath, ragContext);
default:
// Generic analysis for other agents
return PatternAnalyzer.analyzeQA(context.content, context.filePath, ragContext);
}
}
/**
* Detect programming language from file path
*/
detectLanguage(filePath) {
const ext = filePath.split('.').pop()?.toLowerCase() || '';
const langMap = {
'js': 'javascript',
'jsx': 'javascriptreact',
'ts': 'typescript',
'tsx': 'typescriptreact',
'py': 'python',
'rb': 'ruby',
'java': 'java',
'go': 'go',
'rs': 'rust',
'php': 'php',
'vue': 'vue',
'svelte': 'svelte',
'md': 'markdown'
};
return langMap[ext] || 'plaintext';
}
/**
* Determine next steps based on analysis (enhanced with RAG insights)
*/
determineNextSteps(level1, level2, mode, ragContext) {
const steps = [];
// Critical issues require immediate action
const critical = level1.patterns.filter(p => p.severity === 'critical');
if (critical.length > 0) {
steps.push(`🚨 Address ${critical.length} critical issues immediately`);
}
// Mode-specific recommendations
if (mode === 'patterns-only') {
steps.push('📋 Review pattern analysis results');
steps.push('🔧 Configure ANTHROPIC_API_KEY for AI-enhanced analysis');
}
if (mode === 'prompt-ready') {
steps.push('💡 Copy generated prompt to Claude Code/Cursor');
steps.push('🎯 Execute prompt in IDE for intelligent analysis');
}
if (mode === 'ai-enhanced') {
steps.push('✅ Review AI-generated recommendations');
steps.push('🔄 Implement suggested improvements');
}
if (mode === 'rag-enhanced') {
steps.push('🧠 Review RAG-enhanced analysis');
steps.push('🎯 Apply best practices from similar patterns');
if (ragContext?.relevantSolutions.length) {
steps.push(`💡 Consider ${ragContext.relevantSolutions.length} similar solutions`);
}
}
// Agent handoffs
if (level2.handoffSuggestions.length > 0) {
steps.push(`🤝 Coordinate with: ${level2.handoffSuggestions.join(', ')}`);
}
return steps;
}
/**
* Get execution recommendation for user (enhanced with RAG context)
*/
getExecutionRecommendation(mode, prompt, ragContext) {
if (mode === 'ai-enhanced') {
return '✅ AI analysis complete. Review recommendations above and implement suggested changes.';
}
if (mode === 'rag-enhanced') {
const ragInsights = ragContext ? [
`🧠 Found ${ragContext.similarPatterns.length} similar patterns`,
`💡 ${ragContext.relevantSolutions.length} proven solutions available`,
`📋 ${ragContext.projectConventions.length} project conventions applied`,
`🎯 ${ragContext.agentExpertise.length} expert insights integrated`
].join('\n') : '';
return `🚀 **RAG-Enhanced Analysis Complete**\n\n${ragInsights}\n\nThe analysis has been enriched with project-specific knowledge and proven patterns. Review the enhanced recommendations above.`;
}
if (mode === 'prompt-ready') {
return `🎯 **For Claude Code/Cursor Users**:\n\n1. Copy the prompt below\n2. Open Claude Code/Cursor chat\n3. Paste and execute\n4. Get intelligent analysis\n\n---\n\n${prompt.prompt}\n\n---`;
}
return '📊 Pattern analysis complete. Configure ANTHROPIC_API_KEY for enhanced features.';
}
/**
* Get AI integration status
*/
getAIStatus() {
return this.aiIntegration.getStatus();
}
/**
* Batch analyze multiple files
*/
async analyzeFiles(contexts) {
return Promise.all(contexts.map(ctx => this.analyzeFile(ctx)));
}
/**
* Get agent information
*/
getAgentInfo(agentId) {
const agent = this.agentRegistry.getAgent(agentId);
if (!agent) {
throw new Error(`Agent not found: ${agentId}`);
}
return {
id: agentId,
name: agent.name,
specialization: agent.specialization
};
}
/**
* List all available agents
*/
listAgents() {
return this.agentRegistry.getStatus();
}
}
/**
* Create orchestrator with environment configuration and optional RAG support
*/
export function createOrchestrator(vectorMemoryStore) {
return new AgentOrchestrator(createFromEnv(), vectorMemoryStore);
}
/**
* Create RAG-enhanced orchestrator with vector memory
*/
export function createRAGOrchestrator(vectorMemoryStore) {
return new AgentOrchestrator(createFromEnv(), vectorMemoryStore);
}
//# sourceMappingURL=agent-orchestrator.js.map