mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-08-08 23:23:38 +08:00
fix(s08,s20): sync frontmatter parser with s07 fix from PR #434
Replace old manual/split-based _parse_frontmatter with the
line-delimited YAML parser from s07. This fixes skill loading
for YAML block scalars, multiline descriptions, and CRLF line
endings in both s08 and s20. Also update name/desc fallback
from meta.get(k, default) to meta.get(k) or default so empty
string values correctly fall through.
s08 previously used a manual split(':', 1) parser that could not
handle YAML syntax at all. s20 used yaml.safe_load but with the
old text.split('---', 2) approach that misses boundary cases.
This commit is contained in:
@@ -32,7 +32,7 @@ Builds on s07 (skill loading). Usage:
|
|||||||
Needs: pip install anthropic python-dotenv + ANTHROPIC_API_KEY in .env
|
Needs: pip install anthropic python-dotenv + ANTHROPIC_API_KEY in .env
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ast, json, os, subprocess, time
|
import ast, json, os, subprocess, time, yaml
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -57,17 +57,27 @@ CURRENT_TODOS: list[dict] = []
|
|||||||
|
|
||||||
# s07: Skill catalog scan (inherited from s07)
|
# s07: Skill catalog scan (inherited from s07)
|
||||||
def _parse_frontmatter(text: str) -> tuple[dict, str]:
|
def _parse_frontmatter(text: str) -> tuple[dict, str]:
|
||||||
if not text.startswith("---"):
|
"""Parse YAML frontmatter from SKILL.md. Returns (meta, body)."""
|
||||||
|
if not (text.startswith("---\n") or text.startswith("---\r\n")):
|
||||||
return {}, text
|
return {}, text
|
||||||
parts = text.split("---", 2)
|
|
||||||
if len(parts) < 3:
|
lines = text.splitlines(keepends=True)
|
||||||
|
closing_index = None
|
||||||
|
for index, line in enumerate(lines[1:], start=1):
|
||||||
|
if line.strip() == "---":
|
||||||
|
closing_index = index
|
||||||
|
break
|
||||||
|
if closing_index is None:
|
||||||
return {}, text
|
return {}, text
|
||||||
meta = {}
|
|
||||||
for line in parts[1].strip().splitlines():
|
frontmatter = "".join(lines[1:closing_index])
|
||||||
if ":" in line:
|
body = "".join(lines[closing_index + 1 :]).strip()
|
||||||
k, v = line.split(":", 1)
|
try:
|
||||||
meta[k.strip()] = v.strip().strip('"').strip("'")
|
loaded = yaml.safe_load(frontmatter) or {}
|
||||||
return meta, parts[2].strip()
|
except yaml.YAMLError:
|
||||||
|
loaded = {}
|
||||||
|
meta = loaded if isinstance(loaded, dict) else {}
|
||||||
|
return meta, body
|
||||||
|
|
||||||
SKILL_REGISTRY: dict[str, dict] = {}
|
SKILL_REGISTRY: dict[str, dict] = {}
|
||||||
|
|
||||||
@@ -81,8 +91,8 @@ def _scan_skills():
|
|||||||
if manifest.exists():
|
if manifest.exists():
|
||||||
raw = manifest.read_text()
|
raw = manifest.read_text()
|
||||||
meta, body = _parse_frontmatter(raw)
|
meta, body = _parse_frontmatter(raw)
|
||||||
name = meta.get("name", d.name)
|
name = meta.get("name") or d.name
|
||||||
desc = meta.get("description", raw.split("\n")[0].lstrip("#").strip())
|
desc = meta.get("description") or body.split("\n", 1)[0].lstrip("#").strip()
|
||||||
SKILL_REGISTRY[name] = {"name": name, "description": desc, "content": raw}
|
SKILL_REGISTRY[name] = {"name": name, "description": desc, "content": raw}
|
||||||
|
|
||||||
_scan_skills()
|
_scan_skills()
|
||||||
|
|||||||
@@ -288,16 +288,27 @@ SKILL_REGISTRY: dict[str, dict] = {}
|
|||||||
|
|
||||||
|
|
||||||
def _parse_frontmatter(text: str) -> tuple[dict, str]:
|
def _parse_frontmatter(text: str) -> tuple[dict, str]:
|
||||||
if not text.startswith("---"):
|
"""Parse YAML frontmatter from SKILL.md. Returns (meta, body)."""
|
||||||
|
if not (text.startswith("---\n") or text.startswith("---\r\n")):
|
||||||
return {}, text
|
return {}, text
|
||||||
parts = text.split("---", 2)
|
|
||||||
if len(parts) < 3:
|
lines = text.splitlines(keepends=True)
|
||||||
|
closing_index = None
|
||||||
|
for index, line in enumerate(lines[1:], start=1):
|
||||||
|
if line.strip() == "---":
|
||||||
|
closing_index = index
|
||||||
|
break
|
||||||
|
if closing_index is None:
|
||||||
return {}, text
|
return {}, text
|
||||||
|
|
||||||
|
frontmatter = "".join(lines[1:closing_index])
|
||||||
|
body = "".join(lines[closing_index + 1 :]).strip()
|
||||||
try:
|
try:
|
||||||
meta = yaml.safe_load(parts[1]) or {}
|
loaded = yaml.safe_load(frontmatter) or {}
|
||||||
except yaml.YAMLError:
|
except yaml.YAMLError:
|
||||||
meta = {}
|
loaded = {}
|
||||||
return meta, parts[2].strip()
|
meta = loaded if isinstance(loaded, dict) else {}
|
||||||
|
return meta, body
|
||||||
|
|
||||||
|
|
||||||
def scan_skills():
|
def scan_skills():
|
||||||
@@ -311,9 +322,9 @@ def scan_skills():
|
|||||||
if not manifest.exists():
|
if not manifest.exists():
|
||||||
continue
|
continue
|
||||||
raw = manifest.read_text()
|
raw = manifest.read_text()
|
||||||
meta, _ = _parse_frontmatter(raw)
|
meta, body = _parse_frontmatter(raw)
|
||||||
name = meta.get("name", directory.name)
|
name = meta.get("name") or directory.name
|
||||||
desc = meta.get("description", raw.split("\n")[0].lstrip("#").strip())
|
desc = meta.get("description") or body.split("\n", 1)[0].lstrip("#").strip()
|
||||||
SKILL_REGISTRY[name] = {
|
SKILL_REGISTRY[name] = {
|
||||||
"name": name,
|
"name": name,
|
||||||
"description": desc,
|
"description": desc,
|
||||||
|
|||||||
Reference in New Issue
Block a user