Skip to main content
Glama

update_existing_documentation

Analyzes and updates existing documentation by comparing it with code changes, detecting gaps, and suggesting improvements while preserving formatting.

Instructions

Intelligently analyze and update existing documentation using memory insights and code comparison

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
analysisIdYesRepository analysis ID from analyze_repository tool
docsPathYesPath to existing documentation directory
compareModeNoMode of comparison between code and documentationcomprehensive
updateStrategyNoHow aggressively to suggest updatesmoderate
preserveStyleNoPreserve existing documentation style and formatting
focusAreasNoSpecific areas to focus updates on (e.g., "dependencies", "scripts", "api")

Implementation Reference

  • Tool registration: exports the MCP Tool object defining name, description, and inputSchema for 'update_existing_documentation'
    export const updateExistingDocumentation: Tool = { name: "update_existing_documentation", description: "Intelligently analyze and update existing documentation using memory insights and code comparison", inputSchema: { type: "object", properties: { analysisId: { type: "string", description: "Repository analysis ID from analyze_repository tool", }, docsPath: { type: "string", description: "Path to existing documentation directory", }, compareMode: { type: "string", enum: ["comprehensive", "gap-detection", "accuracy-check"], default: "comprehensive", description: "Mode of comparison between code and documentation", }, updateStrategy: { type: "string", enum: ["conservative", "moderate", "aggressive"], default: "moderate", description: "How aggressively to suggest updates", }, preserveStyle: { type: "boolean", default: true, description: "Preserve existing documentation style and formatting", }, focusAreas: { type: "array", items: { type: "string" }, description: 'Specific areas to focus updates on (e.g., "dependencies", "scripts", "api")', }, }, required: ["analysisId", "docsPath"], }, };
  • Tool handler: entry point function that instantiates DocumentationUpdateEngine and executes the core update logic with input arguments
    export async function handleUpdateExistingDocumentation( args: any, ): Promise<UpdateResult> { const engine = new DocumentationUpdateEngine(); return await engine.updateExistingDocumentation(args); }
  • Core handler logic in DocumentationUpdateEngine: orchestrates loading analysis, memory insights, doc analysis, comparison, recommendations, and metrics calculation
    async updateExistingDocumentation( options: UpdateOptions, ): Promise<UpdateResult> { // 1. Load repository analysis and memory insights const analysis = await this.getRepositoryAnalysis(options.analysisId); this.codeAnalysis = analysis; // 2. Load memory insights for intelligent comparison await this.loadMemoryInsights(analysis, options); // 3. Analyze existing documentation structure and content const existingDocs = await this.analyzeExistingDocumentation( options.docsPath, ); this.existingDocs = existingDocs; // 4. Perform comprehensive code-documentation comparison const comparison = await this.performCodeDocumentationComparison( analysis, existingDocs, options, ); // 5. Generate memory-informed update recommendations const recommendations = await this.generateUpdateRecommendations( comparison, options, ); // 6. Calculate metrics and confidence scores const updateMetrics = this.calculateUpdateMetrics( comparison, recommendations, ); return { success: true, analysisPerformed: comparison, recommendations, memoryInsights: this.memoryInsights, updateMetrics, nextSteps: this.generateMemoryInformedNextSteps( comparison, recommendations, ), }; }
  • TypeScript interface defining the input options structure for the tool, matching the inputSchema
    interface UpdateOptions { analysisId: string; docsPath: string; compareMode: "comprehensive" | "gap-detection" | "accuracy-check"; updateStrategy: "conservative" | "moderate" | "aggressive"; preserveStyle: boolean; focusAreas?: string[]; }
  • DocumentationUpdateEngine class containing all helper methods for documentation analysis, gap detection, comparison, recommendation generation, and memory integration
    class DocumentationUpdateEngine { private memoryInsights: any = null; private codeAnalysis: any = null; private existingDocs: Map<string, any> = new Map(); async updateExistingDocumentation( options: UpdateOptions, ): Promise<UpdateResult> { // 1. Load repository analysis and memory insights const analysis = await this.getRepositoryAnalysis(options.analysisId); this.codeAnalysis = analysis; // 2. Load memory insights for intelligent comparison await this.loadMemoryInsights(analysis, options); // 3. Analyze existing documentation structure and content const existingDocs = await this.analyzeExistingDocumentation( options.docsPath, ); this.existingDocs = existingDocs; // 4. Perform comprehensive code-documentation comparison const comparison = await this.performCodeDocumentationComparison( analysis, existingDocs, options, ); // 5. Generate memory-informed update recommendations const recommendations = await this.generateUpdateRecommendations( comparison, options, ); // 6. Calculate metrics and confidence scores const updateMetrics = this.calculateUpdateMetrics( comparison, recommendations, ); return { success: true, analysisPerformed: comparison, recommendations, memoryInsights: this.memoryInsights, updateMetrics, nextSteps: this.generateMemoryInformedNextSteps( comparison, recommendations, ), }; } private async getRepositoryAnalysis(analysisId: string): Promise<any> { // Try to get analysis from memory system first try { const memoryRecall = await handleMemoryRecall({ query: analysisId, type: "analysis", limit: 1, }); // Handle the memory recall result structure if ( memoryRecall && memoryRecall.memories && memoryRecall.memories.length > 0 ) { const memory = memoryRecall.memories[0]; // Handle wrapped content structure if ( memory.data && memory.data.content && Array.isArray(memory.data.content) ) { // Extract the JSON from the first text content const firstContent = memory.data.content[0]; if ( firstContent && firstContent.type === "text" && firstContent.text ) { try { return JSON.parse(firstContent.text); } catch (parseError) { console.warn( "Failed to parse analysis content from memory:", parseError, ); return memory.data; } } } // Try direct content access (legacy format) if (memory.content) { return memory.content; } // Try data field if (memory.data) { return memory.data; } } } catch (error) { console.warn("Failed to retrieve from memory system:", error); } // Fallback to reading from cached analysis file const analysisPath = path.join( ".documcp", "analyses", `${analysisId}.json`, ); try { const content = await fs.readFile(analysisPath, "utf-8"); return JSON.parse(content); } catch { throw new Error( `Repository analysis with ID '${analysisId}' not found. Please run analyze_repository first.`, ); } } private async loadMemoryInsights( analysis: any, options: UpdateOptions, ): Promise<void> { try { // Get similar projects that had successful documentation updates const similarProjectsQuery = `${ analysis.metadata?.primaryLanguage || "" } ${analysis.metadata?.ecosystem || ""} documentation update`; const similarProjects = await handleMemoryRecall({ query: similarProjectsQuery, type: "recommendation", limit: 10, }); // Get patterns for successful documentation updates const updatePatternsQuery = "documentation update successful patterns gaps outdated"; const updatePatterns = await handleMemoryRecall({ query: updatePatternsQuery, type: "configuration", limit: 5, }); // Get memory-enhanced analysis for this specific update task const enhancedAnalysis = await handleMemoryIntelligentAnalysis({ projectPath: analysis.projectPath || "", baseAnalysis: analysis, }); // Get memory-enhanced recommendations for update strategy const enhancedRecommendations = await handleMemoryEnhancedRecommendation({ projectPath: analysis.projectPath || "", baseRecommendation: { updateStrategy: options.updateStrategy, compareMode: options.compareMode, focusAreas: options.focusAreas || [], }, projectFeatures: { ecosystem: analysis.metadata?.ecosystem || "unknown", primaryLanguage: analysis.metadata?.primaryLanguage || "unknown", complexity: analysis.complexity || "medium", hasTests: analysis.structure?.hasTests || false, hasCI: analysis.structure?.hasCI || false, docStructure: "existing", // Indicates we're updating existing docs }, }); this.memoryInsights = { similarProjects: similarProjects.memories || [], updatePatterns: updatePatterns.memories || [], enhancedAnalysis: enhancedAnalysis, enhancedRecommendations: enhancedRecommendations, successfulUpdatePatterns: this.extractUpdatePatterns( similarProjects.memories || [], ), commonGapTypes: this.extractCommonGapTypes( similarProjects.memories || [], ), }; } catch (error) { console.warn("Failed to load memory insights:", error); this.memoryInsights = { similarProjects: [], updatePatterns: [], enhancedAnalysis: null, enhancedRecommendations: null, successfulUpdatePatterns: [], commonGapTypes: {}, }; } } private extractUpdatePatterns(projects: any[]): any[] { return projects .filter( (p) => p.content?.updatePatterns || p.content?.documentationUpdates, ) .map((p) => p.content?.updatePatterns || p.content?.documentationUpdates) .flat() .filter(Boolean); } private extractCommonGapTypes(projects: any[]): Record<string, number> { const gapTypes: Record<string, number> = {}; projects.forEach((p) => { const gaps = p.content?.documentationGaps || []; gaps.forEach((gap: any) => { const type = gap.type || "unknown"; gapTypes[type] = (gapTypes[type] || 0) + 1; }); }); return gapTypes; } private async analyzeExistingDocumentation( docsPath: string, ): Promise<Map<string, any>> { const docs = new Map<string, any>(); try { await this.recursivelyAnalyzeDocuments(docsPath, docs); } catch (error) { console.warn("Failed to analyze existing documentation:", error); } return docs; } private async recursivelyAnalyzeDocuments( dirPath: string, docs: Map<string, any>, relativePath: string = "", ): Promise<void> { try { const entries = await fs.readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); const docPath = path.join(relativePath, entry.name); if (entry.isDirectory()) { await this.recursivelyAnalyzeDocuments(fullPath, docs, docPath); } else if (entry.name.endsWith(".md") || entry.name.endsWith(".mdx")) { try { const content = await fs.readFile(fullPath, "utf-8"); const analysis = this.analyzeDocumentContent(content, docPath); docs.set(docPath, { content, analysis, lastModified: (await fs.stat(fullPath)).mtime, path: fullPath, }); } catch (error) { console.warn(`Failed to read document ${fullPath}:`, error); } } } } catch (error) { console.warn(`Failed to read directory ${dirPath}:`, error); } } private analyzeDocumentContent(content: string, filePath: string): any { return { type: this.inferDocumentType(filePath, content), sections: this.extractSections(content), codeBlocks: this.extractCodeBlocks(content), links: this.extractLinks(content), lastUpdated: this.extractLastUpdated(content), version: this.extractVersion(content), dependencies: this.extractMentionedDependencies(content), features: this.extractDocumentedFeatures(content), wordCount: content.split(/\s+/).length, headingStructure: this.extractHeadingStructure(content), }; } private inferDocumentType(filePath: string, content: string): string { const fileName = path.basename(filePath).toLowerCase(); const pathParts = filePath.toLowerCase().split(path.sep); // Diataxis categories if (pathParts.includes("tutorials")) return "tutorial"; if (pathParts.includes("how-to") || pathParts.includes("howto")) return "how-to"; if (pathParts.includes("reference")) return "reference"; if (pathParts.includes("explanation")) return "explanation"; // Common documentation types if (fileName.includes("readme")) return "readme"; if (fileName.includes("getting-started") || fileName.includes("quickstart")) return "getting-started"; if (fileName.includes("api")) return "api-reference"; if (fileName.includes("install") || fileName.includes("setup")) return "installation"; if (fileName.includes("deploy")) return "deployment"; if (fileName.includes("config")) return "configuration"; // Infer from content if ( content.includes("# Getting Started") || content.includes("## Getting Started") ) return "getting-started"; if (content.includes("# API") || content.includes("## API")) return "api-reference"; if ( content.includes("# Installation") || content.includes("## Installation") ) return "installation"; return "general"; } private extractSections(content: string): any[] { const sections: any[] = []; const lines = content.split("\n"); let currentSection: any = null; for (let i = 0; i < lines.length; i++) { const line = lines[i]; const headingMatch = line.match(/^(#{1,6})\s+(.+)/); if (headingMatch) { if (currentSection) { sections.push(currentSection); } currentSection = { level: headingMatch[1].length, title: headingMatch[2], startLine: i + 1, content: [], }; } else if (currentSection) { currentSection.content.push(line); } } if (currentSection) { sections.push(currentSection); } return sections.map((section) => ({ ...section, content: section.content.join("\n"), wordCount: section.content.join(" ").split(/\s+/).length, })); } private extractCodeBlocks(content: string): any[] { const codeBlocks: any[] = []; const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g; let match; while ((match = codeBlockRegex.exec(content)) !== null) { codeBlocks.push({ language: match[1] || "text", code: match[2], startIndex: match.index, endIndex: match.index + match[0].length, }); } return codeBlocks; } private extractLinks(content: string): any[] { const links: any[] = []; const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g; let match; while ((match = linkRegex.exec(content)) !== null) { links.push({ text: match[1], url: match[2], isInternal: !match[2].startsWith("http"), startIndex: match.index, }); } return links; } private extractLastUpdated(content: string): string | null { const updateMatch = content.match( /(?:last updated|updated|modified):\s*(.+)/i, ); return updateMatch ? updateMatch[1] : null; } private extractVersion(content: string): string | null { const versionMatch = content.match(/(?:version|v)[\s:]+([\d.]+)/i); return versionMatch ? versionMatch[1] : null; } private extractMentionedDependencies(content: string): string[] { const dependencies: Set<string> = new Set(); // Extract from npm install commands const npmMatches = content.match(/npm install\s+([^`\n]+)/g); if (npmMatches) { npmMatches.forEach((match) => { const packages = match.replace("npm install", "").trim().split(/\s+/); packages.forEach((pkg) => { if (pkg && !pkg.startsWith("-")) { dependencies.add(pkg); } }); }); } // Extract from import statements const importMatches = content.match(/import.*from\s+['"]([^'"]+)['"]/g); if (importMatches) { importMatches.forEach((match) => { const packageMatch = match.match(/from\s+['"]([^'"]+)['"]/); if (packageMatch && !packageMatch[1].startsWith(".")) { dependencies.add(packageMatch[1]); } }); } return Array.from(dependencies); } private extractDocumentedFeatures(content: string): string[] { const features: Set<string> = new Set(); // Extract function names from code blocks const functionMatches = content.match( /(?:function|const|let|var)\s+(\w+)/g, ); if (functionMatches) { functionMatches.forEach((match) => { const functionMatch = match.match(/(?:function|const|let|var)\s+(\w+)/); if (functionMatch) { features.add(functionMatch[1]); } }); } // Extract API endpoints const apiMatches = content.match( /(?:GET|POST|PUT|DELETE|PATCH)\s+([/\w-]+)/g, ); if (apiMatches) { apiMatches.forEach((match) => { const endpointMatch = match.match( /(?:GET|POST|PUT|DELETE|PATCH)\s+([/\w-]+)/, ); if (endpointMatch) { features.add(endpointMatch[1]); } }); } // Extract mentioned features from headings const headings = content.match(/#{1,6}\s+(.+)/g); if (headings) { headings.forEach((heading) => { const headingText = heading.replace(/#{1,6}\s+/, "").toLowerCase(); if ( headingText.includes("feature") || headingText.includes("functionality") ) { features.add(headingText); } }); } return Array.from(features); } private extractHeadingStructure(content: string): any[] { const headings: any[] = []; const lines = content.split("\n"); lines.forEach((line, index) => { const headingMatch = line.match(/^(#{1,6})\s+(.+)/); if (headingMatch) { headings.push({ level: headingMatch[1].length, text: headingMatch[2], line: index + 1, }); } }); return headings; } private async performCodeDocumentationComparison( analysis: any, existingDocs: Map<string, any>, _options: UpdateOptions, ): Promise<CodeDocumentationComparison> { const codeFeatures = this.extractCodeFeatures(analysis); const documentedFeatures = this.extractAllDocumentedFeatures(existingDocs); const gaps = await this.detectDocumentationGaps( codeFeatures, documentedFeatures, _options, ); const outdatedSections = await this.detectOutdatedSections( analysis, existingDocs, ); const accuracyIssues = await this.detectAccuracyIssues( analysis, existingDocs, ); return { codeFeatures, documentedFeatures, gaps, outdatedSections, accuracyIssues, }; } private extractCodeFeatures(analysis: any): any[] { const features: any[] = []; // Extract from dependencies if (analysis.dependencies?.packages) { analysis.dependencies.packages.forEach((pkg: string) => { features.push({ type: "dependency", name: pkg, source: "package.json", }); }); } // Extract from scripts const packageJson = this.findPackageJsonInAnalysis(analysis); if (packageJson?.scripts) { Object.keys(packageJson.scripts).forEach((script) => { features.push({ type: "script", name: script, command: packageJson.scripts[script], source: "package.json", }); }); } // Extract from file structure if (analysis.structure) { if (analysis.structure.hasTests) { features.push({ type: "testing", name: "test suite", source: "structure", }); } if (analysis.structure.hasCI) { features.push({ type: "ci-cd", name: "continuous integration", source: "structure", }); } } // Extract from technologies if (analysis.technologies) { Object.entries(analysis.technologies).forEach(([key, value]) => { if (value) { features.push({ type: "technology", name: key, value: value, source: "analysis", }); } }); } return features; } private findPackageJsonInAnalysis(analysis: any): any { const files = analysis.files || []; const packageFile = files.find((f: any) => f.name === "package.json"); if (packageFile?.content) { try { return JSON.parse(packageFile.content); } catch { return null; } } return null; } private extractAllDocumentedFeatures(existingDocs: Map<string, any>): any[] { const allFeatures: any[] = []; existingDocs.forEach((doc, docPath) => { const features = doc.analysis?.features || []; const dependencies = doc.analysis?.dependencies || []; features.forEach((feature: string) => { allFeatures.push({ name: feature, source: docPath, type: "documented-feature", }); }); dependencies.forEach((dep: string) => { allFeatures.push({ name: dep, source: docPath, type: "documented-dependency", }); }); }); return allFeatures; } private async detectDocumentationGaps( codeFeatures: any[], documentedFeatures: any[], _options: UpdateOptions, ): Promise<DocumentationGap[]> { const gaps: DocumentationGap[] = []; const memoryGapPatterns = this.memoryInsights?.commonGapTypes || {}; // Find features in code that aren't documented codeFeatures.forEach((codeFeature) => { const isDocumented = documentedFeatures.some((docFeature) => this.featuresMatch(codeFeature, docFeature), ); if (!isDocumented) { const severity = this.determineGapSeverity( codeFeature, memoryGapPatterns, ); const suggestedUpdate = this.generateGapSuggestion( codeFeature, _options, ); gaps.push({ type: "missing", location: `${codeFeature.source} -> documentation`, description: `${codeFeature.type} '${codeFeature.name}' exists in code but is not documented`, severity, suggestedUpdate, memoryEvidence: this.findMemoryEvidenceForGap(codeFeature), }); } }); // Find documented features that no longer exist in code documentedFeatures.forEach((docFeature) => { const existsInCode = codeFeatures.some((codeFeature) => this.featuresMatch(codeFeature, docFeature), ); if (!existsInCode) { gaps.push({ type: "outdated", location: docFeature.source, description: `Documented feature '${docFeature.name}' no longer exists in code`, severity: "medium", suggestedUpdate: `Remove or update documentation for '${docFeature.name}'`, memoryEvidence: this.findMemoryEvidenceForOutdated(docFeature), }); } }); return gaps; } private featuresMatch(codeFeature: any, docFeature: any): boolean { // Exact name match if (codeFeature.name === docFeature.name) return true; // Type-specific matching if ( codeFeature.type === "dependency" && docFeature.type === "documented-dependency" ) { return codeFeature.name === docFeature.name; } // Partial match for similar names const codeName = codeFeature.name.toLowerCase(); const docName = docFeature.name.toLowerCase(); return codeName.includes(docName) || docName.includes(codeName); } private determineGapSeverity( codeFeature: any, memoryGapPatterns: Record<string, number>, ): "low" | "medium" | "high" | "critical" { // High importance features if ( codeFeature.type === "script" && ["start", "dev", "build", "test"].includes(codeFeature.name) ) { return "high"; } if ( codeFeature.type === "dependency" && this.isCriticalDependency(codeFeature.name) ) { return "high"; } if (codeFeature.type === "testing" || codeFeature.type === "ci-cd") { return "medium"; } // Check memory patterns for common gaps const gapFrequency = memoryGapPatterns[codeFeature.type] || 0; if (gapFrequency > 5) return "medium"; // Common gap type if (gapFrequency > 2) return "low"; return "low"; } private isCriticalDependency(depName: string): boolean { const criticalDeps = [ "react", "vue", "angular", "express", "fastify", "next", "nuxt", "gatsby", "typescript", "jest", "mocha", "webpack", "vite", "rollup", ]; return criticalDeps.some((critical) => depName.includes(critical)); } private generateGapSuggestion( codeFeature: any, _options: UpdateOptions, ): string { switch (codeFeature.type) { case "script": return `Add documentation for the '${codeFeature.name}' script: \`npm run ${codeFeature.name}\``; case "dependency": return `Document the '${codeFeature.name}' dependency and its usage`; case "testing": return `Add testing documentation explaining how to run and write tests`; case "ci-cd": return `Document the CI/CD pipeline and deployment process`; case "technology": return `Add explanation for ${codeFeature.name}: ${codeFeature.value}`; default: return `Document the ${codeFeature.type} '${codeFeature.name}'`; } } private findMemoryEvidenceForGap(codeFeature: any): any[] { return ( this.memoryInsights?.similarProjects .filter( (p: any) => p.content?.gaps?.some((gap: any) => gap.type === codeFeature.type), ) .slice(0, 3) || [] ); } private findMemoryEvidenceForOutdated(docFeature: any): any[] { return ( this.memoryInsights?.similarProjects .filter( (p: any) => p.content?.outdatedSections?.some( (section: any) => section.feature === docFeature.name, ), ) .slice(0, 3) || [] ); } private async detectOutdatedSections( analysis: any, existingDocs: Map<string, any>, ): Promise<any[]> { const outdatedSections: any[] = []; existingDocs.forEach((doc, docPath) => { const sections = doc.analysis?.sections || []; sections.forEach((section: any) => { const isOutdated = this.checkSectionOutdated(section, analysis); if (isOutdated) { outdatedSections.push({ location: docPath, section: section.title, reason: isOutdated.reason, confidence: isOutdated.confidence, suggestedUpdate: isOutdated.suggestedUpdate, }); } }); }); return outdatedSections; } private checkSectionOutdated(section: any, analysis: any): any { const sectionContent = section.content.toLowerCase(); // Check for outdated Node.js versions const nodeVersionMatch = sectionContent.match(/node(?:\.js)?\s+(\d+)/); if (nodeVersionMatch) { const documentedVersion = parseInt(nodeVersionMatch[1], 10); const currentRecommended = 18; // Current LTS if (documentedVersion < currentRecommended - 2) { return { reason: `Documented Node.js version ${documentedVersion} is outdated`, confidence: 0.9, suggestedUpdate: `Update to recommend Node.js ${currentRecommended}+`, }; } } // Check for outdated package names const packageJson = this.findPackageJsonInAnalysis(analysis); if (packageJson?.dependencies) { const currentDeps = Object.keys(packageJson.dependencies); // Look for documented packages that are no longer dependencies for (const dep of currentDeps) { if (sectionContent.includes(dep)) { const version = packageJson.dependencies[dep]; if ( sectionContent.includes(dep) && !sectionContent.includes(version) ) { return { reason: `Package version information may be outdated for ${dep}`, confidence: 0.7, suggestedUpdate: `Update ${dep} version references to ${version}`, }; } } } } return null; } private async detectAccuracyIssues( analysis: any, existingDocs: Map<string, any>, ): Promise<any[]> { const accuracyIssues: any[] = []; existingDocs.forEach((doc, docPath) => { const codeBlocks = doc.analysis?.codeBlocks || []; codeBlocks.forEach((codeBlock: any, index: number) => { const issues = this.validateCodeBlock(codeBlock, analysis); issues.forEach((issue) => { accuracyIssues.push({ location: `${docPath}:code-block-${index}`, type: issue.type, description: issue.description, severity: issue.severity, suggestedFix: issue.suggestedFix, }); }); }); }); return accuracyIssues; } private validateCodeBlock(codeBlock: any, analysis: any): any[] { const issues: any[] = []; const code = codeBlock.code; // Check npm install commands against actual dependencies const npmInstallMatches = code.match(/npm install\s+([^`\n]+)/g); if (npmInstallMatches) { const packageJson = this.findPackageJsonInAnalysis(analysis); const actualDeps = packageJson ? Object.keys(packageJson.dependencies || {}) : []; npmInstallMatches.forEach((match: string) => { const packages = match.replace("npm install", "").trim().split(/\s+/); packages.forEach((pkg: string) => { if (pkg && !pkg.startsWith("-") && !actualDeps.includes(pkg)) { issues.push({ type: "incorrect-dependency", description: `npm install command includes '${pkg}' which is not in package.json`, severity: "medium", suggestedFix: `Remove '${pkg}' or add it to dependencies`, }); } }); }); } // Check for outdated import syntax if ( code.includes("require(") && analysis.metadata?.primaryLanguage === "TypeScript" ) { issues.push({ type: "outdated-syntax", description: "Using require() syntax in TypeScript project", severity: "low", suggestedFix: "Update to ES6 import syntax", }); } return issues; } private async generateUpdateRecommendations( comparison: CodeDocumentationComparison, _options: UpdateOptions, ): Promise<UpdateRecommendation[]> { const recommendations: UpdateRecommendation[] = []; // Generate recommendations for gaps for (const gap of comparison.gaps) { if ( gap.severity === "critical" || gap.severity === "high" || (gap.severity === "medium" && _options.updateStrategy !== "conservative") ) { const recommendation = await this.generateGapRecommendation( gap, _options, ); recommendations.push(recommendation); } } // Generate recommendations for outdated sections for (const outdated of comparison.outdatedSections) { const recommendation = await this.generateOutdatedRecommendation( outdated, _options, ); recommendations.push(recommendation); } // Generate recommendations for accuracy issues for (const issue of comparison.accuracyIssues) { if ( issue.severity !== "low" || _options.updateStrategy === "aggressive" ) { const recommendation = await this.generateAccuracyRecommendation( issue, _options, ); recommendations.push(recommendation); } } return recommendations.sort((a, b) => b.confidence - a.confidence); } private async generateGapRecommendation( gap: DocumentationGap, _options: UpdateOptions, ): Promise<UpdateRecommendation> { const memoryEvidence = gap.memoryEvidence || []; const successfulPatterns = this.memoryInsights?.successfulUpdatePatterns || []; return { section: gap.location, currentContent: "", // No current content for missing items suggestedContent: this.generateContentForGap(gap, successfulPatterns), reasoning: `${gap.description}. ${memoryEvidence.length} similar projects had similar gaps.`, memoryEvidence, confidence: this.calculateGapConfidence(gap, memoryEvidence), effort: this.estimateGapEffort(gap), }; } private generateContentForGap( gap: DocumentationGap, patterns: any[], ): string { // Use memory patterns to generate appropriate content const relevantPatterns = patterns.filter((p) => p.gapType === gap.type); if (relevantPatterns.length > 0) { const bestPattern = relevantPatterns[0]; return this.adaptPatternToGap(bestPattern, gap); } return gap.suggestedUpdate; } private adaptPatternToGap(pattern: any, gap: DocumentationGap): string { let content = pattern.template || pattern.content || gap.suggestedUpdate; // Replace placeholders with actual gap information content = content.replace(/\{feature\}/g, gap.description); content = content.replace(/\{location\}/g, gap.location); return content; } private calculateGapConfidence( gap: DocumentationGap, evidence: any[], ): number { let confidence = 0.5; // Base confidence // Increase confidence based on severity switch (gap.severity) { case "critical": confidence += 0.4; break; case "high": confidence += 0.3; break; case "medium": confidence += 0.2; break; case "low": confidence += 0.1; break; } // Increase confidence based on memory evidence confidence += Math.min(evidence.length * 0.1, 0.3); return Math.min(confidence, 1.0); } private estimateGapEffort(gap: DocumentationGap): "low" | "medium" | "high" { switch (gap.type) { case "missing": return gap.severity === "critical" ? "high" : "medium"; case "outdated": return "low"; case "incorrect": return "medium"; case "incomplete": return "low"; default: return "medium"; } } private async generateOutdatedRecommendation( outdated: any, _options: UpdateOptions, ): Promise<UpdateRecommendation> { return { section: outdated.location, currentContent: outdated.section, suggestedContent: outdated.suggestedUpdate, reasoning: outdated.reason, memoryEvidence: [], confidence: outdated.confidence || 0.8, effort: "low", }; } private async generateAccuracyRecommendation( issue: any, _options: UpdateOptions, ): Promise<UpdateRecommendation> { return { section: issue.location, currentContent: "Code block with accuracy issues", suggestedContent: issue.suggestedFix, reasoning: issue.description, memoryEvidence: [], confidence: issue.severity === "high" ? 0.9 : 0.7, effort: issue.severity === "high" ? "medium" : "low", }; } private calculateUpdateMetrics( comparison: CodeDocumentationComparison, recommendations: UpdateRecommendation[], ): any { const totalGaps = comparison.gaps.length; const totalRecommendations = recommendations.length; const avgConfidence = recommendations.reduce((sum, r) => sum + r.confidence, 0) / recommendations.length || 0; const effortCounts = recommendations.reduce( (acc, r) => { acc[r.effort] = (acc[r.effort] || 0) + 1; return acc; }, {} as Record<string, number>, ); let estimatedEffort = "low"; if (effortCounts.high > 0) estimatedEffort = "high"; else if (effortCounts.medium > effortCounts.low) estimatedEffort = "medium"; return { gapsDetected: totalGaps, recommendationsGenerated: totalRecommendations, confidenceScore: Math.round(avgConfidence * 100) / 100, estimatedEffort, }; } private generateMemoryInformedNextSteps( comparison: CodeDocumentationComparison, recommendations: UpdateRecommendation[], ): string[] { const nextSteps = []; const highConfidenceRecs = recommendations.filter( (r) => r.confidence > 0.8, ); const criticalGaps = comparison.gaps.filter( (g) => g.severity === "critical", ); if (criticalGaps.length > 0) { nextSteps.push( `Address ${criticalGaps.length} critical documentation gaps immediately`, ); } if (highConfidenceRecs.length > 0) { nextSteps.push( `Implement ${highConfidenceRecs.length} high-confidence recommendations first`, ); } if (comparison.accuracyIssues.length > 0) { nextSteps.push( `Fix ${comparison.accuracyIssues.length} code accuracy issues in documentation`, ); } nextSteps.push( "Review and validate all recommended changes before implementation", ); nextSteps.push("Test updated code examples to ensure they work correctly"); const memoryInsights = this.memoryInsights?.similarProjects?.length || 0; if (memoryInsights > 0) { nextSteps.push( `Leverage patterns from ${memoryInsights} similar projects for additional improvements`, ); } return nextSteps; } } // Export the tool implementation

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/documcp'

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