(dirInfo)
| 829 | }; |
| 830 | |
| 831 | const loadSkillsFromDir = (dirInfo) => { |
| 832 | const skills = []; |
| 833 | if (!fs.existsSync(dirInfo.path)) return skills; |
| 834 | |
| 835 | try { |
| 836 | if (dirInfo.isFlat) { |
| 837 | const name = dirInfo.package || path.basename(dirInfo.path); |
| 838 | const skillPath = path.join(dirInfo.path, 'SKILL.md'); |
| 839 | if (!fs.existsSync(skillPath)) return skills; |
| 840 | |
| 841 | const content = fs.readFileSync(skillPath, 'utf8'); |
| 842 | const { data: metadata, body } = parseAgentMarkdown(content); |
| 843 | |
| 844 | skills.push({ |
| 845 | name, |
| 846 | content: body, |
| 847 | description: metadata.description || body.slice(0, 100).replace(/\n/g, ' '), |
| 848 | source: dirInfo.source, |
| 849 | path: skillPath, |
| 850 | root: dirInfo.root, |
| 851 | package: dirInfo.package, |
| 852 | ...metadata |
| 853 | }); |
| 854 | } else { |
| 855 | const entries = fs.readdirSync(dirInfo.path, { withFileTypes: true }); |
| 856 | for (const entry of entries) { |
| 857 | if (!entry.isDirectory()) continue; |
| 858 | |
| 859 | const skillPath = path.join(dirInfo.path, entry.name, 'SKILL.md'); |
| 860 | if (!fs.existsSync(skillPath)) continue; |
| 861 | |
| 862 | const content = fs.readFileSync(skillPath, 'utf8'); |
| 863 | const { data: metadata, body } = parseAgentMarkdown(content); |
| 864 | |
| 865 | skills.push({ |
| 866 | name: entry.name, |
| 867 | content: body, |
| 868 | description: metadata.description || body.slice(0, 100).replace(/\n/g, ' '), |
| 869 | source: dirInfo.source, |
| 870 | path: skillPath, |
| 871 | root: dirInfo.root, |
| 872 | package: dirInfo.package, |
| 873 | ...metadata |
| 874 | }); |
| 875 | } |
| 876 | } |
| 877 | } catch (e) { |
| 878 | console.warn(`Failed to load skills from ${dirInfo.path}:`, e.message); |
| 879 | } |
| 880 | |
| 881 | return skills; |
| 882 | }; |
| 883 | |
| 884 | const getAgentDirs = () => { |
| 885 | const roots = getSearchRoots(); |
nothing calls this directly
no test coverage detected