Skip to main content
Glama

Fork Parity MCP

by moikas-code
integration-helpers.js49.9 kB
// Integration helpers for conflict resolution, adaptation patterns, and migration planning import { execSync } from 'child_process'; import { readFileSync, existsSync, writeFileSync } from 'fs'; import { join, dirname, basename, extname } from 'path'; class IntegrationHelpersSystem { constructor(database) { this.db = database; // Common conflict patterns and their resolutions this.conflictPatterns = { imports: { pattern: /^<<<<<<< HEAD\n(import.*\n)*=======\n(import.*\n)*>>>>>>> /gm, resolver: 'mergeImports', description: 'Import statement conflicts' }, dependencies: { pattern: /^<<<<<<< HEAD\n.*"dependencies".*\n.*=======\n.*"dependencies".*\n.*>>>>>>> /gm, resolver: 'mergeDependencies', description: 'Package dependency conflicts' }, config: { pattern: /^<<<<<<< HEAD\n.*config.*\n.*=======\n.*config.*\n.*>>>>>>> /gm, resolver: 'mergeConfig', description: 'Configuration conflicts' }, functions: { pattern: /^<<<<<<< HEAD\n(.*function.*\{[\s\S]*?\})\n=======\n(.*function.*\{[\s\S]*?\})\n>>>>>>> /gm, resolver: 'analyzeFunctionConflict', description: 'Function implementation conflicts' } }; // Adaptation patterns learned from previous integrations this.adaptationPatterns = new Map(); this.loadAdaptationPatterns(); } /** * Create detailed migration plan */ createMigrationPlan(commitData, analysisResults, repositoryPath) { const plan = { phases: [], estimatedEffort: 'medium', risks: [], prerequisites: [], timeline: {}, rollbackPlan: {}, testingStrategy: {} }; try { // Phase 1: Preparation const preparationPhase = { name: 'Preparation', order: 1, tasks: [ 'Create feature branch for integration', 'Backup current state', 'Review commit changes thoroughly' ], estimatedTime: '1-2 hours', dependencies: [] }; // Add specific preparation tasks based on analysis if (analysisResults.dependencyAnalysis?.packageChanges?.length > 0) { preparationPhase.tasks.push('Review dependency changes and compatibility'); preparationPhase.tasks.push('Update local development environment'); } if (analysisResults.securityAnalysis?.requiresSecurityReview) { preparationPhase.tasks.push('Schedule security review'); preparationPhase.prerequisites = ['Security team approval']; } plan.phases.push(preparationPhase); // Phase 2: Integration const integrationPhase = { name: 'Integration', order: 2, tasks: [], estimatedTime: '2-4 hours', dependencies: ['Preparation'] }; // Determine integration approach if (analysisResults.conflicts?.hasConflicts) { integrationPhase.tasks.push('Resolve merge conflicts manually'); integrationPhase.tasks.push('Apply adaptation patterns'); integrationPhase.estimatedTime = '4-8 hours'; plan.risks.push({ type: 'conflict_resolution', description: 'Manual conflict resolution required', severity: 'medium', mitigation: 'Use automated resolution suggestions where possible' }); } else { integrationPhase.tasks.push('Apply commit via cherry-pick or merge'); integrationPhase.tasks.push('Verify no unintended changes'); } // Add breaking change handling if (analysisResults.breakingChanges?.hasBreakingChanges) { integrationPhase.tasks.push('Implement breaking change adaptations'); integrationPhase.tasks.push('Update dependent code'); integrationPhase.estimatedTime = '6-12 hours'; plan.risks.push({ type: 'breaking_changes', description: 'Breaking changes require code adaptations', severity: 'high', mitigation: 'Follow established adaptation patterns' }); } plan.phases.push(integrationPhase); // Phase 3: Testing const testingPhase = { name: 'Testing', order: 3, tasks: [ 'Run existing test suite', 'Perform manual testing of affected areas', 'Verify no regressions introduced' ], estimatedTime: '2-4 hours', dependencies: ['Integration'] }; // Add specific testing based on analysis if (analysisResults.performanceAnalysis?.requiresPerformanceTest) { testingPhase.tasks.push('Run performance benchmarks'); testingPhase.tasks.push('Compare performance metrics'); testingPhase.estimatedTime = '4-6 hours'; } if (analysisResults.securityAnalysis?.requiresSecurityReview) { testingPhase.tasks.push('Run security scans'); testingPhase.tasks.push('Verify security controls'); } plan.phases.push(testingPhase); // Phase 4: Deployment const deploymentPhase = { name: 'Deployment', order: 4, tasks: [ 'Deploy to staging environment', 'Perform smoke tests', 'Monitor for issues' ], estimatedTime: '1-2 hours', dependencies: ['Testing'] }; if (analysisResults.breakingChanges?.migrationRequired) { deploymentPhase.tasks.unshift('Execute database migrations'); deploymentPhase.tasks.push('Verify migration success'); plan.prerequisites.push('Database backup completed'); plan.risks.push({ type: 'migration_failure', description: 'Database migration could fail', severity: 'critical', mitigation: 'Test migration on staging first, have rollback plan ready' }); } plan.phases.push(deploymentPhase); // Calculate total effort const totalHours = plan.phases.reduce((total, phase) => { const hours = this.parseTimeEstimate(phase.estimatedTime); return total + hours; }, 0); if (totalHours <= 8) { plan.estimatedEffort = 'small'; } else if (totalHours <= 16) { plan.estimatedEffort = 'medium'; } else if (totalHours <= 32) { plan.estimatedEffort = 'large'; } else { plan.estimatedEffort = 'xl'; } // Create timeline plan.timeline = { totalEstimatedTime: `${totalHours} hours`, phases: plan.phases.map(phase => ({ name: phase.name, estimatedTime: phase.estimatedTime, dependencies: phase.dependencies })) }; // Create rollback plan plan.rollbackPlan = { triggers: [ 'Critical bugs discovered', 'Performance degradation > 20%', 'Security vulnerabilities introduced' ], steps: [ 'Revert commit from main branch', 'Redeploy previous version', 'Verify system stability', 'Notify stakeholders' ], estimatedTime: '30 minutes' }; // Create testing strategy plan.testingStrategy = { automated: [ 'Unit tests', 'Integration tests', 'End-to-end tests' ], manual: [ 'User acceptance testing', 'Exploratory testing', 'Performance testing' ], criteria: [ 'All tests pass', 'No performance regression', 'Security scans clean' ] }; } catch (error) { plan.error = `Migration planning failed: ${error.message}`; plan.estimatedEffort = 'unknown'; } return plan; } /** * Generate conflict resolution suggestions */ generateConflictResolutions(conflictData) { const resolutions = []; for (const conflict of conflictData.conflicts) { const resolution = { file: conflict.file, type: conflict.type, suggestions: [] }; // Apply pattern-based resolution for (const [patternName, pattern] of Object.entries(this.conflictPatterns)) { if (conflict.content && pattern.pattern.test(conflict.content)) { const suggestion = this[pattern.resolver](conflict); if (suggestion) { resolution.suggestions.push({ method: patternName, description: pattern.description, resolution: suggestion, confidence: this.calculateResolutionConfidence(patternName, conflict) }); } } } // Check adaptation patterns const adaptationSuggestion = this.findAdaptationPattern(conflict); if (adaptationSuggestion) { resolution.suggestions.push(adaptationSuggestion); } resolutions.push(resolution); } return { resolutions, recommendedApproach: this.recommendIntegrationApproach(resolutions), automationPossible: this.assessAutomationPossibility(resolutions) }; } /** * Analyze code similarity for adaptation guidance */ analyzeCodeSimilarity(commitData, repositoryPath) { const similarities = []; const changedFiles = commitData.filesChanged || []; try { // Get historical commits for similarity analysis const historicalCommits = this.getHistoricalCommits(repositoryPath); for (const file of changedFiles) { const filePath = join(repositoryPath, file); if (!existsSync(filePath)) continue; const currentContent = readFileSync(filePath, 'utf8'); const similarChanges = this.findSimilarChanges(file, currentContent, historicalCommits, repositoryPath); if (similarChanges.length > 0) { similarities.push({ file, similarChanges: similarChanges.slice(0, 5), // Top 5 similar changes adaptationGuidance: this.generateAdaptationGuidance(similarChanges) }); } } return { hasSimilarChanges: similarities.length > 0, similarities, overallGuidance: this.generateOverallGuidance(similarities) }; } catch (error) { return { hasSimilarChanges: false, similarities: [], error: `Similarity analysis failed: ${error.message}`, overallGuidance: 'No similar changes found for guidance.' }; } } /** * Create detailed migration path planning */ createMigrationPlan(commitData, analysisResults, repositoryPath) { const plan = { phases: [], totalEstimatedTime: 0, riskAssessment: 'low', prerequisites: [], rollbackPlan: [], testingStrategy: [] }; // Phase 1: Preparation const prepPhase = { name: 'Preparation', tasks: [ 'Create feature branch for integration', 'Backup current state', 'Review dependency changes' ], estimatedTime: '30 minutes', dependencies: [] }; // Add dependency analysis tasks if (analysisResults.dependencyAnalysis?.complexity !== 'minimal') { prepPhase.tasks.push('Analyze dependency impact'); prepPhase.tasks.push('Update affected modules'); } plan.phases.push(prepPhase); // Phase 2: Core Integration const integrationPhase = { name: 'Core Integration', tasks: [], estimatedTime: '1-2 hours', dependencies: ['Preparation'] }; // Add tasks based on analysis results if (analysisResults.breakingChanges?.hasBreakingChanges) { integrationPhase.tasks.push('Handle breaking changes'); integrationPhase.tasks.push('Update API interfaces'); } if (analysisResults.conflicts?.hasConflicts) { integrationPhase.tasks.push('Resolve merge conflicts'); integrationPhase.tasks.push('Apply conflict resolutions'); } integrationPhase.tasks.push('Apply upstream changes'); integrationPhase.tasks.push('Run initial tests'); plan.phases.push(integrationPhase); // Phase 3: Adaptation const adaptationPhase = { name: 'Adaptation', tasks: [ 'Apply fork-specific adaptations', 'Update custom features', 'Resolve integration issues' ], estimatedTime: '2-4 hours', dependencies: ['Core Integration'] }; // Add adaptation tasks based on patterns const adaptationPatterns = this.getRelevantAdaptationPatterns(commitData); for (const pattern of adaptationPatterns) { adaptationPhase.tasks.push(`Apply ${pattern.name} adaptation pattern`); } plan.phases.push(adaptationPhase); // Phase 4: Testing & Validation const testingPhase = { name: 'Testing & Validation', tasks: [ 'Run unit tests', 'Run integration tests', 'Perform manual testing', 'Validate performance' ], estimatedTime: '1-3 hours', dependencies: ['Adaptation'] }; // Add specific testing based on analysis if (analysisResults.securityAnalysis?.hasSecurityImpact) { testingPhase.tasks.push('Security testing'); } if (analysisResults.performanceAnalysis?.hasPerformanceImpact) { testingPhase.tasks.push('Performance benchmarking'); } plan.phases.push(testingPhase); // Calculate total time and risk plan.totalEstimatedTime = this.calculateTotalTime(plan.phases); plan.riskAssessment = this.assessMigrationRisk(analysisResults); plan.prerequisites = this.generatePrerequisites(analysisResults); plan.rollbackPlan = this.generateRollbackPlan(commitData); plan.testingStrategy = this.generateTestingStrategy(analysisResults); return plan; } /** * Learn and store adaptation patterns */ learnAdaptationPattern(commitHash, adaptationData) { const pattern = { id: `pattern_${Date.now()}`, commitHash, patternType: adaptationData.type, sourcePattern: adaptationData.sourcePattern, targetPattern: adaptationData.targetPattern, context: adaptationData.context, success: adaptationData.success, effort: adaptationData.effort, notes: adaptationData.notes, createdAt: new Date().toISOString() }; // Store in database try { const stmt = this.db.db.prepare(` INSERT INTO adaptation_patterns (pattern_id, commit_hash, pattern_type, source_pattern, target_pattern, context, success, effort, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); stmt.run( pattern.id, pattern.commitHash, pattern.patternType, pattern.sourcePattern, pattern.targetPattern, JSON.stringify(pattern.context), pattern.success ? 1 : 0, pattern.effort, pattern.notes, pattern.createdAt ); // Update in-memory cache this.adaptationPatterns.set(pattern.id, pattern); return pattern; } catch (error) { console.error('Failed to store adaptation pattern:', error); return null; } } // Helper methods async simulateMerge(commitHash, repositoryPath) { try { // Create a temporary branch for simulation const tempBranch = `temp_merge_${Date.now()}`; execSync(`git checkout -b ${tempBranch}`, { cwd: repositoryPath, stdio: 'ignore' }); try { // Attempt merge execSync(`git merge ${commitHash}`, { cwd: repositoryPath, stdio: 'ignore' }); // Clean up execSync('git checkout -', { cwd: repositoryPath, stdio: 'ignore' }); execSync(`git branch -D ${tempBranch}`, { cwd: repositoryPath, stdio: 'ignore' }); return { hasConflicts: false, conflictFiles: [] }; } catch (mergeError) { // Get conflict files const statusOutput = execSync('git status --porcelain', { cwd: repositoryPath, encoding: 'utf8' }); const conflictFiles = statusOutput .split('\n') .filter(line => line.startsWith('UU ')) .map(line => line.substring(3)); // Clean up execSync('git merge --abort', { cwd: repositoryPath, stdio: 'ignore' }); execSync('git checkout -', { cwd: repositoryPath, stdio: 'ignore' }); execSync(`git branch -D ${tempBranch}`, { cwd: repositoryPath, stdio: 'ignore' }); return { hasConflicts: true, conflictFiles }; } } catch (error) { return { hasConflicts: false, conflictFiles: [], error: error.message }; } } async analyzeFileConflicts(filePath, repositoryPath) { try { const fullPath = join(repositoryPath, filePath); const content = readFileSync(fullPath, 'utf8'); const conflictMarkers = content.match(/^<<<<<<< HEAD[\s\S]*?>>>>>>> /gm) || []; return { file: filePath, type: 'merge-conflict', conflictCount: conflictMarkers.length, content: content, conflicts: conflictMarkers.map(marker => this.parseConflictMarker(marker)) }; } catch (error) { return { file: filePath, type: 'file-error', error: error.message }; } } analyzeSemanticConflicts(changedFiles, repositoryPath) { const semanticConflicts = []; // Check for potential semantic conflicts for (const file of changedFiles) { try { const filePath = join(repositoryPath, file); if (!existsSync(filePath)) continue; const content = readFileSync(filePath, 'utf8'); // Check for function signature changes const functionChanges = this.detectFunctionSignatureChanges(content, file); if (functionChanges.length > 0) { semanticConflicts.push({ file, type: 'function-signature', changes: functionChanges, impact: 'high' }); } // Check for API changes const apiChanges = this.detectAPIChanges(content, file); if (apiChanges.length > 0) { semanticConflicts.push({ file, type: 'api-change', changes: apiChanges, impact: 'medium' }); } } catch (error) { continue; } } return semanticConflicts; } generateResolutionSuggestions(conflicts) { const suggestions = []; for (const conflict of conflicts) { if (conflict.type === 'merge-conflict') { suggestions.push({ file: conflict.file, suggestion: 'Use three-way merge tool to resolve conflicts', priority: 'high', estimatedTime: '15-30 minutes' }); } else if (conflict.type === 'function-signature') { suggestions.push({ file: conflict.file, suggestion: 'Update function calls to match new signature', priority: 'high', estimatedTime: '30-60 minutes' }); } else if (conflict.type === 'api-change') { suggestions.push({ file: conflict.file, suggestion: 'Review API changes and update client code', priority: 'medium', estimatedTime: '1-2 hours' }); } } return suggestions; } estimateResolutionTime(conflicts) { let totalMinutes = 0; for (const conflict of conflicts) { switch (conflict.type) { case 'merge-conflict': totalMinutes += conflict.conflictCount * 15; break; case 'function-signature': totalMinutes += conflict.changes.length * 30; break; case 'api-change': totalMinutes += conflict.changes.length * 60; break; default: totalMinutes += 30; } } if (totalMinutes < 60) { return `${totalMinutes} minutes`; } else { const hours = Math.ceil(totalMinutes / 60); return `${hours} hour${hours > 1 ? 's' : ''}`; } } // Conflict resolution methods mergeImports(conflict) { // Extract imports from both sides const headImports = this.extractImports(conflict.headContent); const incomingImports = this.extractImports(conflict.incomingContent); // Merge and deduplicate const mergedImports = [...new Set([...headImports, ...incomingImports])]; return { type: 'automatic', resolution: mergedImports.join('\n'), confidence: 0.9 }; } mergeDependencies(conflict) { try { const headDeps = JSON.parse(conflict.headContent); const incomingDeps = JSON.parse(conflict.incomingContent); // Merge dependencies, preferring newer versions const merged = { ...headDeps }; for (const [pkg, version] of Object.entries(incomingDeps)) { if (!merged[pkg] || this.compareVersions(version, merged[pkg]) > 0) { merged[pkg] = version; } } return { type: 'automatic', resolution: JSON.stringify(merged, null, 2), confidence: 0.8 }; } catch (error) { return { type: 'manual', resolution: 'Manual review required for dependency conflicts', confidence: 0.3 }; } } mergeConfig(conflict) { // Basic config merging - prefer incoming for new keys, keep existing for conflicts return { type: 'manual', resolution: 'Review configuration changes manually', confidence: 0.5, suggestion: 'Compare configurations and merge non-conflicting changes' }; } analyzeFunctionConflict(conflict) { // Analyze function differences const headFunc = this.parseFunctionSignature(conflict.headContent); const incomingFunc = this.parseFunctionSignature(conflict.incomingContent); if (headFunc && incomingFunc) { if (headFunc.name === incomingFunc.name) { return { type: 'signature-change', resolution: 'Function signature changed - review parameters and return type', confidence: 0.7, details: { headSignature: headFunc.signature, incomingSignature: incomingFunc.signature } }; } } return { type: 'manual', resolution: 'Manual review required for function conflicts', confidence: 0.4 }; } calculateResolutionConfidence(patternName, conflict) { const baseConfidence = { imports: 0.9, dependencies: 0.8, config: 0.5, functions: 0.6 }; return baseConfidence[patternName] || 0.5; } findAdaptationPattern(conflict) { // Search for similar patterns in adaptation history for (const [id, pattern] of this.adaptationPatterns) { if (this.isPatternApplicable(pattern, conflict)) { return { method: 'adaptation-pattern', description: `Similar pattern found: ${pattern.patternType}`, resolution: pattern.targetPattern, confidence: pattern.success ? 0.8 : 0.6, patternId: id, notes: pattern.notes }; } } return null; } isPatternApplicable(pattern, conflict) { // Simple similarity check - could be enhanced with ML const patternContext = pattern.context || {}; const conflictFile = conflict.file || ''; // Check file type similarity if (patternContext.fileType && conflictFile) { const conflictExt = extname(conflictFile); if (patternContext.fileType !== conflictExt) { return false; } } // Check pattern type similarity if (pattern.patternType === conflict.type) { return true; } return false; } recommendIntegrationApproach(resolutions) { const automaticCount = resolutions.filter(r => r.suggestions.some(s => s.method === 'automatic') ).length; const totalCount = resolutions.length; if (automaticCount / totalCount > 0.8) { return 'automated'; } else if (automaticCount / totalCount > 0.5) { return 'semi-automated'; } else { return 'manual'; } } assessAutomationPossibility(resolutions) { const highConfidenceCount = resolutions.filter(r => r.suggestions.some(s => s.confidence > 0.8) ).length; return { possible: highConfidenceCount > 0, percentage: Math.round((highConfidenceCount / resolutions.length) * 100), recommendation: highConfidenceCount > resolutions.length * 0.7 ? 'High automation potential' : 'Limited automation potential' }; } getHistoricalCommits(repositoryPath, limit = 100) { try { const output = execSync( `git log --oneline -n ${limit} --pretty=format:"%H|%s"`, { cwd: repositoryPath, encoding: 'utf8' } ); return output.split('\n').map(line => { const [hash, message] = line.split('|'); return { hash, message }; }); } catch (error) { return []; } } findSimilarChanges(file, content, historicalCommits, repositoryPath) { const similarities = []; // Simple similarity based on file type and content patterns const fileExt = extname(file); const contentLines = content.split('\n'); for (const commit of historicalCommits.slice(0, 20)) { // Check last 20 commits try { const commitFiles = execSync( `git show --name-only --pretty=format: ${commit.hash}`, { cwd: repositoryPath, encoding: 'utf8' } ).split('\n').filter(f => f.trim()); const similarFiles = commitFiles.filter(f => extname(f) === fileExt); if (similarFiles.length > 0) { similarities.push({ commitHash: commit.hash, commitMessage: commit.message, similarFiles, similarity: this.calculateContentSimilarity(contentLines, commit, repositoryPath) }); } } catch (error) { continue; } } return similarities .filter(s => s.similarity > 0.3) .sort((a, b) => b.similarity - a.similarity); } calculateContentSimilarity(contentLines, commit, repositoryPath) { // Simple line-based similarity - could be enhanced try { const commitContent = execSync( `git show ${commit.hash}`, { cwd: repositoryPath, encoding: 'utf8' } ); const commitLines = commitContent.split('\n'); const commonLines = contentLines.filter(line => commitLines.some(cLine => cLine.includes(line.trim())) ); return commonLines.length / Math.max(contentLines.length, 1); } catch (error) { return 0; } } generateAdaptationGuidance(similarChanges) { const guidance = []; for (const change of similarChanges) { guidance.push({ approach: `Similar to commit ${change.commitHash.substring(0, 8)}`, description: change.commitMessage, similarity: Math.round(change.similarity * 100) + '%', recommendation: 'Review this commit for adaptation patterns' }); } return guidance; } generateOverallGuidance(similarities) { if (similarities.length === 0) { return 'No similar changes found. Proceed with careful manual integration.'; } const avgSimilarity = similarities.reduce((sum, s) => sum + s.similarChanges.reduce((sum2, sc) => sum2 + sc.similarity, 0) / s.similarChanges.length, 0 ) / similarities.length; if (avgSimilarity > 0.7) { return 'High similarity found with previous changes. Follow established patterns.'; } else if (avgSimilarity > 0.4) { return 'Moderate similarity found. Use previous changes as guidance.'; } else { return 'Low similarity with previous changes. Proceed with caution.'; } } loadAdaptationPatterns() { try { // Create table if it doesn't exist this.db.db.exec(` CREATE TABLE IF NOT EXISTS adaptation_patterns ( id INTEGER PRIMARY KEY AUTOINCREMENT, pattern_id TEXT UNIQUE, commit_hash TEXT, pattern_type TEXT, source_pattern TEXT, target_pattern TEXT, context TEXT, success INTEGER, effort TEXT, notes TEXT, created_at DATETIME ) `); // Load existing patterns const stmt = this.db.db.prepare('SELECT * FROM adaptation_patterns'); const patterns = stmt.all(); for (const pattern of patterns) { this.adaptationPatterns.set(pattern.pattern_id, { ...pattern, context: JSON.parse(pattern.context || '{}'), success: pattern.success === 1 }); } } catch (error) { console.error('Failed to load adaptation patterns:', error); } } getRelevantAdaptationPatterns(commitData) { const relevant = []; for (const [id, pattern] of this.adaptationPatterns) { if (pattern.success && this.isPatternRelevant(pattern, commitData)) { relevant.push(pattern); } } return relevant.slice(0, 5); // Top 5 relevant patterns } isPatternRelevant(pattern, commitData) { // Check if pattern is relevant to current commit const commitFiles = commitData.filesChanged || []; const patternContext = pattern.context || {}; // Check file type overlap if (patternContext.fileTypes) { const commitFileTypes = commitFiles.map(f => extname(f)); const hasOverlap = patternContext.fileTypes.some(ft => commitFileTypes.includes(ft)); if (hasOverlap) return true; } // Check commit message similarity if (pattern.commit_hash && commitData.message) { const similarity = this.calculateMessageSimilarity( pattern.notes || '', commitData.message ); if (similarity > 0.5) return true; } return false; } calculateMessageSimilarity(msg1, msg2) { const words1 = msg1.toLowerCase().split(/\s+/); const words2 = msg2.toLowerCase().split(/\s+/); const commonWords = words1.filter(word => words2.includes(word)); return commonWords.length / Math.max(words1.length, words2.length, 1); } calculateTotalTime(phases) { // Simple time calculation - could be enhanced let totalHours = 0; for (const phase of phases) { const timeStr = phase.estimatedTime; const hours = this.parseTimeString(timeStr); totalHours += hours; } return `${totalHours}-${totalHours * 1.5} hours`; } parseTimeString(timeStr) { const hourMatch = timeStr.match(/(\d+)-?(\d+)?\s*hours?/); const minuteMatch = timeStr.match(/(\d+)\s*minutes?/); if (hourMatch) { return parseInt(hourMatch[1]); } else if (minuteMatch) { return Math.ceil(parseInt(minuteMatch[1]) / 60); } else { return 1; // Default 1 hour } } assessMigrationRisk(analysisResults) { let riskScore = 0; if (analysisResults.breakingChanges?.hasBreakingChanges) { riskScore += analysisResults.breakingChanges.severity === 'critical' ? 3 : 2; } if (analysisResults.conflicts?.hasConflicts) { riskScore += analysisResults.conflicts.conflicts.length; } if (analysisResults.securityAnalysis?.hasSecurityImpact) { riskScore += analysisResults.securityAnalysis.overallRisk === 'critical' ? 3 : 1; } if (analysisResults.dependencyAnalysis?.complexity === 'very-high') { riskScore += 2; } if (riskScore >= 5) return 'high'; if (riskScore >= 3) return 'medium'; return 'low'; } generatePrerequisites(analysisResults) { const prerequisites = ['Ensure clean working directory', 'Create backup branch']; if (analysisResults.dependencyAnalysis?.complexity !== 'minimal') { prerequisites.push('Review dependency changes'); } if (analysisResults.breakingChanges?.hasBreakingChanges) { prerequisites.push('Identify all API consumers'); } if (analysisResults.securityAnalysis?.hasSecurityImpact) { prerequisites.push('Security team review'); } return prerequisites; } generateRollbackPlan(commitData) { return [ 'Reset to backup branch if integration fails', 'Document any manual changes made during integration', 'Restore original configuration files', 'Revert dependency changes if needed', 'Run regression tests to ensure stability' ]; } generateTestingStrategy(analysisResults) { const strategy = ['Run existing test suite']; if (analysisResults.breakingChanges?.hasBreakingChanges) { strategy.push('Test all API endpoints'); strategy.push('Validate backward compatibility'); } if (analysisResults.securityAnalysis?.hasSecurityImpact) { strategy.push('Security vulnerability scan'); strategy.push('Authentication flow testing'); } if (analysisResults.performanceAnalysis?.hasPerformanceImpact) { strategy.push('Performance benchmarking'); strategy.push('Load testing'); } strategy.push('Manual smoke testing'); strategy.push('Integration testing with dependent services'); return strategy; } // Utility methods for parsing parseConflictMarker(marker) { const lines = marker.split('\n'); const headStart = lines.findIndex(line => line.startsWith('<<<<<<< HEAD')); const separator = lines.findIndex(line => line.startsWith('=======')); const incomingEnd = lines.findIndex(line => line.startsWith('>>>>>>> ')); return { headContent: lines.slice(headStart + 1, separator).join('\n'), incomingContent: lines.slice(separator + 1, incomingEnd).join('\n'), type: this.classifyConflictType(marker) }; } classifyConflictType(marker) { if (marker.includes('import ') || marker.includes('require(')) return 'import'; if (marker.includes('function ') || marker.includes('const ') || marker.includes('let ')) return 'code'; if (marker.includes('dependencies') || marker.includes('package.json')) return 'dependency'; return 'unknown'; } extractImports(content) { const imports = []; const importRegex = /^(import.*from.*|const.*require\(.*\));?$/gm; let match; while ((match = importRegex.exec(content)) !== null) { imports.push(match[1]); } return imports; } compareVersions(v1, v2) { const parts1 = v1.replace(/[^\d.]/g, '').split('.').map(Number); const parts2 = v2.replace(/[^\d.]/g, '').split('.').map(Number); for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { const part1 = parts1[i] || 0; const part2 = parts2[i] || 0; if (part1 > part2) return 1; if (part1 < part2) return -1; } return 0; } parseFunctionSignature(content) { const funcMatch = content.match(/function\s+(\w+)\s*\(([^)]*)\)/); if (funcMatch) { return { name: funcMatch[1], parameters: funcMatch[2], signature: funcMatch[0] }; } return null; } detectFunctionSignatureChanges(content, file) { const changes = []; const functions = content.match(/function\s+\w+\s*\([^)]*\)/g) || []; // This is a simplified detection - in practice, you'd compare with the original version for (const func of functions) { changes.push({ type: 'function-signature', function: func, file: file }); } return changes; } detectAPIChanges(content, file) { const changes = []; const exports = content.match(/export\s+(function|class|const|let)\s+\w+/g) || []; for (const exp of exports) { changes.push({ type: 'export-change', export: exp, file: file }); } return changes; } // Helper methods getConflictedFiles(repositoryPath) { try { const statusOutput = execSync('git status --porcelain', { encoding: 'utf8', cwd: repositoryPath }); const conflictedFiles = []; const lines = statusOutput.split('\n').filter(line => line.trim()); for (const line of lines) { if (line.startsWith('UU ') || line.startsWith('AA ') || line.startsWith('DD ')) { const file = line.substring(3).trim(); conflictedFiles.push({ file, status: line.substring(0, 2), type: this.determineConflictType(file) }); } } return conflictedFiles; } catch (error) { return []; } } determineConflictType(file) { const ext = extname(file).toLowerCase(); const path = file.toLowerCase(); if (file.includes('package.json')) return 'dependency'; if (path.includes('config') || path.includes('.env')) return 'config'; if (['.js', '.ts', '.jsx', '.tsx'].includes(ext)) return 'code'; if (['.css', '.scss', '.less'].includes(ext)) return 'style'; if (['.md', '.txt', '.rst'].includes(ext)) return 'documentation'; return 'other'; } async analyzeFileConflicts(conflictFile, repositoryPath) { try { const filePath = join(repositoryPath, conflictFile.file); const content = readFileSync(filePath, 'utf8'); // Extract conflict markers const conflicts = this.extractConflictMarkers(content); return { file: conflictFile.file, type: conflictFile.type, conflicts: conflicts.length, content: content, resolutionComplexity: this.assessResolutionComplexity(conflicts), suggestedResolution: this.suggestResolution(conflictFile.type, conflicts) }; } catch (error) { return { file: conflictFile.file, type: conflictFile.type, error: `Failed to analyze conflicts: ${error.message}`, resolutionComplexity: 'unknown' }; } } extractConflictMarkers(content) { const conflicts = []; const lines = content.split('\n'); let currentConflict = null; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line.startsWith('<<<<<<<')) { currentConflict = { start: i, head: [], base: [], incoming: [] }; } else if (line.startsWith('=======') && currentConflict) { currentConflict.separator = i; } else if (line.startsWith('>>>>>>>') && currentConflict) { currentConflict.end = i; conflicts.push(currentConflict); currentConflict = null; } else if (currentConflict) { if (currentConflict.separator === undefined) { currentConflict.head.push(line); } else { currentConflict.incoming.push(line); } } } return conflicts; } assessResolutionComplexity(conflicts) { if (conflicts.length === 0) return 'none'; if (conflicts.length === 1 && conflicts[0].head.length <= 3) return 'simple'; if (conflicts.length <= 3 && conflicts.every(c => c.head.length <= 10)) return 'moderate'; return 'complex'; } suggestResolution(conflictType, conflicts) { const suggestions = []; switch (conflictType) { case 'dependency': suggestions.push('Merge both dependency sets, resolve version conflicts'); suggestions.push('Use latest compatible versions'); break; case 'config': suggestions.push('Merge configuration values, prioritize security settings'); suggestions.push('Use environment-specific overrides'); break; case 'code': suggestions.push('Review both implementations for best approach'); suggestions.push('Consider refactoring to combine functionality'); break; default: suggestions.push('Manual review required'); suggestions.push('Consider keeping both versions if applicable'); } return suggestions; } analyzeSemanticConflicts(changedFiles, repositoryPath) { const semanticConflicts = []; // Check for potential semantic conflicts based on file patterns const apiFiles = changedFiles.filter(file => file.includes('api') || file.includes('endpoint') || file.includes('route') ); if (apiFiles.length > 0) { semanticConflicts.push({ type: 'api_changes', description: 'API changes may conflict with existing integrations', files: apiFiles, severity: 'medium', recommendation: 'Review API compatibility and versioning' }); } const schemaFiles = changedFiles.filter(file => file.includes('schema') || file.includes('migration') || file.includes('model') ); if (schemaFiles.length > 0) { semanticConflicts.push({ type: 'schema_changes', description: 'Database schema changes may conflict with existing data', files: schemaFiles, severity: 'high', recommendation: 'Plan migration strategy and data backup' }); } return semanticConflicts; } generateResolutionSuggestions(conflicts) { const suggestions = []; for (const conflict of conflicts) { if (conflict.type === 'dependency') { suggestions.push({ type: 'automated', description: 'Use npm/yarn to resolve dependency conflicts', command: 'npm install --legacy-peer-deps', confidence: 0.8 }); } else if (conflict.type === 'config') { suggestions.push({ type: 'manual', description: 'Merge configuration files manually', steps: [ 'Compare configuration values', 'Keep security-critical settings', 'Test configuration in staging' ], confidence: 0.6 }); } } return suggestions; } estimateResolutionTime(conflicts) { let totalMinutes = 0; for (const conflict of conflicts) { switch (conflict.resolutionComplexity || 'moderate') { case 'simple': totalMinutes += 15; break; case 'moderate': totalMinutes += 45; break; case 'complex': totalMinutes += 120; break; default: totalMinutes += 60; } } if (totalMinutes < 60) { return `${totalMinutes} minutes`; } else { const hours = Math.ceil(totalMinutes / 60); return `${hours} hour${hours > 1 ? 's' : ''}`; } } getHistoricalCommits(repositoryPath) { try { const logOutput = execSync( 'git log --oneline -50 --pretty=format:"%H|%s"', { encoding: 'utf8', cwd: repositoryPath } ); return logOutput.split('\n').map(line => { const [hash, message] = line.split('|'); return { hash, message }; }).filter(commit => commit.hash && commit.message); } catch (error) { return []; } } findSimilarChanges(file, content, historicalCommits, repositoryPath) { const similarities = []; // Simple similarity based on file name patterns const fileName = basename(file); const fileDir = dirname(file); for (const commit of historicalCommits.slice(0, 20)) { // Check last 20 commits try { const commitFiles = execSync( `git show --name-only --pretty=format: ${commit.hash}`, { encoding: 'utf8', cwd: repositoryPath } ).split('\n').filter(f => f.trim()); const similarFiles = commitFiles.filter(f => basename(f) === fileName || dirname(f) === fileDir ); if (similarFiles.length > 0) { similarities.push({ commit: commit.hash, message: commit.message, similarFiles, similarity: this.calculateFileSimilarity(file, similarFiles) }); } } catch (error) { // Skip this commit if we can't analyze it continue; } } return similarities.sort((a, b) => b.similarity - a.similarity).slice(0, 5); } calculateFileSimilarity(targetFile, candidateFiles) { const targetName = basename(targetFile); const targetDir = dirname(targetFile); let maxSimilarity = 0; for (const candidate of candidateFiles) { let similarity = 0; // Exact file name match if (basename(candidate) === targetName) { similarity += 0.5; } // Same directory if (dirname(candidate) === targetDir) { similarity += 0.3; } // Same extension if (extname(candidate) === extname(targetFile)) { similarity += 0.2; } maxSimilarity = Math.max(maxSimilarity, similarity); } return maxSimilarity; } parseTimeEstimate(timeString) { const match = timeString.match(/(\d+)-?(\d+)?\s*(hour|minute)/i); if (!match) return 4; // Default 4 hours const min = parseInt(match[1]); const max = match[2] ? parseInt(match[2]) : min; const unit = match[3].toLowerCase(); const average = (min + max) / 2; return unit === 'hour' ? average : average / 60; } // Conflict resolution methods mergeImports(conflict) { const headImports = this.extractImportsFromLines(conflict.head); const incomingImports = this.extractImportsFromLines(conflict.incoming); const mergedImports = [...new Set([...headImports, ...incomingImports])]; return mergedImports.join('\n'); } mergeDependencies(conflict) { try { const headDeps = JSON.parse(conflict.head.join('\n')); const incomingDeps = JSON.parse(conflict.incoming.join('\n')); const merged = { ...headDeps, ...incomingDeps }; return JSON.stringify(merged, null, 2); } catch (error) { return null; // Manual resolution required } } mergeConfig(conflict) { // Simple key-value merge for configuration const headConfig = this.parseConfigLines(conflict.head); const incomingConfig = this.parseConfigLines(conflict.incoming); const merged = { ...headConfig, ...incomingConfig }; return Object.entries(merged).map(([key, value]) => `${key}=${value}`).join('\n'); } analyzeFunctionConflict(conflict) { // For function conflicts, suggest manual review return { suggestion: 'manual_review', reason: 'Function conflicts require careful analysis of logic differences', recommendation: 'Compare both implementations and choose the best approach' }; } extractImportsFromLines(lines) { return lines.filter(line => line.trim().startsWith('import ') || line.trim().startsWith('const ') && line.includes('require(') ); } parseConfigLines(lines) { const config = {}; for (const line of lines) { const match = line.match(/^(\w+)\s*[=:]\s*(.+)$/); if (match) { config[match[1]] = match[2]; } } return config; } calculateResolutionConfidence(method, conflict) { const confidenceMap = { imports: 0.8, dependencies: 0.7, config: 0.6, functions: 0.3 }; return confidenceMap[method] || 0.5; } findAdaptationPattern(conflict) { // Check stored adaptation patterns for (const [pattern, data] of this.adaptationPatterns) { if (this.matchesPattern(conflict, pattern)) { return { method: 'adaptation_pattern', description: `Similar conflict resolved previously: ${data.description}`, resolution: data.resolution, confidence: data.successRate || 0.7 }; } } return null; } matchesPattern(conflict, pattern) { // Simple pattern matching based on file type and conflict type return conflict.type === pattern.type && conflict.file.includes(pattern.filePattern); } recommendIntegrationApproach(resolutions) { const automatable = resolutions.filter(r => r.suggestions.some(s => s.confidence > 0.7) ).length; const total = resolutions.length; if (automatable / total > 0.8) { return 'automated'; } else if (automatable / total > 0.5) { return 'semi_automated'; } else { return 'manual'; } } assessAutomationPossibility(resolutions) { return resolutions.some(r => r.suggestions.some(s => s.type === 'automated' && s.confidence > 0.8) ); } loadAdaptationPatterns() { // Load patterns from database if available try { if (this.db) { const patterns = this.db.getAdaptationPatterns(); for (const pattern of patterns) { this.adaptationPatterns.set(pattern.id, pattern); } } } catch (error) { // Database not available or no patterns stored } } learnAdaptationPattern(commitHash, adaptationData) { const pattern = { id: `pattern_${Date.now()}`, commitHash, type: adaptationData.type, sourcePattern: adaptationData.source_pattern, targetPattern: adaptationData.target_pattern, context: adaptationData.context, success: adaptationData.success, effort: adaptationData.effort, notes: adaptationData.notes, createdAt: new Date().toISOString() }; // Store in memory this.adaptationPatterns.set(pattern.id, pattern); // Store in database if available try { if (this.db) { this.db.storeAdaptationPattern(pattern); } } catch (error) { // Database storage failed, but pattern is still in memory } return pattern; } } export default IntegrationHelpersSystem;

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