#!/usr/bin/env python3 from __future__ import annotations import argparse import re from pathlib import Path from typing import Dict, List def strip_wrapping_quotes(value: str) -> str: value = value.strip() if len(value) >= 2 and ( (value.startswith('"') and value.endswith('"')) or (value.startswith("'") and value.endswith("'")) ): return value[1:-1] return value def normalize_whitespace(value: str) -> str: return re.sub(r"\s+", " ", value).strip() def parse_front_matter(text: str) -> Dict[str, str]: """ Parse a very small YAML front matter subset from SUBSKILL.md. Supported: - name: xxx - description: xxx - description: | line1 line2 - description: > line1 line2 """ lines = text.splitlines() if not lines or lines[0].strip() != "---": return {} end_index = None for i in range(1, len(lines)): if lines[i].strip() == "---": end_index = i break if end_index is None: return {} meta_lines = lines[1:end_index] result: Dict[str, str] = {} i = 0 while i < len(meta_lines): line = meta_lines[i] if not line.strip() or line.lstrip().startswith("#"): i += 1 continue match = re.match(r"^([A-Za-z0-9_-]+):\s*(.*)$", line) if not match: i += 1 continue key, raw_value = match.groups() raw_value = raw_value.strip() if raw_value in {"|", "|-", "|+", ">", ">-", ">+"}: is_folded = raw_value.startswith(">") block_lines: List[str] = [] j = i + 1 while j < len(meta_lines): next_line = meta_lines[j] if next_line.strip() == "": block_lines.append("") j += 1 continue indent = len(next_line) - len(next_line.lstrip(" ")) if indent == 0: break block_lines.append(next_line) j += 1 non_empty = [ln for ln in block_lines if ln.strip()] if non_empty: min_indent = min(len(ln) - len(ln.lstrip(" ")) for ln in non_empty) dedented = [ln[min_indent:] if ln.strip() else "" for ln in block_lines] else: dedented = [] if is_folded: value = " ".join(part.strip() for part in dedented if part.strip()) else: value = "\n".join(dedented).rstrip() result[key] = value i = j continue result[key] = strip_wrapping_quotes(raw_value) i += 1 return result def markdown_escape(value: str) -> str: value = value.replace("\\", "\\\\") value = value.replace("|", r"\|") return value def is_placeholder_subskill(name: str, description: str, rel_path: str) -> bool: normalized_name = name.strip().lower() normalized_description = description.strip().lower() normalized_path = rel_path.strip().lower() return ( normalized_name.endswith("-xxx") or "placeholder" in normalized_description or normalized_path.endswith("-xxx/subskill.md") ) def collect_subskills(root_dir: Path) -> List[Dict[str, str]]: items: List[Dict[str, str]] = [] for skill_file in sorted(root_dir.rglob("SUBSKILL.md")): if skill_file.parent == root_dir: # 跳过父级 dedicated-cloud-ops 自己的 SKILL.md continue if "scripts" in skill_file.parts: continue content = skill_file.read_text(encoding="utf-8") metadata = parse_front_matter(content) name = metadata.get("name", "").strip() or "" description = metadata.get("description", "").strip() or "" rel_path = skill_file.relative_to(root_dir).as_posix() if is_placeholder_subskill(name, description, rel_path): continue items.append( { "name": normalize_whitespace(name), "description": normalize_whitespace(description), "path": rel_path, } ) items.sort(key=lambda x: (x["name"].lower(), x["path"].lower())) return items def render_markdown(items: List[Dict[str, str]], title: str) -> str: lines: List[str] = [] lines.append(f"# {title}") lines.append("") lines.append("This file is generated automatically. Do not edit manually.") lines.append("") lines.append("| Name | Description | SUBSKILL.md Relative Path |") lines.append("|---|---|---|") for item in items: name = markdown_escape(item["name"]) description = markdown_escape(item["description"]) path = markdown_escape(item["path"]) lines.append(f"| {name} | {description} | `{path}` |") if not items: lines.append("| | No subskills found. | - |") lines.append("") return "\n".join(lines) def main() -> None: root_dir = Path(__file__).resolve().parent.parent parser = argparse.ArgumentParser( description="Generate a static Markdown index for Dedicated Cloud operations subskills." ) parser.add_argument( "--root-dir", default=str(root_dir), help="Skill root directory. Default: parent of current directory.", ) parser.add_argument( "--output", default=str(root_dir / "SUBSKILLS_INDEX.md"), help="Output Markdown file path.", ) parser.add_argument( "--title", default="Dedicated Cloud Ops SubSkill Index", help="Markdown document title.", ) args = parser.parse_args() actual_root = Path(args.root_dir).resolve() output_path = Path(args.output).resolve() items = collect_subskills(actual_root) markdown = render_markdown(items, args.title) output_path.write_text(markdown, encoding="utf-8") print(f"Generated {output_path} with {len(items)} subskills.") if __name__ == "__main__": main()