Skip to main content
Glama
review-existing-adrs-tool.ts52.3 kB
/** * MCP Tool for reviewing existing ADRs against actual code implementation * Validates ADR compliance, identifies gaps, and suggests updates * Uses tree-sitter for accurate code analysis * * Following ADR-018 Atomic Tools Architecture: * - Dependency injection for testability * - No ResearchOrchestrator (deprecated) - direct utility calls * - Self-contained with minimal dependencies */ import { McpAdrError } from '../types/index.js'; import { ConversationContext } from '../types/conversation-context.js'; import { TreeSitterAnalyzer } from '../utils/tree-sitter-analyzer.js'; import * as path from 'path'; import * as fs from 'fs/promises'; interface AdrReviewResult { adrPath: string; title: string; status: string; complianceScore: number; codeCompliance: { implemented: boolean; partiallyImplemented: boolean; notImplemented: boolean; evidence: string[]; gaps: string[]; }; recommendations: { updateAdr: boolean; updateCode: boolean; createPlan: boolean; actions: string[]; }; analysis: string; } interface CodeAnalysisResult { files: string[]; patterns: string[]; technologies: string[]; architecturalElements: { apis: string[]; databases: string[]; frameworks: string[]; patterns: string[]; securityFindings?: string[]; infrastructureResources?: string[]; devopsTools?: string[]; }; } /** * Review existing ADRs and validate against actual code implementation */ export async function reviewExistingAdrs(args: { adrDirectory?: string; projectPath?: string; specificAdr?: string; analysisDepth?: 'basic' | 'detailed' | 'comprehensive'; includeTreeSitter?: boolean; generateUpdatePlan?: boolean; conversationContext?: ConversationContext; }): Promise<any> { const { adrDirectory = 'docs/adrs', projectPath = process.cwd(), specificAdr, analysisDepth = 'detailed', includeTreeSitter = true, generateUpdatePlan = true, } = args; // Security: Validate and resolve project path const resolvedProjectPath = path.resolve(projectPath); // Security: Ensure project path is not a system directory // Note: We explicitly ALLOW temp directories (/tmp, /var/folders, /private/tmp) // because tests and legitimate workflows use them const systemPaths = ['/Library', '/System', '/usr', '/etc', '/Applications', '/bin', '/sbin']; const allowedVarPaths = ['/var/folders', '/var/tmp']; // macOS temp directories const homeDir = process.env['HOME'] || ''; const sensitiveHomePaths = ['Library', 'Applications']; // Check for system paths, but allow temp directories const isSystemPath = systemPaths.some(sysPath => resolvedProjectPath.startsWith(sysPath)); const isAllowedVarPath = allowedVarPaths.some(varPath => resolvedProjectPath.startsWith(varPath)); if (isSystemPath) { throw new McpAdrError( 'INVALID_INPUT', `Security: Cannot analyze system directory: ${resolvedProjectPath}`, { projectPath: resolvedProjectPath } ); } // Block /var paths except allowed temp directories if (resolvedProjectPath.startsWith('/var') && !isAllowedVarPath) { throw new McpAdrError( 'INVALID_INPUT', `Security: Cannot analyze system directory: ${resolvedProjectPath}`, { projectPath: resolvedProjectPath } ); } // Block /private paths except /private/tmp (macOS symlink for /tmp) if ( resolvedProjectPath.startsWith('/private') && !resolvedProjectPath.startsWith('/private/tmp') && !resolvedProjectPath.startsWith('/private/var/folders') ) { throw new McpAdrError( 'INVALID_INPUT', `Security: Cannot analyze system directory: ${resolvedProjectPath}`, { projectPath: resolvedProjectPath } ); } // Check for sensitive paths within home directory if (homeDir.length > 0 && resolvedProjectPath.startsWith(homeDir)) { const relativePath = resolvedProjectPath.slice(homeDir.length + 1); const firstDir = relativePath.split(path.sep)[0]; if (firstDir && sensitiveHomePaths.includes(firstDir)) { throw new McpAdrError( 'INVALID_INPUT', `Security: Cannot analyze sensitive directory: ${resolvedProjectPath}`, { projectPath: resolvedProjectPath } ); } } try { // Step 1: Discover existing ADRs const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js'); const discoveryResult = await discoverAdrsInDirectory(adrDirectory, resolvedProjectPath, { includeContent: true, includeTimeline: false, }); if (discoveryResult.totalAdrs === 0) { return { content: [ { type: 'text', text: `# ADR Review: No ADRs Found ## Discovery Results - **Directory**: ${adrDirectory} - **Project Path**: ${resolvedProjectPath} - **ADRs Found**: 0 ## Recommendations 1. **Create Initial ADRs**: Use the \`suggest_adrs\` tool to identify architectural decisions 2. **Set Up ADR Directory**: Create the ADR directory structure 3. **Establish ADR Process**: Implement ADR workflow for future decisions ## Next Steps \`\`\`json { "tool": "suggest_adrs", "args": { "projectPath": "${resolvedProjectPath}", "analysisType": "comprehensive" } } \`\`\` `, }, ], }; } // Step 2: Filter ADRs if specific one requested const adrsToReview = specificAdr ? discoveryResult.adrs.filter( adr => adr.filename.includes(specificAdr) || adr.title.toLowerCase().includes(specificAdr.toLowerCase()) ) : discoveryResult.adrs; if (adrsToReview.length === 0) { throw new McpAdrError(`No ADRs found matching: ${specificAdr}`, 'ADR_NOT_FOUND'); } // Step 3: Analyze environment context (simplified - no ResearchOrchestrator per ADR-018) // The ResearchOrchestrator is deprecated and caused 37+ test timeouts (850s+ test suite) // For environment analysis, users can call environment-analysis-tool separately if needed const environmentContext = ` ## 📊 Code Analysis Context **Analysis Mode**: ${analysisDepth} **Tree-sitter Enabled**: ${includeTreeSitter ? '✅' : '❌'} **Project**: ${path.basename(resolvedProjectPath)} > **Note**: For detailed environment analysis, use the \`environment-analysis-tool\` separately. > This tool focuses on ADR-to-code compliance validation. `; const researchConfidence = 0.85; // Static confidence for basic code analysis // Step 4: Analyze code structure const codeAnalysis = await analyzeCodeStructure(resolvedProjectPath, includeTreeSitter); // Step 5: Review each ADR const reviewResults: AdrReviewResult[] = []; for (const adr of adrsToReview) { const reviewResult = await reviewSingleAdr( adr, codeAnalysis, analysisDepth, resolvedProjectPath ); reviewResults.push(reviewResult); } // Step 5: Generate comprehensive report const overallScore = reviewResults.reduce((sum, result) => sum + result.complianceScore, 0) / reviewResults.length; const totalGaps = reviewResults.reduce( (sum, result) => sum + result.codeCompliance.gaps.length, 0 ); const needsUpdate = reviewResults.filter(result => result.recommendations.updateAdr).length; const needsCodeChanges = reviewResults.filter( result => result.recommendations.updateCode ).length; let updatePlan = ''; if (generateUpdatePlan) { updatePlan = await generateUpdatePlanContent( reviewResults, codeAnalysis, resolvedProjectPath ); } return { content: [ { type: 'text', text: `# ADR Compliance Review Report ## Overview - **Project**: ${path.basename(resolvedProjectPath)} - **ADRs Reviewed**: ${reviewResults.length} - **Overall Compliance Score**: ${overallScore.toFixed(1)}/10 - **Research Confidence**: ${(researchConfidence * 100).toFixed(1)}% - **Analysis Depth**: ${analysisDepth} - **Tree-sitter Analysis**: ${includeTreeSitter ? '✅ Enabled' : '❌ Disabled'} ${environmentContext} ## Summary Statistics - **Total Gaps Identified**: ${totalGaps} - **ADRs Needing Updates**: ${needsUpdate} - **Code Changes Required**: ${needsCodeChanges} - **Full Compliance**: ${reviewResults.filter(r => r.complianceScore >= 8).length} - **Partial Compliance**: ${reviewResults.filter(r => r.complianceScore >= 5 && r.complianceScore < 8).length} - **Non-Compliance**: ${reviewResults.filter(r => r.complianceScore < 5).length} ## Detailed Reviews ${reviewResults .map( result => ` ### ${result.title} - **File**: ${path.basename(result.adrPath)} - **Status**: ${result.status} - **Compliance Score**: ${result.complianceScore}/10 #### Implementation Status - **Implemented**: ${result.codeCompliance.implemented ? '✅' : '❌'} - **Partially Implemented**: ${result.codeCompliance.partiallyImplemented ? '⚠️' : '❌'} - **Not Implemented**: ${result.codeCompliance.notImplemented ? '🚨' : '✅'} #### Evidence Found ${ result.codeCompliance.evidence.length > 0 ? result.codeCompliance.evidence.map(e => `- ${e}`).join('\n') : '- No supporting evidence found in codebase' } #### Gaps Identified ${ result.codeCompliance.gaps.length > 0 ? result.codeCompliance.gaps.map(g => `- ${g}`).join('\n') : '- No gaps identified' } #### Recommendations ${result.recommendations.actions.map(a => `- ${a}`).join('\n')} #### Analysis ${result.analysis} --- ` ) .join('\n')} ## Code Structure Analysis - **Files Analyzed**: ${codeAnalysis.files.length} - **Technologies Detected**: ${codeAnalysis.technologies.join(', ')} - **Architectural Patterns**: ${codeAnalysis.patterns.join(', ')} ### Architectural Elements - **APIs**: ${codeAnalysis.architecturalElements.apis?.length || 0} - **Databases**: ${codeAnalysis.architecturalElements.databases?.length || 0} - **Frameworks**: ${codeAnalysis.architecturalElements.frameworks?.length || 0} - **Patterns**: ${codeAnalysis.architecturalElements.patterns?.length || 0} - **Infrastructure Resources**: ${codeAnalysis.architecturalElements.infrastructureResources?.length || 0} - **DevOps Tools**: ${codeAnalysis.architecturalElements.devopsTools?.length || 0} ### Enterprise Security Analysis (Tree-sitter) ${ includeTreeSitter ? ` - **Security Findings**: ${codeAnalysis.architecturalElements.securityFindings?.length || 0} ${ (codeAnalysis.architecturalElements.securityFindings?.length || 0) > 0 ? ` #### Critical Security Issues: ${codeAnalysis.architecturalElements .securityFindings!.slice(0, 10) .map((finding: string) => `- ${finding}`) .join('\n')} ${(codeAnalysis.architecturalElements.securityFindings!.length || 0) > 10 ? `\n*... and ${(codeAnalysis.architecturalElements.securityFindings!.length || 0) - 10} more security findings*` : ''} ` : '- ✅ No security issues detected' } ` : '- Tree-sitter security analysis disabled' } ### DevOps Stack Analysis ${ includeTreeSitter && (codeAnalysis.architecturalElements.infrastructureResources?.length || 0) > 0 ? ` #### Infrastructure Resources: ${codeAnalysis.architecturalElements .infrastructureResources!.slice(0, 10) .map((resource: string) => `- ${resource}`) .join('\n')} ${(codeAnalysis.architecturalElements.infrastructureResources!.length || 0) > 10 ? `\n*... and ${(codeAnalysis.architecturalElements.infrastructureResources!.length || 0) - 10} more resources*` : ''} ` : '- No infrastructure resources detected' } ${ includeTreeSitter && (codeAnalysis.architecturalElements.devopsTools?.length || 0) > 0 ? ` #### DevOps Tools Detected: ${codeAnalysis.architecturalElements .devopsTools!.slice(0, 10) .map((tool: string) => `- ${tool}`) .join('\n')} ${(codeAnalysis.architecturalElements.devopsTools!.length || 0) > 10 ? `\n*... and ${(codeAnalysis.architecturalElements.devopsTools!.length || 0) - 10} more tools*` : ''} ` : '- No DevOps tools detected' } ${generateUpdatePlan ? updatePlan : ''} ## Next Steps ### Immediate Actions (High Priority) ${ reviewResults .filter(r => r.complianceScore < 5) .map(r => `- **${r.title}**: ${r.recommendations.actions[0] || 'Requires immediate attention'}`) .join('\n') || '- No immediate actions required' } ### Medium Priority ${ reviewResults .filter(r => r.complianceScore >= 5 && r.complianceScore < 8) .map(r => `- **${r.title}**: ${r.recommendations.actions[0] || 'Minor updates needed'}`) .join('\n') || '- No medium priority items' } ### Maintenance ${ reviewResults .filter(r => r.complianceScore >= 8) .map(r => `- **${r.title}**: Well implemented, monitor for changes`) .join('\n') || '- No items in maintenance status' } ## Quality Assessment ### Best Practices Compliance - **Documentation Quality**: ${calculateDocumentationQuality(reviewResults)}/10 - **Implementation Fidelity**: ${calculateImplementationFidelity(reviewResults)}/10 - **Architectural Consistency**: ${calculateArchitecturalConsistency(reviewResults)}/10 ### Recommendations for Process Improvement 1. **Regular ADR Reviews**: Schedule quarterly compliance reviews 2. **Automated Validation**: Implement CI/CD checks for ADR compliance 3. **Developer Training**: Ensure team understands ADR importance 4. **Template Updates**: Standardize ADR format for better tracking ## Tools for Follow-up ### Update Specific ADRs \`\`\`json { "tool": "generate_adr_from_decision", "args": { "decisionData": { "title": "Updated [ADR Title]", "context": "Review findings and current implementation", "decision": "Refined decision based on analysis", "consequences": "Updated consequences from review" } } } \`\`\` ### Generate Implementation Plan \`\`\`json { "tool": "generate_implementation_plan", "args": { "adrPath": "[specific ADR path]", "includeCodeChanges": true, "priority": "high" } } \`\`\` `, }, ], }; } catch (error) { throw new McpAdrError( `Failed to review ADRs: ${error instanceof Error ? error.message : String(error)}`, 'REVIEW_ERROR' ); } } /** * Analyze code structure to understand current implementation * Enhanced with fast-glob for efficient file discovery */ async function analyzeCodeStructure( projectPath: string, useTreeSitter: boolean ): Promise<CodeAnalysisResult> { const result: CodeAnalysisResult = { files: [], patterns: [], technologies: [], architecturalElements: { apis: [], databases: [], frameworks: [], patterns: [], }, }; try { // Enhanced file system analysis using fast-glob const { analyzeProjectStructure } = await import('../utils/file-system.js'); // Use the new analyzeProjectStructure function for comprehensive analysis const projectAnalysis = await analyzeProjectStructure(projectPath); // Extract file paths from the analysis result.files = projectAnalysis.files.map(f => f.path); result.technologies = projectAnalysis.technologies; result.patterns = projectAnalysis.patterns; // Legacy pattern detection for backward compatibility const legacyPatterns = await detectArchitecturalPatterns(result.files); result.patterns = [...new Set([...result.patterns, ...legacyPatterns])]; // If tree-sitter is enabled, perform detailed analysis if (useTreeSitter) { const detailedAnalysis = await performTreeSitterAnalysis(result.files); result.architecturalElements = detailedAnalysis; } return result; } catch (error) { console.warn('Enhanced code analysis failed, falling back to legacy:', error); // Fallback to legacy implementation try { const files = await findSourceFiles(projectPath); result.files = files; result.technologies = await detectTechnologies(projectPath); result.patterns = await detectArchitecturalPatterns(files); if (useTreeSitter) { const detailedAnalysis = await performTreeSitterAnalysis(files); result.architecturalElements = detailedAnalysis; } } catch (fallbackError) { console.warn('Legacy code analysis also failed:', fallbackError); } return result; } } /** * Review a single ADR against code implementation * Enhanced with Smart Code Linking to find related files */ async function reviewSingleAdr( adr: any, codeAnalysis: CodeAnalysisResult, depth: string, projectPath: string ): Promise<AdrReviewResult> { const result: AdrReviewResult = { adrPath: adr.path, title: adr.title, status: adr.status, complianceScore: 0, codeCompliance: { implemented: false, partiallyImplemented: false, notImplemented: false, evidence: [], gaps: [], }, recommendations: { updateAdr: false, updateCode: false, createPlan: false, actions: [], }, analysis: '', }; try { // Parse ADR content for key architectural elements const adrElements = extractAdrElements(adr.content || ''); // SMART CODE LINKING: Find related code files for this specific ADR let relatedFiles: any[] = []; try { const { findRelatedCode } = await import('../utils/file-system.js'); const relatedCodeResult = await findRelatedCode(adr.path, adr.content || '', projectPath, { useAI: true, useRipgrep: true, maxFiles: 25, includeContent: false, }); relatedFiles = relatedCodeResult.relatedFiles; // Add Smart Code Linking results to evidence if (relatedFiles.length > 0) { result.codeCompliance.evidence.push( `Smart Code Linking found ${relatedFiles.length} related files (confidence: ${(relatedCodeResult.confidence * 100).toFixed(0)}%)` ); // Add top related files as evidence const topFiles = relatedFiles.slice(0, 5); topFiles.forEach(file => { result.codeCompliance.evidence.push(`Related: ${file.path}`); }); } else { result.codeCompliance.gaps.push('No related code files found using Smart Code Linking'); } } catch (error) { console.warn('Smart Code Linking failed:', error); result.codeCompliance.gaps.push('Smart Code Linking unavailable - manual review required'); } // Compare ADR elements with code implementation (enhanced with related files) const complianceAnalysis = await analyzeCompliance(adrElements, codeAnalysis, relatedFiles); // Merge Smart Code Linking evidence with compliance analysis result.codeCompliance.evidence.push(...complianceAnalysis.evidence); result.codeCompliance.gaps.push(...complianceAnalysis.gaps); result.codeCompliance.implemented = complianceAnalysis.implemented || relatedFiles.length > 0; result.codeCompliance.partiallyImplemented = complianceAnalysis.partiallyImplemented || (relatedFiles.length > 0 && relatedFiles.length < 5); result.codeCompliance.notImplemented = complianceAnalysis.notImplemented && relatedFiles.length === 0; result.complianceScore = calculateComplianceScore(result.codeCompliance); // Generate recommendations (enhanced with Smart Code Linking insights) result.recommendations = generateRecommendations( result.codeCompliance, result.complianceScore, relatedFiles ); // Generate detailed analysis (include Smart Code Linking results) result.analysis = generateDetailedAnalysis( adrElements, result.codeCompliance, depth, relatedFiles ); return result; } catch (error) { result.analysis = `Error analyzing ADR: ${error instanceof Error ? error.message : String(error)}`; return result; } } /** * Extract architectural elements from ADR content */ function extractAdrElements(content: string): any { const elements: any = { technologies: [], apis: [], databases: [], patterns: [], components: [], constraints: [], decisions: [], }; // Extract from different sections of the ADR const sections = { context: extractSection(content, 'context'), decision: extractSection(content, 'decision'), consequences: extractSection(content, 'consequences'), alternatives: extractSection(content, 'alternatives'), }; // Technology extraction patterns const techPatterns = [ /\b(React|Vue|Angular|Node\.js|Express|FastAPI|Django|Spring|Rails)\b/gi, /\b(PostgreSQL|MySQL|MongoDB|Redis|Elasticsearch)\b/gi, /\b(Docker|Kubernetes|AWS|Azure|GCP)\b/gi, ]; // API patterns const apiPatterns = [ /\b(REST|GraphQL|gRPC|WebSocket)\b/gi, /\b(API|endpoint|service|microservice)\b/gi, ]; // Extract elements from each section for (const [, sectionContent] of Object.entries(sections)) { if (sectionContent) { elements.technologies.push(...extractMatches(sectionContent, techPatterns)); elements.apis.push(...extractMatches(sectionContent, apiPatterns)); } } return elements; } /** * Extract section content from ADR */ function extractSection(content: string, sectionName: string): string | null { const regex = new RegExp(`##\\s*${sectionName}[^#]*`, 'gi'); const match = content.match(regex); return match ? match[0] : null; } /** * Extract matches from content using patterns */ function extractMatches(content: string, patterns: RegExp[]): string[] { const matches: string[] = []; patterns.forEach(pattern => { const found = content.match(pattern); if (found) { matches.push(...found); } }); return [...new Set(matches)]; // Remove duplicates } /** * Analyze compliance between ADR and code */ async function analyzeCompliance( adrElements: any, codeAnalysis: CodeAnalysisResult, relatedFiles: any[] = [] ): Promise<any> { const compliance: any = { implemented: false, partiallyImplemented: false, notImplemented: false, evidence: [], gaps: [], }; // Check technology alignment const adrTechs = adrElements.technologies || []; const codeTechs = codeAnalysis.technologies || []; const techMatches = adrTechs.filter((tech: string) => codeTechs.some( (codeTech: string) => codeTech.toLowerCase().includes(tech.toLowerCase()) || tech.toLowerCase().includes(codeTech.toLowerCase()) ) ); if (techMatches.length > 0) { compliance.evidence.push(`Technologies implemented: ${techMatches.join(', ')}`); } const missingTechs = adrTechs.filter((tech: string) => !techMatches.includes(tech)); if (missingTechs.length > 0) { compliance.gaps.push(`Missing technologies: ${missingTechs.join(', ')}`); } // Smart Code Linking analysis: check if related files provide additional evidence if (relatedFiles.length > 0) { compliance.evidence.push( `Smart Code Linking identified ${relatedFiles.length} potentially related files` ); // Analyze file extensions to infer technologies used in related files const relatedExtensions = [...new Set(relatedFiles.map((f: any) => f.extension))]; const relatedTechHints = relatedExtensions .map(ext => { switch (ext) { case '.ts': case '.tsx': return 'TypeScript'; case '.js': case '.jsx': return 'JavaScript'; case '.py': return 'Python'; case '.java': return 'Java'; case '.cs': return 'C#'; case '.go': return 'Go'; case '.rs': return 'Rust'; default: return null; } }) .filter(Boolean); if (relatedTechHints.length > 0) { compliance.evidence.push( `Related files suggest technologies: ${relatedTechHints.join(', ')}` ); } } else { compliance.gaps.push('No related files found - implementation may not exist'); } // Check API implementation const adrApis = adrElements.apis || []; const codeApis = codeAnalysis.architecturalElements.apis || []; const apiMatches = adrApis.filter((api: string) => codeApis.some((codeApi: string) => codeApi.toLowerCase().includes(api.toLowerCase())) ); if (apiMatches.length > 0) { compliance.evidence.push(`APIs implemented: ${apiMatches.join(', ')}`); } // Determine overall compliance status const totalElements = adrTechs.length + adrApis.length; const implementedElements = techMatches.length + apiMatches.length; if (implementedElements === totalElements && totalElements > 0) { compliance.implemented = true; } else if (implementedElements > 0) { compliance.partiallyImplemented = true; } else { compliance.notImplemented = true; } return compliance; } /** * Calculate compliance score */ function calculateComplianceScore(compliance: any): number { if (compliance.implemented) return 9; if (compliance.partiallyImplemented) return 6; if (compliance.notImplemented) return 2; return 5; // Default/unknown } /** * Generate recommendations based on compliance analysis */ function generateRecommendations(compliance: any, score: number, relatedFiles: any[] = []): any { const recommendations: any = { updateAdr: false, updateCode: false, createPlan: false, actions: [], }; if (score < 5) { recommendations.createPlan = true; recommendations.actions.push('Create implementation plan for missing elements'); recommendations.actions.push('Consider updating ADR if decisions have changed'); } if (compliance.gaps.length > 0) { recommendations.updateCode = true; recommendations.actions.push('Implement missing architectural elements'); } if (score < 7) { recommendations.updateAdr = true; recommendations.actions.push('Update ADR to reflect current implementation'); } // Smart Code Linking enhancements if (relatedFiles.length > 0) { recommendations.actions.push( `Review ${relatedFiles.length} related files identified by Smart Code Linking` ); if (relatedFiles.length > 10) { recommendations.actions.push( 'Consider refactoring - many files may indicate coupling issues' ); } } else { recommendations.actions.push('Use Smart Code Linking to identify implementation files'); } return recommendations; } /** * Generate detailed analysis text */ function generateDetailedAnalysis( adrElements: any, compliance: any, depth: string, relatedFiles: any[] = [] ): string { let analysis = ''; if (depth === 'comprehensive') { analysis += ` **Architectural Elements Analysis:** - Technologies mentioned: ${adrElements.technologies?.length || 0} - APIs referenced: ${adrElements.apis?.length || 0} - Implementation evidence: ${compliance.evidence.length} - Identified gaps: ${compliance.gaps.length} **Smart Code Linking Results:** - Related files found: ${relatedFiles.length} ${ relatedFiles.length > 0 ? `- Top related files:\n${relatedFiles .slice(0, 3) .map((f: any) => ` • ${f.path} (${f.name})`) .join('\n')}` : '- No related files identified' } **Compliance Details:** ${compliance.evidence.map((e: string) => `✅ ${e}`).join('\n')} ${compliance.gaps.map((g: string) => `❌ ${g}`).join('\n')} `; } else { analysis = `Implementation status: ${ compliance.implemented ? 'Fully implemented' : compliance.partiallyImplemented ? 'Partially implemented' : 'Not implemented' }. Smart Code Linking found ${relatedFiles.length} related files.`; } return analysis; } // Helper functions for code analysis // Directories to always exclude for security and performance const EXCLUDED_DIRECTORIES = new Set([ 'node_modules', '.git', '.svn', '.hg', 'dist', 'build', 'coverage', '.cache', '.npm', '.yarn', 'vendor', '__pycache__', '.pytest_cache', 'target', 'bin', 'obj', // System directories that should never be traversed 'Library', 'System', 'Applications', 'usr', 'var', 'etc', 'private', 'cores', 'Volumes', ]); // Maximum recursion depth for directory traversal const MAX_RECURSION_DEPTH = 10; async function findSourceFiles( projectPath: string, rootPath?: string, currentDepth: number = 0 ): Promise<string[]> { const files: string[] = []; const extensions = ['.ts', '.js', '.py', '.java', '.cs', '.go', '.rs', '.rb']; // Security: Initialize and validate root path on first call if (!rootPath) { rootPath = path.resolve(projectPath); // Ensure we're not starting from a system directory const pathParts = rootPath.split(path.sep); if ( pathParts.some( part => EXCLUDED_DIRECTORIES.has(part) && part !== pathParts[pathParts.length - 1] ) ) { console.warn(`Security: Refusing to scan potentially sensitive path: ${rootPath}`); return files; } } // Security: Enforce maximum recursion depth if (currentDepth > MAX_RECURSION_DEPTH) { console.warn( `Security: Maximum recursion depth (${MAX_RECURSION_DEPTH}) reached at: ${projectPath}` ); return files; } // Security: Resolve current path and verify it's within root boundary const resolvedPath = path.resolve(projectPath); if (!resolvedPath.startsWith(rootPath)) { console.warn( `Security: Path traversal attempt detected. Path ${resolvedPath} is outside root ${rootPath}` ); return files; } try { const entries = await fs.readdir(resolvedPath, { withFileTypes: true }); for (const entry of entries) { // Skip hidden directories and excluded directories if (entry.isDirectory()) { if (entry.name.startsWith('.') || EXCLUDED_DIRECTORIES.has(entry.name)) { continue; } const subFiles = await findSourceFiles( path.join(resolvedPath, entry.name), rootPath, currentDepth + 1 ); files.push(...subFiles); } else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) { files.push(path.join(resolvedPath, entry.name)); } } } catch (error) { // Only log non-permission errors to avoid noise if ( error instanceof Error && !error.message.includes('EPERM') && !error.message.includes('EACCES') ) { console.warn('Warning reading directory:', error); } } return files; } async function detectTechnologies(projectPath: string): Promise<string[]> { const technologies: string[] = []; try { // Check package.json for Node.js technologies const packageJsonPath = path.join(projectPath, 'package.json'); try { const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8')); const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; Object.keys(deps).forEach(dep => { if (dep.includes('react')) technologies.push('React'); if (dep.includes('vue')) technologies.push('Vue'); if (dep.includes('angular')) technologies.push('Angular'); if (dep.includes('express')) technologies.push('Express'); if (dep.includes('fastify')) technologies.push('Fastify'); // Cloud SDKs if (dep.includes('aws-sdk') || dep.includes('@aws-sdk')) technologies.push('AWS SDK'); if (dep.includes('google-cloud') || dep.includes('@google-cloud')) technologies.push('GCP SDK'); if (dep.includes('azure') || dep.includes('@azure')) technologies.push('Azure SDK'); }); } catch { // package.json not found or invalid } // Check for other technology indicators const files = await fs.readdir(projectPath); // Container technologies if (files.includes('Dockerfile')) technologies.push('Docker'); if (files.includes('docker-compose.yml') || files.includes('docker-compose.yaml')) technologies.push('Docker Compose'); // Kubernetes if (files.includes('kubernetes.yaml') || files.includes('k8s.yaml')) technologies.push('Kubernetes'); if (files.some(f => f.endsWith('.yaml') || f.endsWith('.yml'))) { const yamlFiles = files.filter(f => f.endsWith('.yaml') || f.endsWith('.yml')); for (const yamlFile of yamlFiles) { try { const content = await fs.readFile(path.join(projectPath, yamlFile), 'utf-8'); if (content.includes('apiVersion:') && content.includes('kind:')) { technologies.push('Kubernetes'); break; } } catch { // Skip unreadable files } } } // Infrastructure as Code if (files.some(f => f.endsWith('.tf') || f.endsWith('.tfvars'))) technologies.push('Terraform'); if (files.includes('cloudformation.yaml') || files.includes('cloudformation.yml')) technologies.push('CloudFormation'); if (files.includes('ansible.yml') || files.includes('playbook.yml')) technologies.push('Ansible'); // Cloud-specific files if (files.includes('.aws') || files.includes('aws-config.yml')) technologies.push('AWS'); if (files.includes('gcp-config.json') || files.includes('.gcp')) technologies.push('GCP'); if (files.includes('azure-pipelines.yml') || files.includes('.azure')) technologies.push('Azure'); // DevOps and CI/CD if (files.includes('.github')) technologies.push('GitHub Actions'); if (files.includes('.gitlab-ci.yml')) technologies.push('GitLab CI'); if (files.includes('Jenkinsfile')) technologies.push('Jenkins'); if (files.includes('azure-pipelines.yml')) technologies.push('Azure DevOps'); // Monitoring and observability if (files.includes('prometheus.yml')) technologies.push('Prometheus'); if (files.includes('grafana.yml') || files.includes('grafana.json')) technologies.push('Grafana'); if (files.includes('jaeger.yml')) technologies.push('Jaeger'); // Language-specific if (files.includes('requirements.txt')) technologies.push('Python'); if (files.includes('Gemfile')) technologies.push('Ruby'); if (files.includes('pom.xml')) technologies.push('Maven/Java'); if (files.includes('Cargo.toml')) technologies.push('Rust'); if (files.includes('go.mod')) technologies.push('Go'); // Check for cloud provider specific directories/files recursively await checkCloudProviderIndicators(projectPath, technologies); } catch (error) { console.warn('Technology detection warning:', error); } return [...new Set(technologies)]; } /** * Enhanced cloud provider detection based on Tosin Akinosho's expertise * Principal Solution Architect at RedHat, specializing in AWS, GCP, Azure, Docker, Kubernetes, Terraform */ async function checkCloudProviderIndicators( projectPath: string, technologies: string[] ): Promise<void> { try { const entries = await fs.readdir(projectPath, { withFileTypes: true }); for (const entry of entries) { if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') { const dirPath = path.join(projectPath, entry.name); // AWS indicators if ( entry.name.includes('aws') || entry.name.includes('lambda') || entry.name.includes('ec2') ) { technologies.push('AWS'); } // GCP indicators if ( entry.name.includes('gcp') || entry.name.includes('google-cloud') || entry.name.includes('gke') ) { technologies.push('GCP'); } // Azure indicators if (entry.name.includes('azure') || entry.name.includes('aks')) { technologies.push('Azure'); } // Kubernetes indicators if ( entry.name.includes('k8s') || entry.name.includes('kubernetes') || entry.name.includes('helm') ) { technologies.push('Kubernetes'); } // Terraform indicators if (entry.name.includes('terraform') || entry.name.includes('tf')) { technologies.push('Terraform'); } // Check for terraform files in subdirectories try { const subFiles = await fs.readdir(dirPath); if (subFiles.some(f => f.endsWith('.tf') || f.endsWith('.tfvars'))) { technologies.push('Terraform'); } if (subFiles.some(f => f.includes('helm') || f.endsWith('.yaml') || f.endsWith('.yml'))) { // Check if it's Kubernetes YAML for (const file of subFiles.filter(f => f.endsWith('.yaml') || f.endsWith('.yml'))) { try { const content = await fs.readFile(path.join(dirPath, file), 'utf-8'); if (content.includes('apiVersion:') && content.includes('kind:')) { technologies.push('Kubernetes'); break; } } catch { // Skip unreadable files } } } } catch { // Skip unreadable directories } } } } catch (error) { console.warn('Cloud provider detection warning:', error); } } async function detectArchitecturalPatterns(files: string[]): Promise<string[]> { const patterns: string[] = []; // Pattern detection based on file structure const fileNames = files.map(f => path.basename(f).toLowerCase()); const filePaths = files.map(f => f.toLowerCase()); // Traditional software patterns if (fileNames.some(name => name.includes('controller'))) patterns.push('MVC'); if (fileNames.some(name => name.includes('service'))) patterns.push('Service Layer'); if (fileNames.some(name => name.includes('repository'))) patterns.push('Repository Pattern'); if (fileNames.some(name => name.includes('factory'))) patterns.push('Factory Pattern'); if (fileNames.some(name => name.includes('adapter'))) patterns.push('Adapter Pattern'); if (fileNames.some(name => name.includes('facade'))) patterns.push('Facade Pattern'); if (fileNames.some(name => name.includes('observer'))) patterns.push('Observer Pattern'); // Cloud and DevOps patterns (specialized for Tosin's expertise) // Microservices patterns if (filePaths.some(path => path.includes('microservice') || path.includes('service'))) { patterns.push('Microservices Architecture'); } // Container patterns if (fileNames.some(name => name.includes('dockerfile'))) patterns.push('Containerization'); if (fileNames.some(name => name.includes('docker-compose'))) patterns.push('Multi-Container Application'); // Kubernetes patterns if (fileNames.some(name => name.includes('deployment.yaml') || name.includes('deployment.yml'))) { patterns.push('Kubernetes Deployment'); } if (fileNames.some(name => name.includes('service.yaml') || name.includes('service.yml'))) { patterns.push('Kubernetes Service Mesh'); } if (fileNames.some(name => name.includes('ingress'))) patterns.push('Ingress Controller'); if (fileNames.some(name => name.includes('configmap') || name.includes('secret'))) { patterns.push('Configuration Management'); } // Infrastructure as Code patterns if (fileNames.some(name => name.includes('.tf') || name.includes('terraform'))) { patterns.push('Infrastructure as Code (Terraform)'); } if (fileNames.some(name => name.includes('cloudformation'))) { patterns.push('Infrastructure as Code (CloudFormation)'); } // Cloud-native patterns if (fileNames.some(name => name.includes('lambda') || name.includes('function'))) { patterns.push('Serverless/FaaS'); } if (fileNames.some(name => name.includes('api-gateway') || name.includes('gateway'))) { patterns.push('API Gateway'); } if ( fileNames.some( name => name.includes('load-balancer') || name.includes('alb') || name.includes('nlb') ) ) { patterns.push('Load Balancing'); } // DevOps patterns if ( fileNames.some(name => name.includes('pipeline') || name.includes('ci') || name.includes('cd')) ) { patterns.push('CI/CD Pipeline'); } if (fileNames.some(name => name.includes('ansible') || name.includes('playbook'))) { patterns.push('Configuration Management (Ansible)'); } // Monitoring and observability patterns if (fileNames.some(name => name.includes('prometheus') || name.includes('metrics'))) { patterns.push('Metrics Collection'); } if (fileNames.some(name => name.includes('grafana') || name.includes('dashboard'))) { patterns.push('Observability Dashboard'); } if ( fileNames.some( name => name.includes('jaeger') || name.includes('zipkin') || name.includes('tracing') ) ) { patterns.push('Distributed Tracing'); } if ( fileNames.some( name => name.includes('logging') || name.includes('fluentd') || name.includes('logstash') ) ) { patterns.push('Centralized Logging'); } // Cloud provider specific patterns if (fileNames.some(name => name.includes('vpc') || name.includes('subnet'))) { patterns.push('Virtual Private Cloud'); } if (fileNames.some(name => name.includes('s3') || name.includes('bucket'))) { patterns.push('Object Storage'); } if (fileNames.some(name => name.includes('rds') || name.includes('database'))) { patterns.push('Managed Database'); } if ( fileNames.some(name => name.includes('eks') || name.includes('gke') || name.includes('aks')) ) { patterns.push('Managed Kubernetes'); } // Security patterns if (fileNames.some(name => name.includes('iam') || name.includes('rbac'))) { patterns.push('Identity and Access Management'); } if (fileNames.some(name => name.includes('security-group') || name.includes('firewall'))) { patterns.push('Network Security'); } if (fileNames.some(name => name.includes('vault') || name.includes('secrets'))) { patterns.push('Secret Management'); } // Data patterns if (fileNames.some(name => name.includes('etl') || name.includes('pipeline'))) { patterns.push('Data Pipeline'); } if ( fileNames.some( name => name.includes('kafka') || name.includes('pubsub') || name.includes('queue') ) ) { patterns.push('Event-Driven Architecture'); } return [...new Set(patterns)]; } async function performTreeSitterAnalysis(files: string[]): Promise<any> { const analyzer = new TreeSitterAnalyzer(); const architecturalElements = { apis: [] as string[], databases: [] as string[], frameworks: [] as string[], patterns: [] as string[], securityFindings: [] as string[], infrastructureResources: [] as string[], devopsTools: [] as string[], }; try { for (const filePath of files.slice(0, 50)) { // Limit to first 50 files for performance try { const analysis = await analyzer.analyzeFile(filePath); // Extract API endpoints and routes if (analysis.functions) { analysis.functions.forEach(func => { if (func.name && isApiFunction(func.name)) { architecturalElements.apis.push(`${func.name} (${filePath})`); } // Enhanced: Add security-sensitive functions if (func.securitySensitive) { architecturalElements.securityFindings.push( `Security-sensitive function: ${func.name} in ${filePath}` ); } }); } // Enhanced database and framework detection if (analysis.imports) { analysis.imports.forEach(imp => { if (isDatabaseImport(imp.module)) { architecturalElements.databases.push(`${imp.module} (${filePath})`); } if (isFrameworkImport(imp.module)) { architecturalElements.frameworks.push(`${imp.module} (${filePath})`); } // Enhanced: Add DevOps tools detection if (isDevOpsImport(imp.module)) { architecturalElements.devopsTools.push(`${imp.module} (${filePath})`); } // Enhanced: Track dangerous imports if (imp.isDangerous) { architecturalElements.securityFindings.push( `Dangerous import: ${imp.module} in ${filePath}${imp.reason ? ` - ${imp.reason}` : ''}` ); } }); } // Enhanced infrastructure analysis for enterprise DevOps if (analysis.infraStructure) { analysis.infraStructure.forEach(infra => { architecturalElements.patterns.push( `${infra.resourceType}: ${infra.name} (${infra.provider})` ); architecturalElements.infrastructureResources.push( `${infra.provider}: ${infra.resourceType} (${filePath})` ); // Enhanced: Track security risks in infrastructure if (infra.securityRisks.length > 0) { infra.securityRisks.forEach(risk => { architecturalElements.securityFindings.push( `Infrastructure security risk in ${filePath}: ${risk}` ); }); } }); } // Enhanced security analysis if (analysis.hasSecrets) { analysis.secrets.forEach(secret => { architecturalElements.securityFindings.push( `${secret.type} detected in ${filePath} at line ${secret.location.line} (confidence: ${secret.confidence})` ); }); } // Enhanced: Security issues from tree-sitter analysis if (analysis.securityIssues && analysis.securityIssues.length > 0) { analysis.securityIssues.forEach(issue => { architecturalElements.securityFindings.push( `${issue.severity.toUpperCase()}: ${issue.message} in ${filePath} at line ${issue.location.line}` ); }); } // Enhanced: Architectural violations if (analysis.architecturalViolations && analysis.architecturalViolations.length > 0) { analysis.architecturalViolations.forEach(violation => { architecturalElements.patterns.push( `Architectural violation in ${filePath}: ${violation.message}` ); }); } // Enhanced: Track language-specific patterns if (analysis.language) { switch (analysis.language) { case 'python': architecturalElements.patterns.push(`Python microservice detected (${filePath})`); break; case 'typescript': case 'javascript': architecturalElements.patterns.push(`Node.js application detected (${filePath})`); break; case 'yaml': architecturalElements.patterns.push( `Configuration/Infrastructure YAML (${filePath})` ); break; case 'hcl': architecturalElements.patterns.push(`Terraform infrastructure (${filePath})`); break; case 'dockerfile': architecturalElements.patterns.push(`Container configuration (${filePath})`); break; case 'bash': architecturalElements.patterns.push(`Shell automation script (${filePath})`); break; } } } catch (fileError) { // Gracefully skip files that can't be analyzed console.warn(`Skipping file analysis for ${filePath}:`, fileError); } } // Deduplicate results architecturalElements.apis = [...new Set(architecturalElements.apis)]; architecturalElements.databases = [...new Set(architecturalElements.databases)]; architecturalElements.frameworks = [...new Set(architecturalElements.frameworks)]; architecturalElements.patterns = [...new Set(architecturalElements.patterns)]; architecturalElements.securityFindings = [...new Set(architecturalElements.securityFindings)]; architecturalElements.infrastructureResources = [ ...new Set(architecturalElements.infrastructureResources), ]; architecturalElements.devopsTools = [...new Set(architecturalElements.devopsTools)]; return architecturalElements; } catch (error) { console.warn('Tree-sitter analysis failed, using fallback:', error); return { apis: [], databases: [], frameworks: [], patterns: [], securityFindings: [], infrastructureResources: [], devopsTools: [], }; } } /** * Helper functions for intelligent detection */ function isApiFunction(name: string): boolean { const apiPatterns = [ /^(get|post|put|delete|patch)_/i, /^handle_/i, /^endpoint_/i, /^route_/i, /^api_/i, /controller$/i, /handler$/i, ]; return apiPatterns.some(pattern => pattern.test(name)); } function isDatabaseImport(module: string): boolean { const dbPatterns = [ 'mongoose', 'sequelize', 'typeorm', 'prisma', 'knex', 'mongodb', 'mysql', 'postgresql', 'sqlite', 'redis', 'firebase', 'dynamodb', 'cassandra', 'neo4j', 'psycopg2', 'pymongo', 'sqlalchemy', 'django.db', ]; return dbPatterns.some(pattern => module.toLowerCase().includes(pattern)); } function isFrameworkImport(module: string): boolean { const frameworkPatterns = [ 'express', 'fastify', 'koa', 'hapi', 'nest', 'flask', 'django', 'fastapi', 'tornado', 'spring', 'gin', 'echo', 'fiber', 'react', 'vue', 'angular', 'svelte', 'next', 'nuxt', 'gatsby', ]; return frameworkPatterns.some(pattern => module.toLowerCase().includes(pattern)); } function isDevOpsImport(module: string): boolean { const devopsPatterns = [ 'docker', 'kubernetes', 'terraform', 'ansible', 'helm', 'aws-sdk', '@aws-sdk', 'boto3', 'azure', '@azure', 'google-cloud', '@google-cloud', 'gcp', 'prometheus', 'grafana', 'jaeger', 'zipkin', 'jenkins', 'gitlab', 'github', 'ci', 'cd', 'vault', 'consul', 'etcd', 'redis', 'nginx', 'elasticsearch', 'logstash', 'kibana', 'fluentd', 'kafka', 'rabbitmq', 'celery', 'airflow', ]; return devopsPatterns.some(pattern => module.toLowerCase().includes(pattern)); } async function generateUpdatePlanContent( reviewResults: AdrReviewResult[], _codeAnalysis: CodeAnalysisResult, _projectPath: string ): Promise<string> { const highPriority = reviewResults.filter(r => r.complianceScore < 5); const mediumPriority = reviewResults.filter(r => r.complianceScore >= 5 && r.complianceScore < 8); return ` ## Update Plan ### Phase 1: Critical Updates (${highPriority.length} ADRs) ${highPriority .map( adr => ` - **${adr.title}** - Score: ${adr.complianceScore}/10 - Actions: ${adr.recommendations.actions.join(', ')} - Timeline: Immediate (1-2 weeks) ` ) .join('\n')} ### Phase 2: Moderate Updates (${mediumPriority.length} ADRs) ${mediumPriority .map( adr => ` - **${adr.title}** - Score: ${adr.complianceScore}/10 - Actions: ${adr.recommendations.actions.join(', ')} - Timeline: Medium term (2-4 weeks) ` ) .join('\n')} ### Implementation Strategy 1. **Document Review**: Update ADRs with current implementation status 2. **Code Alignment**: Implement missing architectural elements 3. **Process Improvement**: Establish regular ADR compliance checks 4. **Team Training**: Ensure understanding of ADR importance ### Success Metrics - Target compliance score: 8.0+ - Gap reduction: 80% - Process adherence: 95% `; } function calculateDocumentationQuality(results: AdrReviewResult[]): number { // Simplified calculation based on compliance scores return results.reduce((sum, r) => sum + r.complianceScore, 0) / results.length; } function calculateImplementationFidelity(results: AdrReviewResult[]): number { const implemented = results.filter(r => r.codeCompliance.implemented).length; return (implemented / results.length) * 10; } function calculateArchitecturalConsistency(results: AdrReviewResult[]): number { const consistent = results.filter(r => r.complianceScore >= 7).length; return (consistent / results.length) * 10; }

Latest Blog Posts

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/tosin2013/mcp-adr-analysis-server'

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