mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
refactor(core): harden skill frontmatter parsing (#16705)
This commit is contained in:
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user