Files
wow20/_bmad/scripts/resolve_customization.py
T
2026-08-14 17:08:24 +02:00

100 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
# /// script
# requires-python = ">=3.11"
# ///
"""Resolve a skill's default, team, and user TOML customization layers."""
import argparse
import json
import sys
from pathlib import Path
# Installed scripts are consumer files, not a location for interpreter caches.
sys.dont_write_bytecode = True
try:
from config_utils import ConfigError, load_customization
except ModuleNotFoundError as error:
if error.name != "tomllib":
raise
sys.stderr.write("error: Python 3.11+ is required (stdlib `tomllib` not found).\n")
raise SystemExit(3) from None
_MISSING = object()
def find_project_root(start: Path) -> Path | None:
current = start.resolve()
while True:
if (current / "_bmad").exists() or (current / ".git").exists():
return current
if current.parent == current:
return None
current = current.parent
def extract_key(data, dotted_key: str):
current = data
for part in dotted_key.split("."):
if isinstance(current, dict) and part in current:
current = current[part]
else:
return _MISSING
return current
def write_json_stdout(output) -> None:
reconfigure = getattr(sys.stdout, "reconfigure", None)
if reconfigure is not None:
reconfigure(encoding="utf-8")
sys.stdout.write(json.dumps(output, indent=2, ensure_ascii=False) + "\n")
def main() -> int:
parser = argparse.ArgumentParser(
description="Resolve skill customization using three-layer TOML merge."
)
parser.add_argument(
"--skill", "-s", required=True, help="Absolute path to the skill directory"
)
parser.add_argument(
"--project-root",
"-p",
help="Explicit project root containing _bmad/ (recommended)",
)
parser.add_argument(
"--key",
"-k",
action="append",
default=[],
help="Dotted field path to resolve (repeatable). Omit for full dump.",
)
args = parser.parse_args()
skill_dir = Path(args.skill).resolve()
project_root = (
Path(args.project_root).resolve()
if args.project_root
else find_project_root(skill_dir) or find_project_root(Path.cwd())
)
try:
merged = load_customization(project_root, skill_dir)
except ConfigError as error:
sys.stderr.write(f"error: {error}\n")
return 1
output = merged
if args.key:
output = {}
for key in args.key:
value = extract_key(merged, key)
if value is not _MISSING:
output[key] = value
write_json_stdout(output)
return 0
if __name__ == "__main__":
raise SystemExit(main())