/**
* 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;
}