♻️ refactor(skills): update playbook.py and tests for thirdparty/ layout

- install_skills_action: collect skills from both codex/skills/ (own) and
  codex/skills/thirdparty/ (thirdparty); mode=all installs both, mode=list
  searches both; log [thirdparty] tag for third-party installs
- Update test_thirdparty_skills_pipeline: fix source_list path assertion
- Update SKILLS.md: document thirdparty/ subdirectory structure

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
csh
2026-05-15 15:09:15 +08:00
co-authored by Claude Opus 4.7
parent b3df41205d
commit f94dba0348
3 changed files with 31 additions and 13 deletions
+24 -10
View File
@@ -1141,6 +1141,7 @@ def install_skills_action(config: dict, context: dict) -> int:
agents_home = (context["project_root"] / agents_home).resolve()
skills_src_root = PLAYBOOK_ROOT / "codex/skills"
skills_thirdparty_root = skills_src_root / "thirdparty"
if not skills_src_root.is_dir():
print(f"ERROR: skills source not found: {skills_src_root}", file=sys.stderr)
return 2
@@ -1149,28 +1150,40 @@ def install_skills_action(config: dict, context: dict) -> int:
ensure_dir(skills_dst_root)
if mode == "all":
skills = [
path.name
own_skills = [
(path.name, skills_src_root, "own")
for path in skills_src_root.iterdir()
if path.is_dir() and not path.name.startswith(".")
if path.is_dir() and not path.name.startswith(".") and path.name != "thirdparty"
]
third_skills = [
(path.name, skills_thirdparty_root, "thirdparty")
for path in skills_thirdparty_root.iterdir()
if path.is_dir() and not path.name.startswith(".")
] if skills_thirdparty_root.is_dir() else []
skill_entries = own_skills + third_skills
elif mode == "list":
try:
skills = normalize_names(config.get("skills"), "skills")
names = normalize_names(config.get("skills"), "skills")
except ValueError as exc:
print(f"ERROR: {exc}", file=sys.stderr)
return 2
skill_entries = []
for name in names:
if (skills_src_root / name).is_dir():
skill_entries.append((name, skills_src_root, "own"))
elif skills_thirdparty_root.is_dir() and (skills_thirdparty_root / name).is_dir():
skill_entries.append((name, skills_thirdparty_root, "thirdparty"))
else:
print(f"ERROR: skill not found: {name}", file=sys.stderr)
return 2
else:
print("ERROR: mode must be list or all", file=sys.stderr)
return 2
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
no_backup = bool(config.get("no_backup", False))
for name in skills:
src = skills_src_root / name
if not src.is_dir():
print(f"ERROR: skill not found: {name}", file=sys.stderr)
return 2
for name, src_root, origin in skill_entries:
src = src_root / name
dst = skills_dst_root / name
if dst.exists():
if no_backup:
@@ -1181,7 +1194,8 @@ def install_skills_action(config: dict, context: dict) -> int:
log(f"Backed up existing skill: {name} -> {backup.name}")
copytree(src, dst)
rewrite_skill_docs_links(dst, resolve_docs_prefix(context))
log(f"Installed: {name}")
tag = " [thirdparty]" if origin == "thirdparty" else ""
log(f"Installed: {name}{tag}")
return 0