Skip to main content
Glama

Autodocument MCP Server

by PARS-DOE
aggregator.js7.31 kB
import * as path from 'path'; import { DirectoryCrawler } from '../crawler/index.js'; import { FileAnalyzer } from '../analyzer/index.js'; import { DocumentationGenerator } from './generator.js'; /** * Class for handling the bottom-up aggregation of documentation */ export class DocumentationAggregator { /** * Creates a new documentation aggregator * @param rootPath The root directory to process * @param apiKey OpenRouter API key (optional) * @param model LLM model to use (optional) */ constructor(rootPath, apiKey, model, updateExisting = true) { this.rootPath = rootPath; this.updateExisting = updateExisting; this.crawler = new DirectoryCrawler(rootPath, { respectGitignore: true }); this.analyzer = new FileAnalyzer(); this.generator = new DocumentationGenerator(apiKey, model, updateExisting); } /** * Runs the full documentation aggregation process * @param progressCallback Optional callback for progress updates * @returns Results of the aggregation process */ async run(progressCallback) { const result = { totalDirectories: 0, successfulDocumentations: 0, failedDocumentations: 0, undocumentedFiles: 0, updatedDocumentations: 0, skippedDocumentations: 0, errors: [] }; try { // Create a bottom-up processing order const directories = await this.crawler.createBottomUpOrder(); result.totalDirectories = directories.length; // Process each directory in bottom-up order for (let i = 0; i < directories.length; i++) { const directoryPath = directories[i]; console.log(`Processing directory: ${directoryPath}`); // Get all code files in the directory const files = this.crawler.getCodeFiles(directoryPath); // Report progress if callback is provided if (progressCallback) { progressCallback(path.relative(this.rootPath, directoryPath) || '.', files.length, i + 1, directories.length); } // Check if directory has subdirectories const hasSubdirectories = this.crawler.hasSubdirectories(directoryPath); // Check if directory should be documented if (!this.analyzer.shouldDocument(directoryPath, files, hasSubdirectories)) { console.log(`Skipping directory ${directoryPath} - Not enough code files to document or skipped due to rules`); // If this is a single-file directory, it will be included in its parent's documentation continue; } // Get documentation from subdirectories and single-file directories that weren't documented const subdirDocs = this.crawler.getSubdirectoryDocs(directoryPath); // Get single-file subdirectories' content to include in this directory's documentation const singleFileDocs = this.crawler.getSingleFileSubdirectories(directoryPath); // Check if this is a directory with no code files but with subdirectories if (files.length === 0 && hasSubdirectories) { console.log(`Processing directory ${directoryPath} - No code files, but contains subdirectories with documentation`); } // Analyze files (might be empty if directory only has subdirectories) const analysisResult = await this.analyzer.analyzeFiles(directoryPath, files); // Check if files are too large or too many if (analysisResult.limited) { console.log(`Directory ${directoryPath} exceeds limits: ${analysisResult.limitReason}`); await this.generator.createUndocumentedFile(directoryPath, analysisResult); result.undocumentedFiles++; continue; } // Get all documentation from child directories (subdirectories and single-file directories) const allChildDocs = [...subdirDocs]; // Add content from single-file subdirectories if (singleFileDocs.length > 0) { allChildDocs.push(...singleFileDocs); } // Generate documentation const isTopLevel = directoryPath === this.rootPath; const docResult = await this.generateDocumentation(directoryPath, analysisResult, isTopLevel, allChildDocs, result); if (docResult.skipped) { result.skippedDocumentations++; console.log(`Skipped existing documentation for ${directoryPath} (updateExisting=false)`); } else if (docResult.isUpdate) { result.updatedDocumentations++; } } return result; } catch (error) { console.error('Error during documentation aggregation:', error); result.errors.push({ directory: this.rootPath, error: `Global error: ${error.message}` }); return result; } } /** * Generates documentation for a directory and updates the aggregation result * @param directoryPath Path to the directory * @param analysisResult Results of file analysis * @param isTopLevel Whether this is the top level directory * @param subdirDocs Documentation from subdirectories * @param aggregationResult Aggregation result to update * @returns Documentation generation result */ async generateDocumentation(directoryPath, analysisResult, isTopLevel, subdirDocs, aggregationResult) { try { const docResult = await this.generator.generateDocumentation(directoryPath, analysisResult, isTopLevel, subdirDocs); if (docResult.success) { console.log(`Successfully ${docResult.isUpdate ? 'updated' : 'generated'} documentation for ${directoryPath}`); aggregationResult.successfulDocumentations++; } else { console.error(`Failed to generate documentation for ${directoryPath}:`, docResult.error); aggregationResult.failedDocumentations++; aggregationResult.errors.push({ directory: directoryPath, error: docResult.error || 'Unknown error' }); } return docResult; } catch (error) { console.error(`Error generating documentation for ${directoryPath}:`, error); aggregationResult.failedDocumentations++; aggregationResult.errors.push({ directory: directoryPath, error: error.message }); return { documentationPath: path.join(directoryPath, 'documentation.md'), success: false, content: '', error: error.message, isUpdate: false }; } } } //# sourceMappingURL=aggregator.js.map

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/PARS-DOE/autodocument'

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