diff --git a/packages/core/src/skills/skillLoader.test.ts b/packages/core/src/skills/skillLoader.test.ts index 7c74ff2f37..dd0564be06 100644 --- a/packages/core/src/skills/skillLoader.test.ts +++ b/packages/core/src/skills/skillLoader.test.ts @@ -194,4 +194,64 @@ Do something. expect(skills[0].description).toContain('Expertise in reviewing code'); expect(skills[0].description).toContain('check'); }); + + it('should handle empty name or description', async () => { + const skillDir = path.join(testRootDir, 'empty-skill'); + await fs.mkdir(skillDir, { recursive: true }); + const skillFile = path.join(skillDir, 'SKILL.md'); + await fs.writeFile( + skillFile, + `--- +name: +description: +--- +`, + ); + + const skills = await loadSkillsFromDir(testRootDir); + + expect(skills).toHaveLength(1); + expect(skills[0].name).toBe(''); + expect(skills[0].description).toBe(''); + }); + + it('should handle indented name and description fields', async () => { + const skillDir = path.join(testRootDir, 'indented-fields'); + await fs.mkdir(skillDir, { recursive: true }); + const skillFile = path.join(skillDir, 'SKILL.md'); + await fs.writeFile( + skillFile, + `--- + name: indented-name + description: indented-desc +--- +`, + ); + + const skills = await loadSkillsFromDir(testRootDir); + + expect(skills).toHaveLength(1); + expect(skills[0].name).toBe('indented-name'); + expect(skills[0].description).toBe('indented-desc'); + }); + + it('should handle missing space after colon', async () => { + const skillDir = path.join(testRootDir, 'no-space'); + await fs.mkdir(skillDir, { recursive: true }); + const skillFile = path.join(skillDir, 'SKILL.md'); + await fs.writeFile( + skillFile, + `--- +name:no-space-name +description:no-space-desc +--- +`, + ); + + const skills = await loadSkillsFromDir(testRootDir); + + expect(skills).toHaveLength(1); + expect(skills[0].name).toBe('no-space-name'); + expect(skills[0].description).toBe('no-space-desc'); + }); }); diff --git a/packages/core/src/skills/skillLoader.ts b/packages/core/src/skills/skillLoader.ts index f25d55f08b..4bbf0823f7 100644 --- a/packages/core/src/skills/skillLoader.ts +++ b/packages/core/src/skills/skillLoader.ts @@ -71,16 +71,22 @@ function parseSimpleFrontmatter( for (let i = 0; i < lines.length; i++) { const line = lines[i]; - if (line.startsWith('name:')) { - name = line.substring(5).trim(); + // Match "name:" at the start of the line (optional whitespace) + const nameMatch = line.match(/^\s*name:\s*(.*)$/); + if (nameMatch) { + name = nameMatch[1].trim(); continue; } - if (line.startsWith('description:')) { - const descLines = [line.substring(12).trim()]; + // Match "description:" at the start of the line (optional whitespace) + const descMatch = line.match(/^\s*description:\s*(.*)$/); + if (descMatch) { + const descLines = [descMatch[1].trim()]; + // Check for multi-line description (indented continuation lines) while (i + 1 < lines.length) { const nextLine = lines[i + 1]; + // If next line is indented, it's a continuation of the description if (nextLine.match(/^[ \t]+\S/)) { descLines.push(nextLine.trim()); i++; @@ -169,7 +175,7 @@ export async function loadSkillFromFile( name: frontmatter.name, description: frontmatter.description, location: filePath, - body: match[2].trim(), + body: match[2]?.trim() ?? '', }; } catch (error) { debugLogger.log(`Error parsing skill file ${filePath}:`, error);