[eric] skills: frontmatter parser reads YAML block scalars, so a |- description no longer renders literally (ENG-307)

This commit is contained in:
ciregenz
2026-08-16 01:53:28 -07:00
parent a15466ff54
commit dc303222ac
3 changed files with 55 additions and 16 deletions
@@ -23,10 +23,24 @@ def parse_frontmatter(raw: str) -> tuple[dict, str]:
fm_block = raw[3:end].strip()
body = raw[end + 3:].strip()
meta: dict = {}
for line in fm_block.splitlines():
m = re.match(r"^(\w[\w_-]*)\s*:\s*(.+)$", line)
if m:
meta[m.group(1).strip()] = m.group(2).strip().strip('"').strip("'")
lines = fm_block.splitlines()
i = 0
while i < len(lines):
m = re.match(r"^(\w[\w_-]*)\s*:\s*(.*)$", lines[i])
i += 1
if not m:
continue
key, val = m.group(1).strip(), m.group(2).strip()
if re.fullmatch(r"[|>][+-]?", val):
# YAML block scalar: the text is the indented lines below; the bare indicator once shipped as a card's whole description (ENG-307).
block: list[str] = []
while i < len(lines) and (not lines[i].strip() or lines[i][0] in (" ", "\t")):
block.append(lines[i].strip())
i += 1
joiner = "\n" if val[0] == "|" else " "
meta[key] = joiner.join(b for b in block if b).strip()
else:
meta[key] = val.strip('"').strip("'")
return meta, body
+2 -12
View File
@@ -12,6 +12,7 @@ import time
import zipfile
from contextlib import asynccontextmanager
from fastapi import HTTPException
from backend.apps.skill_registry.skill_registry_github import parse_frontmatter
from backend.config.Apps import SubApp
from backend.apps.skills.models import Skill, SkillCreate, SkillLoadRequest, SkillUpdate, SkillUpload, SkillWorkspaceSeedRequest
@@ -339,18 +340,7 @@ async def load_skill(body: SkillLoadRequest):
def p_parse_skill_frontmatter(raw: str) -> dict:
"""Extract YAML frontmatter fields from a SKILL.md file."""
if not raw.startswith("---"):
return {}
end = raw.find("---", 3)
if end == -1:
return {}
fm_block = raw[3:end].strip()
meta: dict = {}
for line in fm_block.splitlines():
m = re.match(r"^(\w[\w_-]*)\s*:\s*(.+)$", line)
if m:
meta[m.group(1).strip()] = m.group(2).strip().strip('"').strip("'")
return meta
return parse_frontmatter(raw)[0]
@skills.router.post("/workspace/seed")
@@ -0,0 +1,35 @@
"""A SKILL.md whose description uses a YAML block scalar rendered as the literal string "|-" on
its marketplace card (ENG-307, seen live on /claude-api). The line-regex parser matched the
indicator as the value and dropped the indented block below it. One parser now serves both the
registry and the upload path, and it reads block scalars.
"""
from backend.apps.skill_registry.skill_registry_github import parse_frontmatter
from backend.apps.skills.skills import p_parse_skill_frontmatter
def test_literal_block_scalar_reads_the_indented_text():
meta, body = parse_frontmatter("---\nname: claude-api\ndescription: |-\n Talk to the API\n with retries.\n---\nBody")
assert meta["description"] == "Talk to the API\nwith retries."
assert meta["name"] == "claude-api"
assert body == "Body"
def test_folded_scalar_joins_with_spaces():
meta, _ = parse_frontmatter("---\ndescription: >-\n One line\n folded.\n---\n")
assert meta["description"] == "One line folded."
def test_plain_and_quoted_values_are_unchanged():
meta, _ = parse_frontmatter('---\nname: "quoted"\nlicense: MIT\n---\n')
assert meta == {"name": "quoted", "license": "MIT"}
def test_empty_block_scalar_yields_empty_not_the_indicator():
meta, _ = parse_frontmatter("---\ndescription: |-\nname: x\n---\n")
assert meta["description"] == ""
assert meta["name"] == "x"
def test_upload_path_uses_the_same_parser():
meta = p_parse_skill_frontmatter("---\ndescription: |-\n Uploaded skill.\n---\n")
assert meta["description"] == "Uploaded skill."