UNPKG

@sofianedjerbi/knowledge-tree-mcp

Version:

MCP server for hierarchical project knowledge management

159 lines 4.8 kB
/** * File system utilities for Knowledge Tree MCP * Handles all file operations, directory management, and path utilities */ import { promises as fs } from 'fs'; import { join, dirname, relative } from 'path'; /** * Scans the knowledge tree directory recursively for JSON files * @param knowledgeRoot - Root directory to scan * @returns Array of relative paths to JSON files */ export async function scanKnowledgeTree(knowledgeRoot) { const entries = []; async function scan(dir) { try { const items = await fs.readdir(dir, { withFileTypes: true }); for (const item of items) { const fullPath = join(dir, item.name); if (item.isDirectory()) { await scan(fullPath); } else if (item.name.endsWith('.json') && item.name !== '.knowledge-tree.json') { entries.push(relative(knowledgeRoot, fullPath)); } } } catch (error) { // Directory might not exist yet, silently continue } } await scan(knowledgeRoot); return entries; } /** * Ensures a directory exists, creating it if necessary * @param dirPath - Directory path to ensure exists * @returns Whether the directory was newly created */ export async function ensureDirectory(dirPath) { try { const existed = await fs.access(dirPath).then(() => true).catch(() => false); await fs.mkdir(dirPath, { recursive: true }); return !existed; } catch (error) { throw new Error(`Failed to create directory ${dirPath}: ${error}`); } } /** * Reads a knowledge entry from a JSON file * @param filePath - Path to the JSON file * @returns Parsed knowledge entry */ export async function readKnowledgeEntry(filePath) { try { const content = await fs.readFile(filePath, 'utf-8'); return JSON.parse(content); } catch (error) { throw new Error(`Failed to read knowledge entry at ${filePath}: ${error}`); } } /** * Writes a knowledge entry to a JSON file * @param filePath - Path to the JSON file * @param entry - Knowledge entry to write */ export async function writeKnowledgeEntry(filePath, entry) { const dir = dirname(filePath); await ensureDirectory(dir); await fs.writeFile(filePath, JSON.stringify(entry, null, 2)); } /** * Checks if a file exists * @param filePath - Path to check * @returns Whether the file exists */ export async function fileExists(filePath) { try { await fs.access(filePath); return true; } catch { return false; } } /** * Deletes a file * @param filePath - Path to the file to delete */ export async function deleteFile(filePath) { await fs.unlink(filePath); } /** * Gets file statistics * @param filePath - Path to the file * @returns File statistics */ export async function getFileStats(filePath) { return await fs.stat(filePath); } /** * Appends content to a file * @param filePath - Path to the file * @param content - Content to append */ export async function appendToFile(filePath, content) { await fs.appendFile(filePath, content); } /** * Reads file content as string * @param filePath - Path to the file * @returns File content */ export async function readFile(filePath) { return await fs.readFile(filePath, 'utf-8'); } /** * Write content to a file * @param filePath - Path to write to * @param content - Content to write */ export async function writeFile(filePath, content) { await fs.writeFile(filePath, content, 'utf-8'); } /** * Generates a description from a knowledge entry path * @param path - Relative path to the knowledge entry * @returns Human-readable description */ export function getDescriptionFromPath(path) { const parts = path.split('/'); const filename = parts[parts.length - 1]; const category = parts.length > 1 ? parts.slice(0, -1).join(' > ') : 'root'; return `Knowledge in ${category}`; } /** * Ensures a path ends with .json extension * @param path - Path to check * @returns Path with .json extension */ export function ensureJsonExtension(path) { return path.endsWith('.json') ? path : `${path}.json`; } /** * Ensures a path ends with an appropriate knowledge extension * @param path - Path to check * @param preferMarkdown - Whether to prefer .md over .json * @returns Path with appropriate extension */ export function ensureKnowledgeExtension(path, preferMarkdown = false) { // If already has a valid extension, return as is if (path.endsWith('.json') || path.endsWith('.md')) { return path; } // Add appropriate extension return preferMarkdown ? `${path}.md` : `${path}.json`; } //# sourceMappingURL=fileSystem.js.map