(workspacePath: string)
| 88 | } |
| 89 | |
| 90 | async function getFileTree(workspacePath: string): Promise<FileNode[]> { |
| 91 | const tree: FileNode[] = []; |
| 92 | |
| 93 | for (const file of ROOT_FILES) { |
| 94 | const fullPath = path.join(workspacePath, file); |
| 95 | if (await fileExists(fullPath)) { |
| 96 | tree.push({ |
| 97 | name: file, |
| 98 | path: file, |
| 99 | type: "file", |
| 100 | }); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | const memoryTree = await buildMarkdownFolderTree( |
| 105 | path.join(workspacePath, MEMORY_DIR), |
| 106 | MEMORY_DIR, |
| 107 | { recursive: false, reverseFiles: true } |
| 108 | ); |
| 109 | if (memoryTree) { |
| 110 | tree.push(memoryTree); |
| 111 | } |
| 112 | |
| 113 | const skillsTree = await buildMarkdownFolderTree( |
| 114 | path.join(workspacePath, SKILLS_DIR), |
| 115 | SKILLS_DIR, |
| 116 | { recursive: true } |
| 117 | ); |
| 118 | if (skillsTree) { |
| 119 | tree.push(skillsTree); |
| 120 | } |
| 121 | |
| 122 | return tree; |
| 123 | } |
| 124 | |
| 125 | function sanitizePath(requestedPath: string): string | null { |
| 126 | // Prevent directory traversal |
no test coverage detected