Skip to main content
Glama

Fork Parity MCP

by moikas-code
triage.jsβ€’10.1 kB
// Smart triage system for fork parity analysis class SmartTriageSystem { constructor() { // Keywords for different categories and priorities this.patterns = { security: { keywords: ['security', 'vulnerability', 'exploit', 'cve', 'xss', 'csrf', 'injection', 'auth', 'permission', 'sanitize', 'escape'], priority: 'critical', confidence: 0.9 }, bugfix: { keywords: ['fix', 'bug', 'issue', 'error', 'crash', 'fail', 'broken', 'incorrect', 'wrong', 'patch'], priority: 'high', confidence: 0.8 }, feature: { keywords: ['add', 'new', 'feature', 'implement', 'support', 'enable', 'introduce'], priority: 'medium', confidence: 0.7 }, refactor: { keywords: ['refactor', 'cleanup', 'reorganize', 'restructure', 'optimize', 'improve', 'simplify'], priority: 'low', confidence: 0.6 }, docs: { keywords: ['doc', 'readme', 'comment', 'documentation', 'guide', 'example', 'tutorial'], priority: 'low', confidence: 0.9 }, test: { keywords: ['test', 'spec', 'coverage', 'mock', 'stub', 'fixture'], priority: 'low', confidence: 0.8 }, chore: { keywords: ['chore', 'update', 'bump', 'version', 'dependency', 'build', 'ci', 'lint'], priority: 'low', confidence: 0.7 } }; // File patterns that indicate impact areas this.impactPatterns = { 'core': [/^src\/core/, /^lib\/core/, /^core\//], 'api': [/api/, /endpoint/, /route/, /controller/], 'ui': [/component/, /view/, /ui/, /frontend/, /client/], 'database': [/migration/, /schema/, /model/, /db/, /database/], 'auth': [/auth/, /login/, /permission/, /security/], 'config': [/config/, /setting/, /env/, /\.env/], 'build': [/webpack/, /rollup/, /vite/, /build/, /package\.json/, /Dockerfile/], 'test': [/test/, /spec/, /__tests__/], 'docs': [/readme/, /doc/, /\.md$/] }; // Effort estimation based on file changes and complexity this.effortPatterns = { trivial: { maxFiles: 2, maxLines: 10 }, small: { maxFiles: 5, maxLines: 50 }, medium: { maxFiles: 15, maxLines: 200 }, large: { maxFiles: 30, maxLines: 500 } }; } /** * Analyze a commit and generate triage results */ analyzeCommit(commitData) { const message = commitData.message.toLowerCase(); const filesChanged = commitData.filesChanged || []; const totalLines = (commitData.insertions || 0) + (commitData.deletions || 0); // Determine category and base priority const categoryResult = this.categorizeCommit(message, filesChanged); // Determine impact areas const impactAreas = this.determineImpactAreas(filesChanged); // Estimate effort const effortEstimate = this.estimateEffort(filesChanged.length, totalLines); // Calculate conflict risk const conflictRisk = this.calculateConflictRisk(filesChanged, impactAreas); // Adjust priority based on impact and risk const adjustedPriority = this.adjustPriority( categoryResult.priority, impactAreas, conflictRisk, effortEstimate ); // Generate reasoning const reasoning = this.generateReasoning( categoryResult, impactAreas, effortEstimate, conflictRisk, adjustedPriority ); return { priority: adjustedPriority, category: categoryResult.category, impactAreas, conflictRisk, effortEstimate, reasoning, confidence: categoryResult.confidence }; } /** * Categorize commit based on message and files */ categorizeCommit(message, filesChanged) { let bestMatch = { category: 'chore', priority: 'low', confidence: 0.3 }; // Check each pattern category for (const [category, pattern] of Object.entries(this.patterns)) { const matchCount = pattern.keywords.filter(keyword => message.includes(keyword) ).length; if (matchCount > 0) { const confidence = Math.min(0.9, pattern.confidence + (matchCount - 1) * 0.1); if (confidence > bestMatch.confidence) { bestMatch = { category, priority: pattern.priority, confidence }; } } } // Special handling for security-related files const hasSecurityFiles = filesChanged.some(file => /auth|security|permission|login/.test(file.toLowerCase()) ); if (hasSecurityFiles && bestMatch.category !== 'security') { bestMatch.priority = this.escalatePriority(bestMatch.priority); } return bestMatch; } /** * Determine which areas of the codebase are impacted */ determineImpactAreas(filesChanged) { const impactAreas = new Set(); for (const file of filesChanged) { for (const [area, patterns] of Object.entries(this.impactPatterns)) { if (patterns.some(pattern => pattern.test(file))) { impactAreas.add(area); } } } return Array.from(impactAreas); } /** * Estimate effort required for integration */ estimateEffort(fileCount, lineCount) { for (const [effort, limits] of Object.entries(this.effortPatterns)) { if (fileCount <= limits.maxFiles && lineCount <= limits.maxLines) { return effort; } } return 'xl'; } /** * Calculate risk of conflicts during integration */ calculateConflictRisk(filesChanged, impactAreas) { let risk = 0.1; // Base risk // Higher risk for core areas if (impactAreas.includes('core')) risk += 0.3; if (impactAreas.includes('api')) risk += 0.2; if (impactAreas.includes('database')) risk += 0.25; // Risk based on number of files risk += Math.min(0.3, filesChanged.length * 0.02); // Risk for commonly modified files const commonFiles = ['package.json', 'README.md', 'config.js', 'index.js']; const hasCommonFiles = filesChanged.some(file => commonFiles.some(common => file.includes(common)) ); if (hasCommonFiles) risk += 0.15; return Math.min(1.0, risk); } /** * Adjust priority based on various factors */ adjustPriority(basePriority, impactAreas, conflictRisk, effortEstimate) { let priority = basePriority; // Escalate if affecting core systems if (impactAreas.includes('core') || impactAreas.includes('auth')) { priority = this.escalatePriority(priority); } // Escalate high-risk changes if (conflictRisk > 0.7) { priority = this.escalatePriority(priority); } // De-escalate trivial changes unless they're security-related if (effortEstimate === 'trivial' && priority !== 'critical') { priority = this.deescalatePriority(priority); } return priority; } /** * Generate human-readable reasoning for the triage decision */ generateReasoning(categoryResult, impactAreas, effortEstimate, conflictRisk, finalPriority) { const parts = []; parts.push(`Categorized as ${categoryResult.category} based on commit message`); if (impactAreas.length > 0) { parts.push(`affects ${impactAreas.join(', ')} areas`); } parts.push(`estimated ${effortEstimate} effort`); if (conflictRisk > 0.5) { parts.push(`high conflict risk (${Math.round(conflictRisk * 100)}%)`); } if (finalPriority !== categoryResult.priority) { parts.push(`priority adjusted from ${categoryResult.priority} to ${finalPriority}`); } return parts.join(', '); } /** * Batch analyze multiple commits */ batchAnalyze(commits) { return commits.map(commit => ({ hash: commit.hash, triage: this.analyzeCommit(commit) })); } /** * Helper methods for priority adjustment */ escalatePriority(priority) { const escalation = { 'low': 'medium', 'medium': 'high', 'high': 'critical' }; return escalation[priority] || priority; } deescalatePriority(priority) { const deescalation = { 'critical': 'high', 'high': 'medium', 'medium': 'low' }; return deescalation[priority] || priority; } /** * Get actionable items based on priority and status */ getActionableItems(commits, options = {}) { const { minPriority = 'medium', maxItems = 20 } = options; const priorityOrder = { 'critical': 4, 'high': 3, 'medium': 2, 'low': 1 }; return commits .filter(commit => { const triage = commit.triage || this.analyzeCommit(commit); return priorityOrder[triage.priority] >= priorityOrder[minPriority]; }) .sort((a, b) => { const aPriority = (a.triage || this.analyzeCommit(a)).priority; const bPriority = (b.triage || this.analyzeCommit(b)).priority; return priorityOrder[bPriority] - priorityOrder[aPriority]; }) .slice(0, maxItems); } /** * Generate integration recommendations */ generateIntegrationPlan(commits) { const analyzed = this.batchAnalyze(commits); const critical = analyzed.filter(c => c.triage.priority === 'critical'); const high = analyzed.filter(c => c.triage.priority === 'high'); const medium = analyzed.filter(c => c.triage.priority === 'medium'); const low = analyzed.filter(c => c.triage.priority === 'low'); return { immediate: critical.concat(high.slice(0, 3)), nextSprint: high.slice(3).concat(medium.slice(0, 5)), backlog: medium.slice(5).concat(low), summary: { totalCommits: commits.length, criticalCount: critical.length, highCount: high.length, mediumCount: medium.length, lowCount: low.length, estimatedEffort: this.calculateTotalEffort(analyzed) } }; } calculateTotalEffort(analyzedCommits) { const effortPoints = { trivial: 1, small: 3, medium: 8, large: 20, xl: 40 }; return analyzedCommits.reduce((total, commit) => { return total + (effortPoints[commit.triage.effortEstimate] || 0); }, 0); } } export default SmartTriageSystem;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/moikas-code/fork-parity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server