@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),
305 lines • 13.5 kB
JavaScript
/**
* OPERA Testing Orchestrator - Agent-Driven UI/UX Testing Workflow
*
* Coordinates Enhanced Maria-QA and Enhanced James for comprehensive
* UI/UX testing with real-time quality feedback and agent handoffs.
*/
import { EnhancedMaria } from '../agents/enhanced-maria.js';
import { EnhancedJames } from '../agents/enhanced-james.js';
import { VERSATILLogger } from '../utils/logger.js';
export class OPERATestingOrchestrator {
constructor() {
this.activeWorkflows = new Map();
this.logger = VERSATILLogger.getInstance();
this.mariaQA = new EnhancedMaria();
this.jamesFrontend = new EnhancedJames();
}
/**
* Trigger agent-driven testing workflow based on file changes
*/
async triggerAgentWorkflow(context) {
const workflowId = `workflow-${Date.now()}`;
this.activeWorkflows.set(workflowId, context);
this.logger.info('🚀 Starting OPERA Agent-Driven Testing Workflow', {
workflowId,
changeType: context.changeType,
testingSuite: context.testingSuite
}, 'opera-orchestrator');
try {
// Phase 1: Frontend Analysis (Enhanced James)
let workflowResult = await this.executeJamesAnalysis(context);
// Phase 2: Quality Validation (Enhanced Maria)
if (workflowResult.qualityScore >= 70) {
workflowResult = await this.executeMariaValidation(context, workflowResult);
}
// Phase 3: Agent Handoff Decision
workflowResult.nextSteps = this.determineNextSteps(workflowResult);
// Phase 4: Execute Quality Gates
if (context.qualityGates.performance || context.qualityGates.accessibility) {
workflowResult = await this.executeQualityGates(context, workflowResult);
}
this.activeWorkflows.delete(workflowId);
return workflowResult;
}
catch (error) {
this.logger.error('❌ OPERA Testing Workflow Failed', error, 'opera-orchestrator');
this.activeWorkflows.delete(workflowId);
return {
success: false,
qualityScore: 0,
agent: 'opera-orchestrator',
issues: [{
type: 'critical',
description: `Workflow execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
recommendation: 'Review workflow configuration and agent availability',
agent: 'opera-orchestrator'
}],
recommendations: ['Fix workflow execution issues', 'Check agent system status'],
nextSteps: ['Debug workflow failure', 'Restart agent system if needed']
};
}
}
/**
* Execute Enhanced James frontend analysis
*/
async executeJamesAnalysis(context) {
this.logger.info('🎨 Enhanced James: Frontend Analysis Phase', {
changeType: context.changeType,
components: context.affectedComponents
}, 'enhanced-james');
const jamesContext = {
trigger: 'opera-workflow',
filePath: context.filePath || '',
userRequest: `Analyze ${context.changeType} changes for UI/UX quality`,
contextClarity: 'clear',
urgency: 'high',
testing: true
};
const jamesResponse = await this.jamesFrontend.activate(jamesContext);
return {
success: true,
qualityScore: this.calculateQualityScore(jamesResponse),
agent: 'enhanced-james',
issues: this.convertToWorkflowIssues(jamesResponse),
recommendations: jamesResponse.suggestions.map(s => s.message),
nextSteps: ['Proceed to Enhanced Maria QA validation'],
handoffTo: jamesResponse.handoffTo
};
}
/**
* Execute Enhanced Maria quality validation
*/
async executeMariaValidation(context, previousResult) {
this.logger.info('🔍 Enhanced Maria: Quality Validation Phase', {
previousScore: previousResult.qualityScore,
qualityGates: context.qualityGates
}, 'enhanced-maria');
const mariaContext = {
trigger: 'opera-handoff',
filePath: context.filePath || '',
userRequest: 'Validate UI/UX changes against quality standards',
contextClarity: 'clear',
urgency: 'high',
testing: true
};
const mariaResponse = await this.mariaQA.activate(mariaContext);
// Combine results from both agents
const combinedScore = Math.round((previousResult.qualityScore + this.calculateQualityScore(mariaResponse)) / 2);
return {
success: combinedScore >= 70,
qualityScore: combinedScore,
agent: 'enhanced-maria',
issues: [
...previousResult.issues,
...this.convertToWorkflowIssues(mariaResponse)
],
recommendations: [
...previousResult.recommendations,
...mariaResponse.suggestions.map(s => s.message)
],
nextSteps: this.determineNextSteps({ ...previousResult, qualityScore: combinedScore }),
handoffTo: mariaResponse.handoffTo
};
}
/**
* Execute quality gates based on configuration
*/
async executeQualityGates(context, workflowResult) {
this.logger.info('🚨 Executing Quality Gates', context.qualityGates, 'opera-quality-gates');
const qualityGateResults = [];
// Performance Gate
if (context.qualityGates.performance) {
const performanceScore = await this.executePerformanceGate(context);
qualityGateResults.push({ gate: 'performance', passed: performanceScore >= 90, score: performanceScore });
}
// Accessibility Gate
if (context.qualityGates.accessibility) {
const accessibilityScore = await this.executeAccessibilityGate(context);
qualityGateResults.push({ gate: 'accessibility', passed: accessibilityScore >= 95, score: accessibilityScore });
}
// Visual Regression Gate
if (context.qualityGates.visualRegression) {
const visualScore = await this.executeVisualRegressionGate(context);
qualityGateResults.push({ gate: 'visual', passed: visualScore >= 95, score: visualScore });
}
// Security Gate
if (context.qualityGates.security) {
const securityScore = await this.executeSecurityGate(context);
qualityGateResults.push({ gate: 'security', passed: securityScore >= 90, score: securityScore });
}
// Calculate overall gate score
const gateScore = Math.round(qualityGateResults.reduce((sum, result) => sum + result.score, 0) / qualityGateResults.length);
const allGatesPassed = qualityGateResults.every(result => result.passed);
// Add quality gate issues
const gateIssues = qualityGateResults
.filter(result => !result.passed)
.map(result => ({
type: 'high',
description: `Quality gate failed: ${result.gate} (Score: ${result.score})`,
recommendation: `Improve ${result.gate} to meet quality standards`,
agent: 'opera-quality-gates'
}));
return {
...workflowResult,
success: workflowResult.success && allGatesPassed,
qualityScore: Math.round((workflowResult.qualityScore + gateScore) / 2),
issues: [...workflowResult.issues, ...gateIssues],
recommendations: [
...workflowResult.recommendations,
...qualityGateResults.map(result => `${result.gate} gate: ${result.passed ? '✅ PASSED' : '❌ FAILED'} (${result.score}/100)`)
]
};
}
/**
* Execute performance quality gate
*/
async executePerformanceGate(context) {
// Mock performance testing - in real implementation, this would:
// - Run Lighthouse audits
// - Measure Core Web Vitals
// - Check performance budgets
// - Analyze bundle sizes
this.logger.info('⚡ Performance Quality Gate Executing', { context }, 'performance-gate');
// Simulate performance analysis
const performanceFactors = {
bundleSize: context.changeType === 'component' ? 85 : 95,
renderTime: context.testingSuite === 'performance' ? 90 : 85,
networkOptimization: 90,
coreWebVitals: 88
};
const score = Math.round(Object.values(performanceFactors).reduce((sum, score) => sum + score, 0) / 4);
this.logger.info('📊 Performance Gate Result', { score, factors: performanceFactors }, 'performance-gate');
return score;
}
/**
* Execute accessibility quality gate
*/
async executeAccessibilityGate(context) {
this.logger.info('♿ Accessibility Quality Gate Executing', { context }, 'accessibility-gate');
// Mock accessibility testing - in real implementation, this would:
// - Run axe-core audits
// - Check WCAG compliance
// - Validate keyboard navigation
// - Test screen reader compatibility
const accessibilityFactors = {
wcagCompliance: 95,
keyboardNavigation: 92,
screenReaderCompatibility: 94,
colorContrast: 96
};
const score = Math.round(Object.values(accessibilityFactors).reduce((sum, score) => sum + score, 0) / 4);
this.logger.info('📊 Accessibility Gate Result', { score, factors: accessibilityFactors }, 'accessibility-gate');
return score;
}
/**
* Execute visual regression quality gate
*/
async executeVisualRegressionGate(context) {
this.logger.info('👁️ Visual Regression Quality Gate Executing', { context }, 'visual-gate');
// Mock visual testing - in real implementation, this would:
// - Compare screenshots with baselines
// - Detect pixel differences
// - Analyze layout shifts
// - Check responsive design
const visualFactors = {
pixelAccuracy: context.changeType === 'style' ? 85 : 98,
layoutStability: 95,
responsiveDesign: 92,
crossBrowserConsistency: 90
};
const score = Math.round(Object.values(visualFactors).reduce((sum, score) => sum + score, 0) / 4);
this.logger.info('📊 Visual Regression Gate Result', { score, factors: visualFactors }, 'visual-gate');
return score;
}
/**
* Execute security quality gate
*/
async executeSecurityGate(context) {
this.logger.info('🔒 Security Quality Gate Executing', { context }, 'security-gate');
// Mock security testing - in real implementation, this would:
// - Scan for XSS vulnerabilities
// - Check CSP headers
// - Validate authentication
// - Test authorization
const securityFactors = {
xssProtection: 95,
cspHeaders: 90,
authenticationSecurity: 92,
dataValidation: 88
};
const score = Math.round(Object.values(securityFactors).reduce((sum, score) => sum + score, 0) / 4);
this.logger.info('📊 Security Gate Result', { score, factors: securityFactors }, 'security-gate');
return score;
}
/**
* Helper methods
*/
calculateQualityScore(agentResponse) {
// Convert agent response to quality score
const priorityWeights = { critical: 0, high: 20, medium: 50, low: 80 };
const baseScore = 100;
const deductions = agentResponse.suggestions.reduce((total, suggestion) => {
const weight = priorityWeights[suggestion.priority] ?? 50;
return total + (100 - weight);
}, 0);
return Math.max(0, Math.round(baseScore - deductions));
}
convertToWorkflowIssues(agentResponse) {
return agentResponse.suggestions.map(suggestion => ({
type: suggestion.priority,
description: suggestion.message,
recommendation: suggestion.message,
agent: agentResponse.agentId
}));
}
determineNextSteps(result) {
const steps = [];
if (result.qualityScore < 70) {
steps.push('🚨 CRITICAL: Address quality issues before proceeding');
steps.push('Fix critical and high priority issues');
}
if (result.qualityScore >= 70 && result.qualityScore < 90) {
steps.push('⚠️ Address medium priority issues for production readiness');
steps.push('Run additional quality gates');
}
if (result.qualityScore >= 90) {
steps.push('✅ Quality standards met - ready for deployment');
steps.push('Execute final integration tests');
}
return steps;
}
/**
* Get active workflow status
*/
getActiveWorkflows() {
return Array.from(this.activeWorkflows.entries()).map(([id, context]) => ({ id, context }));
}
/**
* Cancel workflow
*/
cancelWorkflow(workflowId) {
return this.activeWorkflows.delete(workflowId);
}
}
export default OPERATestingOrchestrator;
//# sourceMappingURL=bmad-testing-orchestrator.js.map