UNPKG

zed.mcp

Version:

MCP server for project analysis, AI rules reading, and dependency checking

125 lines (115 loc) 3.28 kB
import fs from "fs/promises"; import path from "path"; /** * Default patterns for an LLM to ignore */ const DEFAULT_IGNORE_PATTERNS = [ "node_modules", ".git", "dist", "build", ".DS_Store", "*.log", "*.lock", ".env", ]; /** * Parses the .gitignore file from the project path and combines it with * default ignore patterns. */ export async function getIgnorePatterns(projectPath: string): Promise<string[]> { const gitignorePath = path.join(projectPath, ".gitignore"); try { const gitignoreContent = await fs.readFile(gitignorePath, "utf-8"); const gitignorePatterns = gitignoreContent .split("\n") .map((line) => line.trim()) .filter((line) => line && !line.startsWith("#")); return [...DEFAULT_IGNORE_PATTERNS, ...gitignorePatterns]; } catch (error) { return DEFAULT_IGNORE_PATTERNS; } } /** * Checks if a given file path should be ignored based on patterns. * NOTE: Simplified implementation - doesn't support complex glob patterns. */ export function isIgnored(relativePath: string, ignorePatterns: string[]): boolean { const pathSegments = relativePath.split(path.sep); return ignorePatterns.some((pattern) => { // Handle wildcard patterns like *.log if (pattern.startsWith("*.")) { const extension = pattern.substring(1); return relativePath.endsWith(extension); } // Handle directory or file names return pathSegments.includes(pattern.replace("/", "")); }); } /** * Recursively traverses directories to build an indented string representation * of the project structure. */ export async function buildStructureString( dirPath: string, projectPath: string, ignorePatterns: string[], indent = "", ): Promise<string> { let structure = ""; let entries; try { entries = await fs.readdir(dirPath, { withFileTypes: true }); } catch (error) { console.error(`Could not read directory: ${dirPath}`); return ""; } for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); const relativePath = path.relative(projectPath, fullPath); if (isIgnored(relativePath, ignorePatterns)) { continue; } if (entry.isDirectory()) { structure += `${indent}${entry.name}/\n`; structure += await buildStructureString( fullPath, projectPath, ignorePatterns, indent + " ", ); } else { structure += `${indent}${entry.name}\n`; } } return structure; } /** * Checks if a path exists and is a directory */ export async function isDirectory(dirPath: string): Promise<boolean> { try { const stats = await fs.stat(dirPath); return stats.isDirectory(); } catch (error) { return false; } } /** * Reads a JSON file and parses it */ export async function readJsonFile<T = any>(filePath: string): Promise<T> { const content = await fs.readFile(filePath, "utf-8"); return JSON.parse(content); } /** * Checks if a file exists */ export async function fileExists(filePath: string): Promise<boolean> { try { await fs.access(filePath); return true; } catch (error) { return false; } }