(dir: string, root: string)
| 1158 | } |
| 1159 | |
| 1160 | private walkDir(dir: string, root: string): Array<{ path: string; type: string; size: number }> { |
| 1161 | const results: Array<{ path: string; type: string; size: number }> = []; |
| 1162 | try { |
| 1163 | const entries = fs.readdirSync(dir, { withFileTypes: true }); |
| 1164 | for (const entry of entries) { |
| 1165 | const fullPath = path.join(dir, entry.name); |
| 1166 | const relPath = path.relative(root, fullPath); |
| 1167 | if (entry.isDirectory()) { |
| 1168 | results.push(...this.walkDir(fullPath, root)); |
| 1169 | } else { |
| 1170 | const stat = fs.statSync(fullPath); |
| 1171 | const ext = path.extname(entry.name).toLowerCase(); |
| 1172 | let type = "file"; |
| 1173 | if (entry.name === "SKILL.md") type = "skill"; |
| 1174 | else if ([".sh", ".py", ".ts", ".js"].includes(ext)) type = "script"; |
| 1175 | else if ([".md", ".txt", ".json"].includes(ext)) type = "reference"; |
| 1176 | results.push({ path: relPath, type, size: stat.size }); |
| 1177 | } |
| 1178 | } |
| 1179 | } catch { /* directory may not exist */ } |
| 1180 | return results; |
| 1181 | } |
| 1182 | |
| 1183 | private serveSkillDownload(res: http.ServerResponse, urlPath: string): void { |
| 1184 | const skillId = urlPath.replace("/api/skill/", "").replace("/download", ""); |
no test coverage detected