UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

360 lines (326 loc) 10.8 kB
/** * Focus Area Recommender * * Generates strategic focus area recommendations for human review: * - Architecture decisions * - Business logic * - Security considerations * - UX/UI implications * * @module core/quality-gates/focus-area-recommender * @version 1.0.0 * @story 3.5 - Human Review Orchestration (Layer 3) */ /** * Focus Area Recommender * Generates intelligent focus areas based on code changes and context */ class FocusAreaRecommender { /** * Create a new recommender * @param {Object} config - Recommender configuration */ constructor(config = {}) { this.config = config; this.strategicAreas = config.strategicAreas || [ 'architecture', 'business-logic', 'security', 'ux', 'performance', 'data-integrity', ]; this.skipAreas = config.skipAreas || [ 'syntax', 'formatting', 'simple-logic', 'naming-conventions', 'import-order', ]; } /** * Generate focus area recommendations * @param {Object} context - Recommendation context * @returns {Promise<Object>} Focus area recommendations */ async recommend(context = {}) { const { prContext = {}, layer1Result: _layer1Result = {}, layer2Result = {} } = context; const recommendations = { primary: [], secondary: [], skip: this.skipAreas, summary: '', highlightedAspects: [], }; // Analyze changed files const fileAnalysis = this.analyzeChangedFiles(prContext.changedFiles || []); recommendations.highlightedAspects.push(...fileAnalysis.highlights); // Add primary focus areas recommendations.primary = this.determinePrimaryAreas(fileAnalysis, layer2Result); // Add secondary focus areas recommendations.secondary = this.determineSecondaryAreas(fileAnalysis, layer2Result); // Generate summary recommendations.summary = this.generateSummary(recommendations); return recommendations; } /** * Analyze changed files to determine focus areas * @param {Array} changedFiles - List of changed file paths * @returns {Object} File analysis results */ analyzeChangedFiles(changedFiles = []) { const analysis = { categories: {}, patterns: [], highlights: [], riskLevel: 'low', }; const categoryPatterns = [ { pattern: /\.(api|routes|endpoints)\./i, category: 'api', highlight: 'API endpoint changes detected', risk: 'high', }, { pattern: /auth|login|password|token|jwt|session/i, category: 'security', highlight: 'Security-sensitive code changes', risk: 'critical', }, { pattern: /database|migration|schema|model/i, category: 'data-integrity', highlight: 'Database/data model changes', risk: 'high', }, { pattern: /component|page|view|ui|layout/i, category: 'ux', highlight: 'UI/UX component changes', risk: 'medium', }, { pattern: /service|handler|controller|manager/i, category: 'business-logic', highlight: 'Business logic changes', risk: 'high', }, { pattern: /config|settings|env|yaml|json/i, category: 'configuration', highlight: 'Configuration changes', risk: 'medium', }, { pattern: /core|base|abstract|interface/i, category: 'architecture', highlight: 'Core architecture changes', risk: 'critical', }, { pattern: /agent|workflow|task|orchestrat/i, category: 'aios-core', highlight: 'AIOS framework changes', risk: 'high', }, { pattern: /cache|performance|optimi/i, category: 'performance', highlight: 'Performance-related changes', risk: 'medium', }, ]; // Analyze each file changedFiles.forEach((file) => { categoryPatterns.forEach(({ pattern, category, highlight, risk }) => { if (pattern.test(file)) { if (!analysis.categories[category]) { analysis.categories[category] = []; analysis.highlights.push(highlight); } analysis.categories[category].push(file); // Update risk level if (risk === 'critical') analysis.riskLevel = 'critical'; else if (risk === 'high' && analysis.riskLevel !== 'critical') { analysis.riskLevel = 'high'; } else if (risk === 'medium' && analysis.riskLevel === 'low') { analysis.riskLevel = 'medium'; } } }); }); return analysis; } /** * Determine primary focus areas * @param {Object} fileAnalysis - File analysis results * @param {Object} layer2Result - Layer 2 results * @returns {Array} Primary focus areas */ determinePrimaryAreas(fileAnalysis, layer2Result) { const primary = []; // Priority order for categories const priorityOrder = [ 'security', 'architecture', 'data-integrity', 'business-logic', 'api', ]; // Add categories based on file analysis priorityOrder.forEach((cat) => { if (fileAnalysis.categories[cat]?.length > 0) { primary.push({ area: cat, reason: `${fileAnalysis.categories[cat].length} file(s) in ${cat} area modified`, files: fileAnalysis.categories[cat].slice(0, 5), questions: this.getReviewQuestions(cat), }); } }); // Add areas based on CodeRabbit issues const coderabbitResult = layer2Result?.results?.find((r) => r.check === 'coderabbit'); if (coderabbitResult?.issues) { if (coderabbitResult.issues.high > 0) { const existingBusinessLogic = primary.find((p) => p.area === 'business-logic'); if (!existingBusinessLogic) { primary.push({ area: 'code-quality', reason: `${coderabbitResult.issues.high} HIGH severity issues from CodeRabbit`, questions: [ 'Are the HIGH severity issues acceptable tradeoffs?', 'Do these issues indicate deeper architectural problems?', ], }); } } } // Limit to top 3 primary areas return primary.slice(0, 3); } /** * Determine secondary focus areas * @param {Object} fileAnalysis - File analysis results * @param {Object} layer2Result - Layer 2 results * @returns {Array} Secondary focus areas */ determineSecondaryAreas(fileAnalysis, _layer2Result) { const secondary = []; // Lower priority categories const secondaryCategories = ['ux', 'configuration', 'performance', 'aios-core']; secondaryCategories.forEach((cat) => { if (fileAnalysis.categories[cat]?.length > 0) { secondary.push({ area: cat, reason: `${fileAnalysis.categories[cat].length} file(s) modified`, files: fileAnalysis.categories[cat].slice(0, 3), }); } }); // Limit to top 2 secondary areas return secondary.slice(0, 2); } /** * Get review questions for a category * @param {string} category - Category name * @returns {Array} Review questions */ getReviewQuestions(category) { const questionBank = { security: [ 'Are authentication and authorization properly implemented?', 'Is sensitive data properly encrypted/protected?', 'Are there any potential injection vulnerabilities?', 'Is input validation comprehensive?', ], architecture: [ 'Does this align with our architectural principles?', 'Are dependencies properly managed?', 'Is the separation of concerns maintained?', 'Will this scale appropriately?', ], 'data-integrity': [ 'Are database migrations reversible?', 'Is data validation comprehensive?', 'Are there potential data consistency issues?', 'Is the schema design appropriate?', ], 'business-logic': [ 'Does this correctly implement the business requirements?', 'Are edge cases handled appropriately?', 'Is the logic testable and maintainable?', 'Are business rules properly enforced?', ], api: [ 'Is the API design consistent with existing endpoints?', 'Are breaking changes properly documented?', 'Is error handling comprehensive?', 'Is the API versioned appropriately?', ], ux: [ 'Is the user experience consistent?', 'Are accessibility requirements met?', 'Is the interface responsive?', 'Are error states handled gracefully?', ], performance: [ 'Are there potential performance bottlenecks?', 'Is caching used appropriately?', 'Are expensive operations optimized?', 'Is the memory footprint acceptable?', ], 'aios-core': [ 'Does this follow AIOS framework patterns?', 'Is backward compatibility maintained?', 'Are agent/task contracts preserved?', 'Is the change properly documented?', ], }; return questionBank[category] || [ 'Is this change necessary and well-implemented?', 'Are there any potential issues or risks?', ]; } /** * Generate summary of focus recommendations * @param {Object} recommendations - Focus recommendations * @returns {string} Summary text */ generateSummary(recommendations) { const parts = []; if (recommendations.primary.length > 0) { parts.push(`Focus on ${recommendations.primary.length} strategic area(s):`); recommendations.primary.forEach((p) => { parts.push(` • ${p.area}: ${p.reason}`); }); } if (recommendations.highlightedAspects.length > 0) { parts.push('\nKey aspects:'); recommendations.highlightedAspects.forEach((h) => { parts.push(` ⚡ ${h}`); }); } parts.push(`\nSkip automated-covered areas: ${recommendations.skip.join(', ')}`); return parts.join('\n'); } /** * Calculate strategic review priority * @param {Object} recommendations - Focus recommendations * @returns {string} Priority level (P0, P1, P2) */ calculatePriority(recommendations) { const criticalAreas = ['security', 'architecture', 'data-integrity']; const highAreas = ['business-logic', 'api']; const hasCritical = recommendations.primary.some((p) => criticalAreas.includes(p.area), ); const hasHigh = recommendations.primary.some((p) => highAreas.includes(p.area), ); if (hasCritical) return 'P0'; if (hasHigh) return 'P1'; return 'P2'; } } module.exports = { FocusAreaRecommender };