UNPKG

@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),

462 lines 18 kB
/** * VERSATIL SDLC Framework - Auto-Agent Dispatcher * Real-time agent activation based on file patterns, context, and triggers * * This is the core missing piece that makes OPERA methodology truly autonomous */ import { EventEmitter } from 'events'; import { watch } from 'fs'; import * as path from 'path'; /** * Core Agent Dispatch System * Monitors files, patterns, and context to automatically activate appropriate agents */ class VERSATILAgentDispatcher extends EventEmitter { constructor() { super(); this.agents = new Map(); this.activeAgents = new Set(); this.fileWatchers = new Map(); this.contextValidator = new ContextValidator(); this.initializeAgents(); this.setupFileWatching(); } /** * Initialize OPERA Agents with Enhanced Triggers */ initializeAgents() { // James - Frontend Agent this.agents.set('james', { agent: 'James (Frontend)', priority: 1, triggers: { filePatterns: ['*.tsx', '*.jsx', '*.css', '*.scss', 'components/**/*', 'pages/**/*'], keywords: ['UI', 'component', 'styling', 'responsive', 'design', 'router', 'navigation'], actions: ['component development', 'styling changes', 'UI fixes', 'routing issues'], dependencies: ['react', 'react-router', 'antd', '@tremor/react'], errorPatterns: [ 'No routes matched location', 'component.*not.*found', 'styling.*error', 'CSS.*error', 'import.*component.*failed' ] }, autoActivate: true, mcpTools: ['Chrome MCP', 'Shadcn MCP'], collaborators: ['Marcus', 'Maria'] }); // Marcus - Backend Agent this.agents.set('marcus', { agent: 'Marcus (Backend)', priority: 1, triggers: { filePatterns: ['*.ts', 'src/services/**/*', '*.sql', 'supabase/**/*', 'api/**/*'], keywords: ['API', 'database', 'backend', 'Edge Function', 'auth', 'server'], actions: ['backend service', 'database changes', 'API work', 'server configuration'], dependencies: ['@supabase/supabase-js', '@refinedev/core', 'supabase'], errorPatterns: [ 'Failed to resolve import', 'dependency.*not.*found', 'module.*not.*found', 'API.*error', 'database.*error', 'auth.*error' ] }, autoActivate: true, mcpTools: ['GitHub MCP'], collaborators: ['James', 'Maria'] }); // Maria - QA Agent this.agents.set('maria', { agent: 'Maria (QA)', priority: 2, triggers: { filePatterns: ['*.test.*', '*.spec.*', 'tests/**/*', 'cypress/**/*'], keywords: ['test', 'bug', 'error', 'validation', 'quality', 'debug'], actions: ['testing', 'debugging', 'error investigation', 'quality assessment'], dependencies: ['@testing-library/*', 'jest', 'vitest', 'cypress', 'playwright'], errorPatterns: [ 'test.*failed', 'assertion.*error', 'timeout.*error', 'console.*error', 'warning.*detected' ] }, autoActivate: true, mcpTools: ['Chrome MCP', 'Playwright MCP'], collaborators: ['James', 'Marcus'] }); // Sarah - Product Manager Agent this.agents.set('sarah', { agent: 'Sarah (PM)', priority: 3, triggers: { filePatterns: ['*.md', '*.stories.*', 'docs/**/*'], keywords: ['feature', 'requirements', 'user story', 'roadmap', 'specification'], actions: ['feature planning', 'requirements', 'documentation'], dependencies: ['@storybook/*'], errorPatterns: [] }, autoActivate: false, // PM requires manual activation for strategic decisions mcpTools: [], collaborators: ['Alex', 'James', 'Marcus'] }); // Dr. AI - ML/AI Agent this.agents.set('dr-ai', { agent: 'Dr. AI (ML)', priority: 1, triggers: { filePatterns: ['*RAG*', '*AI*', '*ML*', 'osint/**/*', 'agents/**/*', '*brain*'], keywords: ['RAG', 'LLM', 'AI', 'machine learning', 'OSINT', 'neural', 'model'], actions: ['AI development', 'RAG systems', 'ML implementation', 'OSINT analysis'], dependencies: ['@anthropic/*', 'openai', 'langchain', '@vercel/ai'], errorPatterns: [ 'AI.*model.*error', 'RAG.*system.*failed', 'embedding.*error', 'LLM.*timeout' ] }, autoActivate: true, mcpTools: ['GitHub MCP'], collaborators: ['Marcus', 'Maria'] }); // Logan - Context Agent (NEW) this.agents.set('logan', { agent: 'Logan (Context)', priority: 3, triggers: { filePatterns: ['CLAUDE.md', '.cursorrules', '.versatil/**/*'], keywords: ['context', 'conversation', 'memory', 'documentation', 'framework'], actions: ['context preservation', 'conversation logging', 'decision recording'], dependencies: [], errorPatterns: ['context.*loss', 'memory.*issue'] }, autoActivate: true, mcpTools: [], collaborators: ['Maria', 'Sarah'] }); console.log(`🤖 VERSATIL Agent Dispatcher: ${this.agents.size} agents initialized`); } /** * Enhanced Context Clarity Validation (User's New Requirement) */ async validateTaskContext(userRequest) { return this.contextValidator.validateContext(userRequest); } /** * Auto-Activate Agents Based on File Changes */ setupFileWatching() { // Skip file watching in CI environments or during initial setup if (process.env.CI === 'true' || process.env.VERSATIL_SKIP_WATCH === 'true') { console.log('📁 File watching disabled (CI/test environment)'); return; } const watchPath = process.cwd(); try { const watcher = watch(watchPath, { recursive: true }, (eventType, filename) => { if (!filename || this.shouldIgnoreFile(filename)) return; const fullPath = path.join(watchPath, filename); this.handleFileChange(eventType, fullPath); }); this.fileWatchers.set(watchPath, watcher); console.log(`📁 File watching enabled for: ${watchPath}`); } catch (error) { // Recursive watching not supported on this platform - gracefully degrade console.log('📁 File watching not available on this platform (non-recursive mode)'); // Framework will still work, just without auto-activation on file changes } } shouldIgnoreFile(filename) { const ignorePatterns = [ 'node_modules', '.git', 'dist', 'build', '.next', '.vite', 'coverage', '.nyc_output' ]; return ignorePatterns.some(pattern => filename.includes(pattern)); } /** * Core File Change Handler - Triggers Agent Activation */ async handleFileChange(eventType, filePath) { console.log(`📝 File ${eventType}: ${filePath}`); // Find matching agents based on file patterns const matchingAgents = this.findMatchingAgents(filePath); if (matchingAgents.length > 0) { console.log(`🎯 Auto-activating agents for ${filePath}:`, matchingAgents.map(a => a.agent)); for (const agent of matchingAgents) { await this.activateAgent(agent, { filePath }); } } } /** * Find Agents That Match File Patterns */ findMatchingAgents(filePath) { const fileName = path.basename(filePath); const relativePath = path.relative(process.cwd(), filePath); const matchingAgents = []; for (const [agentKey, agent] of this.agents) { if (!agent.autoActivate) continue; // Check file pattern matches const patternMatch = agent.triggers.filePatterns.some(pattern => { if (pattern.includes('*')) { const regex = new RegExp(pattern.replace(/\*/g, '.*')); return regex.test(fileName) || regex.test(relativePath); } return fileName.includes(pattern) || relativePath.includes(pattern); }); if (patternMatch) { matchingAgents.push(agent); } } return matchingAgents.sort((a, b) => a.priority - b.priority); } /** * Activate Agent with Context */ async activateAgent(trigger, context = {}) { if (!trigger.agent) { throw new Error('Agent name is required'); } const agentKey = trigger.agent.toLowerCase().split('(')[0].trim(); // Check if agent is already active if (this.activeAgents.has(agentKey)) { return { agent: trigger.agent, status: 'activated', message: `${trigger.agent} is already active` }; } this.activeAgents.add(agentKey); // Validate context clarity if user request provided let contextValidation = { clarity: 'clear', clarifications: [] }; if (context.userRequest) { contextValidation = await this.contextValidator.validateContext(context.userRequest); } const activationContext = { trigger, contextClarity: contextValidation.clarity, requiredClarifications: contextValidation.clarifications, ...context }; // If context is ambiguous, request clarification if (contextValidation.clarity === 'ambiguous') { return { agent: trigger.agent, status: 'clarification_needed', message: `${trigger.agent} needs clarification before proceeding`, clarifications: contextValidation.clarifications }; } // Activate MCP tools if required if (trigger.mcpTools.length > 0) { console.log(`🛠️ Auto-activating MCP tools for ${trigger.agent}:`, trigger.mcpTools); await this.activateMCPTools(trigger.mcpTools, activationContext); } // Activate collaborating agents if needed if (trigger.collaborators.length > 0) { console.log(`🤝 Activating collaborators for ${trigger.agent}:`, trigger.collaborators); for (const collaborator of trigger.collaborators) { const collaboratorTrigger = this.findAgentByName(collaborator); if (collaboratorTrigger) { await this.activateAgent(collaboratorTrigger, context); } } } this.emit('agent-activated', { agent: trigger.agent, context: activationContext, timestamp: new Date() }); return { agent: trigger.agent, status: 'activated', message: `${trigger.agent} successfully activated`, collaborators: trigger.collaborators }; } /** * Emergency Protocol - Auto-activate agents for critical errors */ async handleEmergency(errorMessage, context = '') { console.log('🚨 EMERGENCY PROTOCOL ACTIVATED:', errorMessage); const responses = []; // Find agents that can handle this error const emergencyAgents = this.findAgentsForError(errorMessage); if (emergencyAgents.length === 0) { // Default emergency response - activate Maria for investigation const mariaAgent = this.agents.get('maria'); if (mariaAgent) { const response = await this.activateAgent(mariaAgent, { errorMessage, userRequest: `Emergency: ${errorMessage}` }); responses.push(response); } } else { // Activate all matching emergency agents for (const agent of emergencyAgents) { const response = await this.activateAgent(agent, { errorMessage, userRequest: `Emergency: ${errorMessage}` }); responses.push(response); } } this.emit('emergency-handled', { error: errorMessage, agents: responses.map(r => r.agent), timestamp: new Date() }); return responses; } /** * Find agents that can handle specific error patterns */ findAgentsForError(errorMessage) { const matchingAgents = []; for (const [agentKey, agent] of this.agents) { const errorMatch = agent.triggers.errorPatterns.some(pattern => { const regex = new RegExp(pattern, 'i'); return regex.test(errorMessage); }); if (errorMatch) { matchingAgents.push(agent); } } return matchingAgents.sort((a, b) => a.priority - b.priority); } findAgentByName(name) { for (const [key, agent] of this.agents) { if (agent.agent.toLowerCase().includes(name.toLowerCase())) { return agent; } } return undefined; } /** * Activate MCP Tools */ async activateMCPTools(tools, context) { for (const tool of tools) { console.log(`🔧 Activating ${tool} for ${context.trigger.agent}`); // This would integrate with actual MCP activation // For now, log the activation } } /** * Deactivate agent */ deactivateAgent(agentName) { if (!agentName) { throw new Error('Agent name is required'); } const agentKey = agentName.toLowerCase().split('(')[0].trim(); this.activeAgents.delete(agentKey); this.emit('agent-deactivated', { agent: agentName, timestamp: new Date() }); } /** * Get currently active agents */ getActiveAgents() { return Array.from(this.activeAgents); } /** * Cleanup */ destroy() { // Stop file watchers for (const [path, watcher] of this.fileWatchers) { watcher.close(); } this.fileWatchers.clear(); // Clear active agents this.activeAgents.clear(); console.log('🛑 VERSATIL Agent Dispatcher stopped'); } } /** * Context Clarity Validator (User's Enhancement Request) */ class ContextValidator { async validateContext(userRequest) { const clarifications = []; const recommendedAgents = []; // Check for ambiguous terms const ambiguousTerms = ['it', 'this', 'that', 'thing', 'stuff', 'something']; const hasAmbiguousTerms = ambiguousTerms.some(term => userRequest.toLowerCase().includes(term)); // Check for missing specifics const hasSpecifics = { fileLocation: /file|path|component|\.tsx|\.ts|\.js/.test(userRequest), action: /add|create|fix|update|delete|modify|implement/.test(userRequest), technology: /react|antd|supabase|typescript|javascript/.test(userRequest) }; // Generate clarifications if (hasAmbiguousTerms) { clarifications.push('Please specify what "it" or "this" refers to'); } if (!hasSpecifics.fileLocation) { clarifications.push('Which file or component should be modified?'); } if (!hasSpecifics.action) { clarifications.push('What specific action should be taken?'); } if (!hasSpecifics.technology && userRequest.length > 20) { clarifications.push('Which technology stack or framework is involved?'); } // Recommend agents based on context if (/UI|component|styling|frontend/i.test(userRequest)) { recommendedAgents.push('James (Frontend)'); } if (/API|backend|database|server/i.test(userRequest)) { recommendedAgents.push('Marcus (Backend)'); } if (/test|bug|error|debug/i.test(userRequest)) { recommendedAgents.push('Maria (QA)'); } if (/AI|RAG|ML|OSINT/i.test(userRequest)) { recommendedAgents.push('Dr. AI (ML)'); } // Determine clarity level let clarity = 'clear'; if (clarifications.length > 2) { clarity = 'missing'; } else if (clarifications.length > 0) { clarity = 'ambiguous'; } return { clarity, clarifications, recommendedAgents }; } } // Export classes and singleton instance export { VERSATILAgentDispatcher, ContextValidator }; export const versatilDispatcher = new VERSATILAgentDispatcher(); // Start monitoring immediately in development if (process.env['NODE_ENV'] !== 'test') { console.log('🚀 VERSATIL Auto-Agent System: ONLINE'); } //# sourceMappingURL=agent-dispatcher.js.map