mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 14:34:21 +00:00
fix(skills): support multiline frontmatter fallback without PyYAML
This commit is contained in:
@@ -32,13 +32,25 @@ def _parse_simple_frontmatter(frontmatter_text: str) -> Optional[dict[str, str]]
|
||||
Supports simple `key: value` mappings used by SKILL.md frontmatter.
|
||||
"""
|
||||
parsed: dict[str, str] = {}
|
||||
current_key: Optional[str] = None
|
||||
for raw_line in frontmatter_text.splitlines():
|
||||
line = raw_line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
stripped = raw_line.strip()
|
||||
if not stripped or stripped.startswith("#"):
|
||||
continue
|
||||
if ":" not in line:
|
||||
|
||||
is_indented = raw_line[:1].isspace()
|
||||
if is_indented:
|
||||
if current_key is None:
|
||||
return None
|
||||
current_value = parsed[current_key]
|
||||
parsed[current_key] = (
|
||||
f"{current_value}\n{stripped}" if current_value else stripped
|
||||
)
|
||||
continue
|
||||
|
||||
if ":" not in stripped:
|
||||
return None
|
||||
key, value = line.split(":", 1)
|
||||
key, value = stripped.split(":", 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
if not key:
|
||||
@@ -48,6 +60,7 @@ def _parse_simple_frontmatter(frontmatter_text: str) -> Optional[dict[str, str]]
|
||||
):
|
||||
value = value[1:-1]
|
||||
parsed[key] = value
|
||||
current_key = key
|
||||
return parsed
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import tempfile
|
||||
from pathlib import Path
|
||||
from unittest import TestCase, main
|
||||
|
||||
from quick_validate import validate_skill
|
||||
import quick_validate
|
||||
|
||||
|
||||
class TestQuickValidate(TestCase):
|
||||
@@ -26,7 +26,7 @@ class TestQuickValidate(TestCase):
|
||||
content = "---\r\nname: crlf-skill\r\ndescription: ok\r\n---\r\n# Skill\r\n"
|
||||
(skill_dir / "SKILL.md").write_text(content, encoding="utf-8")
|
||||
|
||||
valid, message = validate_skill(skill_dir)
|
||||
valid, message = quick_validate.validate_skill(skill_dir)
|
||||
|
||||
self.assertTrue(valid, message)
|
||||
|
||||
@@ -36,11 +36,37 @@ class TestQuickValidate(TestCase):
|
||||
content = "---\nname: bad-skill\ndescription: missing end\n# no closing fence\n"
|
||||
(skill_dir / "SKILL.md").write_text(content, encoding="utf-8")
|
||||
|
||||
valid, message = validate_skill(skill_dir)
|
||||
valid, message = quick_validate.validate_skill(skill_dir)
|
||||
|
||||
self.assertFalse(valid)
|
||||
self.assertEqual(message, "Invalid frontmatter format")
|
||||
|
||||
def test_fallback_parser_handles_multiline_frontmatter_without_pyyaml(self):
|
||||
skill_dir = self.temp_dir / "multiline-skill"
|
||||
skill_dir.mkdir(parents=True, exist_ok=True)
|
||||
content = """---
|
||||
name: multiline-skill
|
||||
description: Works without pyyaml
|
||||
allowed-tools:
|
||||
- gh
|
||||
metadata: |
|
||||
{
|
||||
"owners": ["team-openclaw"]
|
||||
}
|
||||
---
|
||||
# Skill
|
||||
"""
|
||||
(skill_dir / "SKILL.md").write_text(content, encoding="utf-8")
|
||||
|
||||
previous_yaml = quick_validate.yaml
|
||||
quick_validate.yaml = None
|
||||
try:
|
||||
valid, message = quick_validate.validate_skill(skill_dir)
|
||||
finally:
|
||||
quick_validate.yaml = previous_yaml
|
||||
|
||||
self.assertTrue(valid, message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user