Skip to main content
Glama

Task Trellis MCP

getChildrenByFilePath.ts3.33 kB
import { readdir, stat } from "node:fs/promises"; import { dirname, join, basename } from "node:path"; import { getObjectByFilePath } from "./getObjectByFilePath"; /** * Determines the child folders based on the object type prefix */ function getChildFolders(parentDir: string, objectPrefix: string): string[] { switch (objectPrefix) { case "P": // Projects have epics in e/ subfolder return [join(parentDir, "e")]; case "E": // Epics have features in f/ subfolder return [join(parentDir, "f")]; case "F": // Features have tasks in t/open/ and t/closed/ subfolders return [join(parentDir, "t", "open"), join(parentDir, "t", "closed")]; default: // Tasks (T) and unknown types have no children return []; } } /** * Scans a folder for child objects (handles both directory-based and file-based structures) */ async function scanFolderForChildren(folder: string): Promise<string[]> { const children: string[] = []; try { const entries = await readdir(folder); for (const entry of entries) { const fullPath = join(folder, entry); const stats = await stat(fullPath); if (stats.isDirectory()) { // For P, E, F objects, the markdown file is inside a folder with the same name // e.g., e/E-epic-name/E-epic-name.md const mdFilePath = join(fullPath, `${entry}.md`); try { const mdStats = await stat(mdFilePath); if (mdStats.isFile()) { const childObject = await getObjectByFilePath(mdFilePath); children.push(childObject.id); } } catch { // File doesn't exist, skip } } else if (stats.isFile() && entry.endsWith(".md")) { // For tasks in open/closed folders, the markdown files are directly in those folders const childObject = await getObjectByFilePath(fullPath); children.push(childObject.id); } } } catch (error) { // Folder doesn't exist or can't be read, skip silently if (error instanceof Error && "code" in error && error.code !== "ENOENT") { console.error(`Warning: Could not read directory ${folder}:`, error); } } return children; } /** * Gets all child object IDs for a given Trellis object file path. * * @param filePath - The file path to a Trellis object markdown file * @returns Array of child object IDs * * Hierarchy: * - Projects (P-*) can have Epics (E-*) as children in e/ subfolder * - Epics (E-*) can have Features (F-*) as children in f/ subfolder * - Features (F-*) can have Tasks (T-*) as children in t/open/ and t/closed/ subfolders * - Tasks (T-*) have no children */ export async function getChildrenByFilePath( filePath: string, ): Promise<string[]> { const parentDir = dirname(filePath); const fileName = basename(filePath, ".md"); // Determine object type from filename prefix const objectPrefix = fileName.charAt(0).toUpperCase(); // Get the folders where children might be located const childFolders = getChildFolders(parentDir, objectPrefix); // Scan each child folder for markdown files const children: string[] = []; for (const folder of childFolders) { const folderChildren = await scanFolderForChildren(folder); children.push(...folderChildren); } return children; }

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/langadventurellc/task-trellis-mcp'

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