Coverage for merco/skills/loader.py: 92%
37 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-07 14:04 +0800
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-07 14:04 +0800
1"""技能加载器 - 从文件系统加载 SKILL.md"""
3import re
4from pathlib import Path
5from typing import Optional
8class SkillLoader:
9 """从目录加载技能"""
11 SKILL_FILE = "SKILL.md"
13 @classmethod
14 def load_from_path(cls, path: str) -> Optional[dict]:
15 """从路径加载单个技能"""
16 skill_path = Path(path).expanduser() / cls.SKILL_FILE
17 if not skill_path.exists():
18 return None
20 content = skill_path.read_text()
21 return cls._parse_skill(content)
23 @classmethod
24 def load_from_directory(cls, directory: str) -> list[dict]:
25 """从目录递归加载所有技能"""
26 skills = []
27 base = Path(directory).expanduser()
29 if not base.exists():
30 return skills
32 for skill_dir in base.rglob("*"):
33 if skill_dir.is_dir() and (skill_dir / cls.SKILL_FILE).exists():
34 skill = cls.load_from_path(str(skill_dir))
35 if skill:
36 skills.append(skill)
38 return skills
40 @classmethod
41 def _parse_skill(cls, content: str) -> dict:
42 """解析技能文件(支持 frontmatter)"""
43 # 提取 frontmatter
44 frontmatter_match = re.match(r"^---\n(.*?)\n---\n(.*)", content, re.DOTALL)
46 if frontmatter_match:
47 frontmatter_str = frontmatter_match.group(1)
48 body = frontmatter_match.group(2).strip()
50 # 简单解析 YAML-like frontmatter
51 frontmatter = {}
52 for line in frontmatter_str.splitlines():
53 if ":" in line:
54 key, value = line.split(":", 1)
55 frontmatter[key.strip()] = value.strip()
57 return {
58 "name": frontmatter.get("name", "unknown"),
59 "description": frontmatter.get("description", ""),
60 "content": body,
61 "metadata": frontmatter,
62 }
64 return {
65 "name": Path(content[:50]).stem if content else "unknown",
66 "description": "",
67 "content": content,
68 "metadata": {},
69 }