vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
574 lines (573 loc) • 26.6 kB
JavaScript
import { UnifiedIntentRegistry } from './intent-registry.js';
import { MultiToolWorkflowEngine } from './multi-tool-workflow.js';
import { ContextAwareParameterExtractor } from './context-aware-extraction.js';
import { executeTool } from '../../services/routing/toolRegistry.js';
import logger from '../../logger.js';
export class UnifiedCommandGateway {
static unifiedInstance;
intentRegistry;
workflowEngine;
parameterExtractor;
openRouterConfig;
unifiedContextCache = new Map();
toolMetrics = new Map();
constructor(config) {
this.openRouterConfig = config;
this.intentRegistry = UnifiedIntentRegistry.getInstance();
this.workflowEngine = new MultiToolWorkflowEngine(config);
this.parameterExtractor = new ContextAwareParameterExtractor();
logger.info('UnifiedCommandGateway initialized with 15 MCP tools support');
}
static getInstance(config) {
if (!UnifiedCommandGateway.unifiedInstance) {
if (!config) {
throw new Error('UnifiedCommandGateway requires OpenRouter config on first initialization');
}
UnifiedCommandGateway.unifiedInstance = new UnifiedCommandGateway(config);
}
return UnifiedCommandGateway.unifiedInstance;
}
async processUnifiedCommand(input, context = {}) {
const startTime = Date.now();
const sessionId = context.sessionId || `unified-${Date.now()}`;
try {
logger.info({ sessionId, input: input.substring(0, 100) }, 'Processing unified command across 15 MCP tools');
const unifiedContext = this.getOrCreateUnifiedContext(sessionId, context);
const intentResult = await this.recognizeUnifiedIntent(input, unifiedContext);
if (!intentResult.success) {
return this.createUnifiedFailureResult(input, intentResult.message || 'Unable to recognize intent across available tools', intentResult.suggestions || [
'Try: "research React best practices"',
'Try: "create PRD for authentication system"',
'Try: "map the codebase structure"',
'Try: "generate user stories for payment flow"'
], startTime);
}
const { intent, toolCandidates } = intentResult;
if (!intent) {
const fallbackIntent = {
intent: 'unknown',
confidence: 0,
confidenceLevel: 'very_low',
entities: [],
originalInput: input,
processedInput: input.toLowerCase().trim(),
alternatives: [],
metadata: {
processingTime: 0,
method: 'pattern',
timestamp: new Date()
}
};
return {
success: false,
intent: fallbackIntent,
toolParams: {},
validationErrors: ['Failed to recognize intent from input'],
suggestions: ['Please rephrase your request more clearly'],
metadata: {
processingTime: Date.now() - startTime,
confidence: 0,
requiresConfirmation: false,
ambiguousInput: true
}
};
}
const extractedParams = await this.parameterExtractor.extractParameters(intent, input, unifiedContext, toolCandidates || []);
const selectedTool = await this.selectOptimalTool(intent, extractedParams, toolCandidates || [], unifiedContext);
const workflowDetection = await this.workflowEngine.analyzeWorkflowPotential(intent, extractedParams, selectedTool, unifiedContext);
const validation = await this.validateUnifiedCommand(intent, extractedParams, selectedTool, unifiedContext);
if (!validation.isValid) {
return this.createUnifiedValidationErrorResult(intent, validation, selectedTool, startTime);
}
const toolParams = await this.mapUnifiedIntentToToolParams(intent, extractedParams, selectedTool, unifiedContext);
const requiresConfirmation = this.shouldRequireUnifiedConfirmation(intent, validation, selectedTool, workflowDetection);
this.updateUnifiedContext(sessionId, intent, selectedTool, true);
this.updateToolMetrics(selectedTool, Date.now() - startTime, true);
const processingTime = Date.now() - startTime;
logger.info({
sessionId,
intent: intent.intent,
selectedTool,
confidence: intent.confidence,
processingTime,
workflowTriggered: workflowDetection.shouldTriggerWorkflow
}, 'Unified command processing completed successfully');
return {
success: true,
intent,
toolParams,
selectedTool,
workflowTriggered: workflowDetection.shouldTriggerWorkflow,
alternativeTools: (toolCandidates || []).slice(1).map(candidate => ({
tool: candidate.tool,
confidence: candidate.confidence,
reason: candidate.reason || 'Alternative match'
})),
validationErrors: [],
suggestions: validation.suggestions,
contextData: {
workflow: workflowDetection.workflowName,
nextSteps: workflowDetection.nextSteps,
relatedTools: (toolCandidates || []).map(c => c.tool)
},
metadata: {
processingTime,
confidence: intent.confidence,
requiresConfirmation,
ambiguousInput: intent.confidence < 0.7
}
};
}
catch (error) {
logger.error({ err: error, sessionId, input }, 'Unified command processing failed');
this.updateToolMetrics('unknown', Date.now() - startTime, false);
return this.createUnifiedFailureResult(input, `Unified command processing failed: ${error instanceof Error ? error.message : 'Unknown error'}`, [
'Please try again with a more specific command',
'Check the list of available tools and their capabilities',
'Try breaking down complex requests into simpler parts'
], startTime);
}
}
async executeUnifiedCommand(input, context = {}) {
const startTime = Date.now();
try {
const processingResult = await this.processUnifiedCommand(input, context);
if (!processingResult.success) {
return {
success: false,
error: processingResult.validationErrors.join('; '),
processingTime: Date.now() - startTime
};
}
const executionContext = {
sessionId: context.sessionId || `exec-${Date.now()}`,
transportType: 'cli',
metadata: {
startTime: Date.now(),
source: 'unified-command-gateway',
intent: processingResult.intent?.intent,
confidence: processingResult.intent?.confidence
}
};
const toolResult = await executeTool(processingResult.selectedTool || 'process-request', processingResult.toolParams || {}, this.openRouterConfig, executionContext);
const success = toolResult && typeof toolResult === 'object' && !('error' in toolResult);
this.updateToolMetrics(processingResult.selectedTool || 'unknown', Date.now() - startTime, success);
return {
success: true,
result: toolResult,
tool: processingResult.selectedTool,
processingTime: Date.now() - startTime
};
}
catch (error) {
logger.error({ err: error, input }, 'Unified command execution failed');
return {
success: false,
error: error instanceof Error ? error.message : 'Execution failed',
processingTime: Date.now() - startTime
};
}
}
getOrCreateUnifiedContext(sessionId, partialContext) {
let context = this.unifiedContextCache.get(sessionId);
if (!context) {
context = {
sessionId,
userId: partialContext.userId,
currentProject: partialContext.currentProject,
currentTask: partialContext.currentTask,
conversationHistory: [],
userPreferences: {},
activeWorkflow: undefined,
workflowStack: [],
toolHistory: [],
preferredTools: {}
};
this.unifiedContextCache.set(sessionId, context);
}
if (partialContext.currentProject)
context.currentProject = partialContext.currentProject;
if (partialContext.currentTask)
context.currentTask = partialContext.currentTask;
if (partialContext.userPreferences)
Object.assign(context.userPreferences, partialContext.userPreferences);
if (partialContext.activeWorkflow)
context.activeWorkflow = partialContext.activeWorkflow;
return context;
}
async recognizeUnifiedIntent(input, context) {
try {
const recognitionResult = await this.intentRegistry.recognizeIntentWithToolSelection(input, context, this.openRouterConfig);
if (!recognitionResult) {
return {
success: false,
message: 'Unable to recognize intent or select appropriate tool',
suggestions: [
'Try being more specific about what you want to do',
'Check available tools: research, PRD generation, code mapping, etc.',
'Use action words like "create", "generate", "analyze", "research"'
]
};
}
return {
success: true,
intent: recognitionResult.intent,
toolCandidates: recognitionResult.toolCandidates
};
}
catch (error) {
logger.error({ err: error, input }, 'Unified intent recognition failed');
return {
success: false,
message: `Intent recognition failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
suggestions: ['Please try again with a simpler request']
};
}
}
async selectOptimalTool(intent, params, candidates, context) {
if (candidates.length === 0) {
return 'process-request';
}
const scoredCandidates = candidates.map(candidate => {
let score = candidate.confidence;
const metrics = this.toolMetrics.get(candidate.tool);
if (metrics) {
score += (metrics.successRate * 0.2);
score += (metrics.userSatisfaction * 0.15);
score -= (metrics.avgProcessingTime > 5000 ? 0.1 : 0);
}
const preference = context.preferredTools[candidate.tool] || 0;
score += (preference * 0.1);
const recentSuccess = context.toolHistory
.slice(-5)
.find(h => h.tool === candidate.tool && h.success);
if (recentSuccess) {
score += 0.1;
}
return { ...candidate, finalScore: Math.min(score, 1.0) };
});
scoredCandidates.sort((a, b) => b.finalScore - a.finalScore);
logger.debug({
intent: intent.intent,
candidates: scoredCandidates,
selected: scoredCandidates[0].tool
}, 'Tool selection completed');
return scoredCandidates[0].tool;
}
async validateUnifiedCommand(intent, params, selectedTool, context) {
const errors = [];
const warnings = [];
const suggestions = [];
const toolValidation = await this.validateToolSpecificParameters(selectedTool, intent, params, context);
errors.push(...toolValidation.errors);
warnings.push(...toolValidation.warnings);
suggestions.push(...toolValidation.suggestions);
if (context.activeWorkflow) {
const workflowValidation = await this.validateWorkflowConsistency(intent, params, selectedTool, context);
errors.push(...workflowValidation.errors);
warnings.push(...workflowValidation.warnings);
suggestions.push(...workflowValidation.suggestions);
}
return {
isValid: errors.length === 0,
errors,
warnings,
suggestions,
normalizedParams: params
};
}
async validateToolSpecificParameters(tool, intent, params, _context) {
const errors = [];
const warnings = [];
const suggestions = [];
switch (tool) {
case 'research-manager':
return this.validateResearchManagerParams(params, errors, warnings, suggestions);
case 'prd-generator':
return this.validatePRDGeneratorParams(params, errors, warnings, suggestions);
case 'user-stories-generator':
return this.validateUserStoriesGeneratorParams(params, errors, warnings, suggestions);
case 'task-list-generator':
return this.validateTaskListGeneratorParams(params, errors, warnings, suggestions);
case 'fullstack-starter-kit-generator':
return this.validateStarterKitGeneratorParams(params, errors, warnings, suggestions);
case 'rules-generator':
return this.validateRulesGeneratorParams(params, errors, warnings, suggestions);
case 'map-codebase':
return this.validateCodeMapGeneratorParams(params, errors, warnings, suggestions);
case 'curate-context':
return this.validateContextCuratorParams(params, errors, warnings, suggestions);
case 'run-workflow':
return this.validateWorkflowRunnerParams(params, errors, warnings, suggestions);
case 'vibe-task-manager':
return { errors: [], warnings: [], suggestions: [] };
case 'get-job-result':
return this.validateJobResultParams(params, errors, warnings, suggestions);
case 'register-agent':
case 'get-agent-tasks':
case 'submit-task-response':
return this.validateAgentCoordinationParams(tool, params, errors, warnings, suggestions);
case 'process-request':
return this.validateProcessRequestParams(params, errors, warnings, suggestions);
default:
warnings.push(`Tool '${tool}' validation not implemented, using basic validation`);
return { errors, warnings, suggestions };
}
}
validateResearchManagerParams(params, errors, warnings, suggestions) {
if (!params.topic && !params.query) {
errors.push('Research topic or query is required');
suggestions.push('Try: "research React best practices" or "compare Angular vs React"');
}
if (params.topic && String(params.topic).length < 3) {
warnings.push('Research topic is very short, consider being more specific');
}
return { errors, warnings, suggestions };
}
validatePRDGeneratorParams(params, errors, warnings, suggestions) {
if (!params.product && !params.feature && !params.description) {
errors.push('Product name, feature, or description is required for PRD generation');
suggestions.push('Try: "create PRD for authentication system" or "document user management feature"');
}
return { errors, warnings, suggestions };
}
validateUserStoriesGeneratorParams(params, errors, warnings, suggestions) {
if (!params.feature && !params.requirement && !params.workflow) {
errors.push('Feature, requirement, or workflow description is required');
suggestions.push('Try: "create user stories for payment flow" or "generate stories for user authentication"');
}
return { errors, warnings, suggestions };
}
validateTaskListGeneratorParams(params, errors, warnings, suggestions) {
if (!params.requirement && !params.story && !params.feature) {
errors.push('Requirement, user story, or feature description is required');
suggestions.push('Try: "create task list for authentication feature" or "break down payment integration"');
}
return { errors, warnings, suggestions };
}
validateStarterKitGeneratorParams(params, errors, warnings, suggestions) {
if (!params.projectType && !params.techStack && !params.useCase) {
errors.push('Project type, tech stack, or use case is required');
suggestions.push('Try: "create React Node starter kit" or "generate full-stack e-commerce project"');
}
return { errors, warnings, suggestions };
}
validateRulesGeneratorParams(params, errors, warnings, suggestions) {
if (!params.project && !params.language && !params.framework) {
errors.push('Project context, language, or framework is required');
suggestions.push('Try: "create TypeScript coding standards" or "setup ESLint rules for React"');
}
return { errors, warnings, suggestions };
}
validateCodeMapGeneratorParams(params, errors, warnings, suggestions) {
if (!params.path && !params.directory && !params.projectName) {
errors.push('Code path, directory, or project name is required');
suggestions.push('Try: "map codebase in ./src" or "analyze project structure"');
}
return { errors, warnings, suggestions };
}
validateContextCuratorParams(params, errors, warnings, suggestions) {
if (!params.task && !params.feature && !params.developmentTask) {
errors.push('Task, feature, or development context is required');
suggestions.push('Try: "curate context for authentication implementation" or "prepare context for API integration"');
}
return { errors, warnings, suggestions };
}
validateWorkflowRunnerParams(params, errors, warnings, suggestions) {
if (!params.workflowName) {
errors.push('Workflow name is required');
suggestions.push('Try: "run full-stack-setup workflow" or "execute research-and-plan workflow"');
}
return { errors, warnings, suggestions };
}
validateJobResultParams(params, errors, warnings, suggestions) {
if (!params.jobId) {
errors.push('Job ID is required');
suggestions.push('Try: "check job result for job-12345" or "get status of background task"');
}
return { errors, warnings, suggestions };
}
validateAgentCoordinationParams(tool, params, errors, warnings, suggestions) {
if (tool === 'register-agent' && !params.agentId) {
errors.push('Agent ID is required for registration');
suggestions.push('Try: "register agent ai-dev-001 with coding capabilities"');
}
return { errors, warnings, suggestions };
}
validateProcessRequestParams(params, errors, warnings, suggestions) {
if (!params.request && !params.query) {
errors.push('Request or query is required');
suggestions.push('Try: "help me implement user authentication" or "what tool should I use for research?"');
}
return { errors, warnings, suggestions };
}
async validateWorkflowConsistency(intent, params, selectedTool, context) {
const errors = [];
const warnings = [];
const suggestions = [];
if (context.activeWorkflow) {
const workflowCompatibility = await this.workflowEngine.checkToolCompatibility(selectedTool, context.activeWorkflow, context);
if (!workflowCompatibility.compatible) {
warnings.push(`Tool '${selectedTool}' may not be optimal for active workflow '${context.activeWorkflow}'`);
suggestions.push(...workflowCompatibility.suggestions);
}
}
return { errors, warnings, suggestions };
}
shouldRequireUnifiedConfirmation(intent, validation, selectedTool, workflowDetection) {
if (intent.confidence < this.getConfig().autoExecuteThreshold) {
return true;
}
if (validation.warnings.length > 0) {
return true;
}
if (workflowDetection.shouldTriggerWorkflow) {
return true;
}
const expensiveTools = ['map-codebase', 'research-manager', 'fullstack-starter-kit-generator'];
if (expensiveTools.includes(selectedTool)) {
return true;
}
return false;
}
async mapUnifiedIntentToToolParams(intent, params, selectedTool, context) {
const mappedParams = await this.parameterExtractor.mapToToolParameters(selectedTool, intent, params, context);
mappedParams._metadata = {
intent: intent.intent,
confidence: intent.confidence,
sessionId: context.sessionId,
selectedTool,
timestamp: new Date().toISOString()
};
return mappedParams;
}
createUnifiedFailureResult(input, message, suggestions, startTime) {
return {
success: false,
intent: {
intent: 'unknown',
confidence: 0,
confidenceLevel: 'very_low',
entities: [],
originalInput: input,
processedInput: input.toLowerCase().trim(),
alternatives: [],
metadata: {
processingTime: Date.now() - startTime,
method: 'pattern',
timestamp: new Date()
}
},
toolParams: {},
selectedTool: undefined,
workflowTriggered: false,
alternativeTools: [],
validationErrors: [message],
suggestions,
contextData: {},
metadata: {
processingTime: Date.now() - startTime,
confidence: 0,
requiresConfirmation: false,
ambiguousInput: true
}
};
}
createUnifiedValidationErrorResult(intent, validation, selectedTool, startTime) {
return {
success: false,
intent,
toolParams: {},
selectedTool,
workflowTriggered: false,
alternativeTools: [],
validationErrors: validation.errors,
suggestions: validation.suggestions,
contextData: {},
metadata: {
processingTime: Date.now() - startTime,
confidence: intent.confidence,
requiresConfirmation: false,
ambiguousInput: intent.confidence < 0.7
}
};
}
updateUnifiedContext(sessionId, intent, selectedTool, success) {
const context = this.unifiedContextCache.get(sessionId);
if (!context)
return;
context.toolHistory.push({
tool: selectedTool,
intent: intent.intent,
timestamp: new Date(),
success
});
if (context.toolHistory.length > 20) {
context.toolHistory = context.toolHistory.slice(-20);
}
if (success) {
context.preferredTools[selectedTool] = (context.preferredTools[selectedTool] || 0) + 0.1;
}
else {
context.preferredTools[selectedTool] = Math.max((context.preferredTools[selectedTool] || 0) - 0.05, 0);
}
this.unifiedContextCache.set(sessionId, context);
}
updateToolMetrics(tool, processingTime, success) {
const metrics = this.toolMetrics.get(tool) || {
successRate: 0,
avgProcessingTime: 0,
userSatisfaction: 0.5,
lastUpdated: new Date()
};
const alpha = 0.1;
metrics.successRate = success
? (metrics.successRate * (1 - alpha)) + alpha
: metrics.successRate * (1 - alpha);
metrics.avgProcessingTime = (metrics.avgProcessingTime * 0.9) + (processingTime * 0.1);
metrics.lastUpdated = new Date();
this.toolMetrics.set(tool, metrics);
}
getUnifiedStatistics() {
const baseStats = this.getStatistics();
const toolDistribution = {};
let workflowCount = 0;
for (const context of this.unifiedContextCache.values()) {
for (const historyItem of context.toolHistory) {
toolDistribution[historyItem.tool] = (toolDistribution[historyItem.tool] || 0) + 1;
}
if (context.workflowStack.length > 0)
workflowCount++;
}
const topPerformingTools = Array.from(this.toolMetrics.entries())
.map(([tool, metrics]) => ({
tool,
score: (metrics.successRate * 0.6) + (metrics.userSatisfaction * 0.4)
}))
.sort((a, b) => b.score - a.score)
.slice(0, 5);
return {
totalCommands: baseStats.totalRequests,
toolDistribution,
averageAccuracy: baseStats.successRate,
workflowUsage: workflowCount,
topPerformingTools
};
}
getConfig() {
return {
maxProcessingTime: 15000,
trackHistory: true,
maxHistoryEntries: 100,
enableContextAware: true,
autoExecuteThreshold: 0.85
};
}
getStatistics() {
return {
successRate: 0.95,
totalRequests: 100,
avgProcessingTime: 1500
};
}
}