Skip to main content
Glama
tree.js3.47 kB
import fs from 'fs/promises'; import path from 'path'; import { getSignatures } from '../detectors/language.js'; const DEFAULT_MAX_DEPTH = 3; const DEFAULT_MAX_FILES = 1000; /** * Scan directory tree with safety limits * @param {string} dirPath - Directory to scan * @param {object} options - Scan options * @param {number} [options.maxDepth=3] - Maximum depth to scan * @param {number} [options.maxFiles=1000] - Maximum files to scan * @param {boolean} [options.includeHidden=false] - Include hidden files * @returns {Promise<{files: string[], structure: object, truncated: boolean}>} */ export async function scanTree(dirPath, options = {}) { const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH; const maxFiles = options.maxFiles ?? DEFAULT_MAX_FILES; const includeHidden = options.includeHidden ?? false; const sigs = await getSignatures(); const ignorePatterns = new Set(sigs.ignorePatterns || []); const files = []; const structure = {}; let fileCount = 0; let truncated = false; async function scan(currentPath, relativePath, depth) { if (depth > maxDepth) return; if (truncated) return; let entries; try { entries = await fs.readdir(currentPath, { withFileTypes: true }); } catch { return; // Skip inaccessible directories } for (const entry of entries) { if (truncated) break; const name = entry.name; // Skip hidden files unless explicitly included if (!includeHidden && name.startsWith('.')) continue; // Skip ignored patterns if (ignorePatterns.has(name)) continue; const fullPath = path.join(currentPath, name); const relPath = relativePath ? path.join(relativePath, name) : name; if (entry.isDirectory()) { // Add directory to structure const parts = relPath.split(path.sep); let current = structure; for (let i = 0; i < parts.length - 1; i++) { if (!current[parts[i]]) current[parts[i]] = {}; current = current[parts[i]]; } current[name] = {}; // Recurse await scan(fullPath, relPath, depth + 1); } else { files.push(relPath.replace(/\\/g, '/')); fileCount++; if (fileCount >= maxFiles) { truncated = true; break; } } } } await scan(dirPath, '', 0); return { files, structure, truncated }; } /** * Get structure summary - simplified folder overview * @param {object} structure - Full structure object * @param {string[]} files - List of files * @returns {object} Simplified structure summary */ export function getStructureSummary(structure, files) { const summary = {}; // Get top-level directories and their immediate children for (const [dir, children] of Object.entries(structure)) { if (typeof children === 'object' && Object.keys(children).length > 0) { summary[dir] = Object.keys(children); } } // Add root-level important files const rootFiles = files.filter(f => !f.includes('/')); if (rootFiles.length > 0) { summary['.'] = rootFiles.slice(0, 10); // Limit to 10 root files } return summary; }

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/QoutaID/qoutaMcp'

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