-
-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathscaffold-setup-skill.py
More file actions
132 lines (114 loc) · 4.36 KB
/
scaffold-setup-skill.py
File metadata and controls
132 lines (114 loc) · 4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# ///
"""Scaffold a BMad module setup skill from template.
This is the **multi-skill direct-download bundle**: an optional add-on for
modules that need to be installable without the BMad installer. The canonical
manifests live at the module root (`<module>/module.yaml` and
`<module>/module-help.csv`); this script duplicates them into a setup skill so
users can run the skill manually to register the module.
Copies the setup-skill-template into the target directory as {code}-setup/,
then writes the supplied module.yaml and module-help.csv into the assets folder
and updates the SKILL.md frontmatter with the module's identity. The supplied
files should be the same content as the root manifests; typically pass the root
manifest paths directly via --module-yaml and --module-csv.
"""
import argparse
import json
import shutil
import sys
from pathlib import Path
def main() -> int:
parser = argparse.ArgumentParser(
description="Scaffold a BMad module setup skill from template"
)
parser.add_argument(
"--target-dir",
required=True,
help="Directory to create the setup skill in (the user's skills folder)",
)
parser.add_argument(
"--module-code",
required=True,
help="Module code (2-4 letter abbreviation, e.g. 'cis')",
)
parser.add_argument(
"--module-name",
required=True,
help="Module display name (e.g. 'Creative Intelligence Suite')",
)
parser.add_argument(
"--module-yaml",
required=True,
help="Path to the generated module.yaml content file",
)
parser.add_argument(
"--module-csv",
required=True,
help="Path to the generated module-help.csv content file",
)
parser.add_argument(
"--verbose", action="store_true", help="Print progress to stderr"
)
args = parser.parse_args()
template_dir = Path(__file__).resolve().parent.parent / "assets" / "setup-skill-template"
setup_skill_name = f"{args.module_code}-setup"
target = Path(args.target_dir) / setup_skill_name
if not template_dir.is_dir():
print(
json.dumps({"status": "error", "message": f"Template not found: {template_dir}"}),
file=sys.stdout,
)
return 2
for source_path in [args.module_yaml, args.module_csv]:
if not Path(source_path).is_file():
print(
json.dumps({"status": "error", "message": f"Source file not found: {source_path}"}),
file=sys.stdout,
)
return 2
target_dir = Path(args.target_dir)
if not target_dir.is_dir():
print(
json.dumps({"status": "error", "message": f"Target directory not found: {target_dir}"}),
file=sys.stdout,
)
return 2
# Remove existing setup skill if present (anti-zombie)
if target.exists():
if args.verbose:
print(f"Removing existing {setup_skill_name}/", file=sys.stderr)
shutil.rmtree(target)
# Copy template
if args.verbose:
print(f"Copying template to {target}", file=sys.stderr)
shutil.copytree(template_dir, target)
# Update SKILL.md frontmatter placeholders
skill_md = target / "SKILL.md"
content = skill_md.read_text(encoding="utf-8")
content = content.replace("{setup-skill-name}", setup_skill_name)
content = content.replace("{module-name}", args.module_name)
content = content.replace("{module-code}", args.module_code)
skill_md.write_text(content, encoding="utf-8")
# Write generated module.yaml
yaml_content = Path(args.module_yaml).read_text(encoding="utf-8")
(target / "assets" / "module.yaml").write_text(yaml_content, encoding="utf-8")
# Write generated module-help.csv
csv_content = Path(args.module_csv).read_text(encoding="utf-8")
(target / "assets" / "module-help.csv").write_text(csv_content, encoding="utf-8")
# Collect file list
files_created = sorted(
str(p.relative_to(target)) for p in target.rglob("*") if p.is_file()
)
result = {
"status": "success",
"setup_skill": setup_skill_name,
"location": str(target),
"files_created": files_created,
"files_count": len(files_created),
}
print(json.dumps(result, indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())