mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +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.
|
Supports simple `key: value` mappings used by SKILL.md frontmatter.
|
||||||
"""
|
"""
|
||||||
parsed: dict[str, str] = {}
|
parsed: dict[str, str] = {}
|
||||||
|
current_key: Optional[str] = None
|
||||||
for raw_line in frontmatter_text.splitlines():
|
for raw_line in frontmatter_text.splitlines():
|
||||||
line = raw_line.strip()
|
stripped = raw_line.strip()
|
||||||
if not line or line.startswith("#"):
|
if not stripped or stripped.startswith("#"):
|
||||||
continue
|
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
|
return None
|
||||||
key, value = line.split(":", 1)
|
key, value = stripped.split(":", 1)
|
||||||
key = key.strip()
|
key = key.strip()
|
||||||
value = value.strip()
|
value = value.strip()
|
||||||
if not key:
|
if not key:
|
||||||
@@ -48,6 +60,7 @@ def _parse_simple_frontmatter(frontmatter_text: str) -> Optional[dict[str, str]]
|
|||||||
):
|
):
|
||||||
value = value[1:-1]
|
value = value[1:-1]
|
||||||
parsed[key] = value
|
parsed[key] = value
|
||||||
|
current_key = key
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import tempfile
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase, main
|
from unittest import TestCase, main
|
||||||
|
|
||||||
from quick_validate import validate_skill
|
import quick_validate
|
||||||
|
|
||||||
|
|
||||||
class TestQuickValidate(TestCase):
|
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"
|
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")
|
(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)
|
self.assertTrue(valid, message)
|
||||||
|
|
||||||
@@ -36,11 +36,37 @@ class TestQuickValidate(TestCase):
|
|||||||
content = "---\nname: bad-skill\ndescription: missing end\n# no closing fence\n"
|
content = "---\nname: bad-skill\ndescription: missing end\n# no closing fence\n"
|
||||||
(skill_dir / "SKILL.md").write_text(content, encoding="utf-8")
|
(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.assertFalse(valid)
|
||||||
self.assertEqual(message, "Invalid frontmatter format")
|
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__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user