bmad-method 6.10.1-next.2 → 6.10.1-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +52 -27
- package/package.json +4 -3
- package/removals.txt +5 -0
- package/src/bmm-skills/1-analysis/bmad-agent-analyst/customize.toml +19 -4
- package/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md +1 -1
- package/src/bmm-skills/1-analysis/bmad-product-brief/customize.toml +5 -3
- package/src/bmm-skills/2-plan-workflows/bmad-prd/SKILL.md +2 -0
- package/src/bmm-skills/2-plan-workflows/bmad-prd/customize.toml +5 -3
- package/src/{core-skills → bmm-skills/2-plan-workflows}/bmad-spec/SKILL.md +18 -3
- package/src/{core-skills → bmm-skills/2-plan-workflows}/bmad-spec/assets/spec-template.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-spec/assets/stories-schema.md +44 -0
- package/src/{core-skills → bmm-skills/2-plan-workflows}/bmad-spec/customize.toml +3 -4
- package/src/bmm-skills/2-plan-workflows/bmad-ux/customize.toml +4 -2
- package/src/bmm-skills/3-solutioning/bmad-architecture/SKILL.md +2 -2
- package/src/bmm-skills/3-solutioning/bmad-architecture/customize.toml +4 -2
- package/src/bmm-skills/4-implementation/bmad-agent-dev/customize.toml +3 -0
- package/src/bmm-skills/4-implementation/bmad-code-review/SKILL.md +2 -4
- package/src/bmm-skills/4-implementation/bmad-code-review/customize.toml +52 -0
- package/src/bmm-skills/4-implementation/bmad-code-review/steps/step-01-gather-context.md +0 -1
- package/src/bmm-skills/4-implementation/bmad-code-review/steps/step-02-review.md +10 -24
- package/src/bmm-skills/4-implementation/bmad-code-review/steps/step-03-triage.md +3 -4
- package/src/bmm-skills/4-implementation/bmad-dev-auto/SKILL.md +33 -12
- package/src/bmm-skills/4-implementation/bmad-dev-auto/customize.toml +75 -0
- package/src/bmm-skills/4-implementation/bmad-dev-auto/spec-template.md +4 -4
- package/src/bmm-skills/4-implementation/bmad-dev-auto/step-01-clarify-and-route.md +22 -4
- package/src/bmm-skills/4-implementation/bmad-dev-auto/step-02-plan.md +5 -6
- package/src/bmm-skills/4-implementation/bmad-dev-auto/step-03-implement.md +8 -4
- package/src/bmm-skills/4-implementation/bmad-dev-auto/step-04-review.md +13 -19
- package/src/bmm-skills/4-implementation/bmad-dev-story/customize.toml +3 -0
- package/src/bmm-skills/4-implementation/bmad-quick-dev/SKILL.md +6 -108
- package/src/bmm-skills/4-implementation/bmad-quick-dev/customize.toml +73 -0
- package/src/bmm-skills/4-implementation/bmad-quick-dev/render.py +381 -0
- package/src/bmm-skills/4-implementation/bmad-quick-dev/spec-template.md +2 -2
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-01-clarify-and-route.md +11 -13
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-02-plan.md +4 -9
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-03-implement.md +12 -4
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-04-review.md +8 -20
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-05-present.md +4 -4
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-oneshot.md +12 -13
- package/src/bmm-skills/4-implementation/bmad-quick-dev/sync-sprint-status.md +6 -6
- package/src/bmm-skills/4-implementation/bmad-quick-dev/workflow.md +85 -0
- package/src/bmm-skills/module-help.csv +2 -4
- package/src/bmm-skills/module.yaml +2 -5
- package/src/bmm-skills/v6-shims/README.md +24 -0
- package/src/bmm-skills/{3-solutioning → v6-shims}/bmad-create-architecture/SKILL.md +1 -1
- package/src/bmm-skills/{2-plan-workflows → v6-shims}/bmad-create-prd/SKILL.md +3 -3
- package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +14 -0
- package/src/bmm-skills/{2-plan-workflows → v6-shims}/bmad-edit-prd/SKILL.md +3 -3
- package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +14 -0
- package/src/bmm-skills/{2-plan-workflows → v6-shims}/bmad-validate-prd/SKILL.md +3 -3
- package/src/core-skills/bmad-advanced-elicitation/SKILL.md +26 -103
- package/src/core-skills/bmad-advanced-elicitation/customize.toml +54 -0
- package/src/core-skills/bmad-advanced-elicitation/scripts/pick_methods.py +233 -0
- package/src/core-skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py +228 -0
- package/src/core-skills/bmad-brainstorming/SKILL.md +3 -3
- package/src/core-skills/bmad-brainstorming/assets/brain-selector.html +2 -0
- package/src/core-skills/bmad-brainstorming/references/mode-autonomous.md +1 -1
- package/src/core-skills/bmad-brainstorming/scripts/brain.py +36 -6
- package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +22 -0
- package/src/core-skills/bmad-customize/SKILL.md +2 -2
- package/src/core-skills/bmad-deep-recon/SKILL.md +82 -0
- package/src/core-skills/bmad-deep-recon/assets/research.template.md +18 -0
- package/src/core-skills/bmad-deep-recon/customize.toml +212 -0
- package/src/core-skills/bmad-deep-recon/references/draft.md +8 -0
- package/src/core-skills/bmad-deep-recon/references/finalize.md +11 -0
- package/src/core-skills/bmad-deep-recon/references/html-briefing.md +16 -0
- package/src/core-skills/bmad-deep-recon/references/lifecycle.md +11 -0
- package/src/core-skills/bmad-deep-recon/references/process.md +10 -0
- package/src/core-skills/bmad-deep-recon/references/run.md +73 -0
- package/src/core-skills/bmad-deep-recon/references/selection.md +13 -0
- package/src/core-skills/bmad-deep-recon/references/synthesis.md +16 -0
- package/src/core-skills/bmad-deep-recon/references/verification.md +29 -0
- package/src/core-skills/bmad-deep-recon/scripts/recon_kit.py +322 -0
- package/src/core-skills/bmad-deep-recon/scripts/tests/test_recon_kit.py +144 -0
- package/src/core-skills/bmad-deep-recon/types/academic-lit.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/competitive.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/domain.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/market.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/technical.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/user-voice.md +19 -0
- package/src/core-skills/bmad-forge-idea/SKILL.md +2 -2
- package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +4 -1
- package/src/core-skills/bmad-help/SKILL.md +1 -1
- package/src/core-skills/bmad-party-mode/SKILL.md +2 -2
- package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +11 -3
- package/src/core-skills/bmad-review/SKILL.md +49 -0
- package/src/core-skills/bmad-review/customize.toml +141 -0
- package/src/core-skills/bmad-review/references/editorial-common.md +56 -0
- package/src/core-skills/bmad-review/references/lens-adversarial.md +18 -0
- package/src/core-skills/bmad-review/references/lens-edge-case-hunter.md +54 -0
- package/src/core-skills/bmad-review/references/lens-prose.md +7 -0
- package/src/core-skills/bmad-review/references/lens-structure.md +9 -0
- package/src/core-skills/{bmad-review-verification-gap/SKILL.md → bmad-review/references/lens-verification-gap.md} +15 -39
- package/src/core-skills/bmad-review/references/structure-models.md +44 -0
- package/src/core-skills/bmad-review/scripts/tests/test_word_metrics.py +62 -0
- package/src/core-skills/bmad-review/scripts/word_metrics.py +102 -0
- package/src/core-skills/module-help.csv +3 -7
- package/src/core-skills/module.yaml +5 -0
- package/src/core-skills/v6-shims/README.md +25 -0
- package/src/core-skills/v6-shims/bmad-editorial-review/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-editorial-review/customize.toml +31 -0
- package/src/core-skills/v6-shims/bmad-editorial-review-prose/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-editorial-review-structure/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-adversarial-general/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-edge-case-hunter/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-verification-gap/SKILL.md +6 -0
- package/tools/installer/ide/platform-codes.yaml +7 -0
- package/tools/installer/modules/custom-module-manager.js +12 -6
- package/tools/installer/modules/external-manager.js +12 -8
- package/tools/installer/modules/git-env.js +47 -0
- package/tools/skill-validator.md +11 -1
- package/tools/validate-skills.js +33 -0
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/SKILL.md +0 -96
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/customize.toml +0 -41
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-01-init.md +0 -137
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-02-domain-analysis.md +0 -229
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-03-competitive-landscape.md +0 -238
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-04-regulatory-focus.md +0 -206
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-05-technical-trends.md +0 -234
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-06-research-synthesis.md +0 -450
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/research.template.md +0 -29
- package/src/bmm-skills/1-analysis/research/bmad-market-research/SKILL.md +0 -96
- package/src/bmm-skills/1-analysis/research/bmad-market-research/customize.toml +0 -41
- package/src/bmm-skills/1-analysis/research/bmad-market-research/research.template.md +0 -29
- package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-01-init.md +0 -184
- package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-02-customer-behavior.md +0 -239
- package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-03-customer-pain-points.md +0 -251
- package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-04-customer-decisions.md +0 -261
- package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-05-competitive-analysis.md +0 -173
- package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-06-research-completion.md +0 -484
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/SKILL.md +0 -96
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/customize.toml +0 -41
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/research.template.md +0 -29
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-01-init.md +0 -137
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-02-technical-overview.md +0 -239
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-03-integration-patterns.md +0 -248
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-04-architectural-patterns.md +0 -202
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-05-implementation-research.md +0 -233
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-06-research-synthesis.md +0 -493
- package/src/core-skills/bmad-brainstorming/analysis/catalog-analysis.md +0 -239
- package/src/core-skills/bmad-brainstorming/analysis/method-matrix.csv +0 -109
- package/src/core-skills/bmad-editorial-review-prose/SKILL.md +0 -86
- package/src/core-skills/bmad-editorial-review-structure/SKILL.md +0 -179
- package/src/core-skills/bmad-index-docs/SKILL.md +0 -66
- package/src/core-skills/bmad-review-adversarial-general/SKILL.md +0 -37
- package/src/core-skills/bmad-review-edge-case-hunter/SKILL.md +0 -73
- package/src/core-skills/bmad-review-edge-case-hunter/references/deletion-check.md +0 -14
- package/src/core-skills/bmad-shard-doc/SKILL.md +0 -105
- /package/src/{core-skills → bmm-skills/2-plan-workflows}/bmad-spec/assets/headless-schemas.md +0 -0
- /package/src/bmm-skills/{3-solutioning → v6-shims}/bmad-create-architecture/customize.toml +0 -0
- /package/src/bmm-skills/{2-plan-workflows → v6-shims}/bmad-create-prd/customize.toml +0 -0
- /package/src/bmm-skills/{2-plan-workflows → v6-shims}/bmad-edit-prd/customize.toml +0 -0
- /package/src/bmm-skills/{2-plan-workflows → v6-shims}/bmad-validate-prd/customize.toml +0 -0
- /package/src/core-skills/bmad-advanced-elicitation/{methods.csv → assets/methods.csv} +0 -0
- /package/src/core-skills/bmad-party-mode/scripts/tests/{test-resolve_party.py → test_resolve_party.py} +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.10"
|
|
4
|
+
# ///
|
|
5
|
+
"""Exact word counts for a document, as JSON.
|
|
6
|
+
|
|
7
|
+
Emits the document's total word count and a per-heading-section breakdown so
|
|
8
|
+
an editorial review can ground word-impact estimates and reduction
|
|
9
|
+
percentages in real numbers instead of guessing. Sections are delimited by
|
|
10
|
+
markdown headings (# through ######); heading markers inside fenced code
|
|
11
|
+
blocks are ignored (fences pair CommonMark-style: a fence closes only on a
|
|
12
|
+
run of the same character at least as long, so ```` fences may embed ```
|
|
13
|
+
examples). A word is any whitespace-separated token, plus one word per CJK
|
|
14
|
+
character since those scripts do not space-delimit words. For non-markdown
|
|
15
|
+
input the result is a single section holding the full text.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import json
|
|
20
|
+
import re
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
HEADING = re.compile(r"^(#{1,6})\s+(\S.*)$")
|
|
25
|
+
FENCE = re.compile(r"^ {0,3}(`{3,}|~{3,})")
|
|
26
|
+
CJK = re.compile(r"[-ヿ㐀-䶿一-鿿豈-가-ヲ-゚]")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def word_count(text: str) -> int:
|
|
30
|
+
cjk = len(CJK.findall(text))
|
|
31
|
+
return cjk + len(CJK.sub(" ", text).split())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def section_metrics(text: str) -> list[dict]:
|
|
35
|
+
sections = []
|
|
36
|
+
current = {"heading": "(preamble)", "level": 0, "body": []}
|
|
37
|
+
open_fence = None # (char, length) while inside a fenced block
|
|
38
|
+
for line in text.splitlines():
|
|
39
|
+
fence = FENCE.match(line)
|
|
40
|
+
if fence:
|
|
41
|
+
marker = fence.group(1)
|
|
42
|
+
if open_fence is None:
|
|
43
|
+
open_fence = (marker[0], len(marker))
|
|
44
|
+
elif marker[0] == open_fence[0] and len(marker) >= open_fence[1] and line.strip() == marker:
|
|
45
|
+
open_fence = None
|
|
46
|
+
current["body"].append(line)
|
|
47
|
+
continue
|
|
48
|
+
match = None if open_fence else HEADING.match(line)
|
|
49
|
+
if match:
|
|
50
|
+
sections.append(current)
|
|
51
|
+
current = {
|
|
52
|
+
"heading": match.group(2).strip(),
|
|
53
|
+
"level": len(match.group(1)),
|
|
54
|
+
"body": [],
|
|
55
|
+
}
|
|
56
|
+
else:
|
|
57
|
+
current["body"].append(line)
|
|
58
|
+
sections.append(current)
|
|
59
|
+
|
|
60
|
+
out = []
|
|
61
|
+
for section in sections:
|
|
62
|
+
words = word_count("\n".join(section["body"]))
|
|
63
|
+
if section["heading"] == "(preamble)" and words == 0:
|
|
64
|
+
continue
|
|
65
|
+
out.append(
|
|
66
|
+
{"heading": section["heading"], "level": section["level"], "words": words}
|
|
67
|
+
)
|
|
68
|
+
return out
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def metrics(path: Path) -> dict:
|
|
72
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
73
|
+
return {
|
|
74
|
+
"file": str(path),
|
|
75
|
+
"total_words": word_count(text),
|
|
76
|
+
"sections": section_metrics(text),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def main() -> int:
|
|
81
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
82
|
+
sys.stdout.reconfigure(encoding="utf-8") # JSON is UTF-8 regardless of locale code page
|
|
83
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
84
|
+
parser.add_argument("path", help="document to measure")
|
|
85
|
+
parser.add_argument("-o", "--output", help="write JSON here (default: stdout)")
|
|
86
|
+
args = parser.parse_args()
|
|
87
|
+
|
|
88
|
+
path = Path(args.path)
|
|
89
|
+
if not path.is_file():
|
|
90
|
+
print(f"error: not a readable file: {path}", file=sys.stderr)
|
|
91
|
+
return 2
|
|
92
|
+
|
|
93
|
+
result = json.dumps(metrics(path), indent=2, ensure_ascii=False)
|
|
94
|
+
if args.output:
|
|
95
|
+
Path(args.output).write_text(result + "\n", encoding="utf-8")
|
|
96
|
+
else:
|
|
97
|
+
print(result)
|
|
98
|
+
return 0
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
if __name__ == "__main__":
|
|
102
|
+
sys.exit(main())
|
|
@@ -3,12 +3,8 @@ Core,_meta,,,,,,,,,false,https://docs.bmad-method.org/llms.txt,
|
|
|
3
3
|
Core,bmad-brainstorming,Brainstorming,BSP,Use early in ideation or when stuck generating ideas.,,,anytime,,,false,{output_folder}/brainstorming,brainstorming session
|
|
4
4
|
Core,bmad-party-mode,Party Mode,PM,Orchestrate multi-agent discussions when you need multiple perspectives or want agents to collaborate.,,,anytime,,,false,,
|
|
5
5
|
Core,bmad-help,BMad Help,BH,,,,anytime,,,false,,
|
|
6
|
-
Core,bmad-index-docs,Index Docs,ID,Use when LLM needs to understand available docs without loading everything.,,,anytime,,,false,,
|
|
7
|
-
Core,bmad-shard-doc,Shard Document,SD,Use when doc becomes too large (>500 lines) to manage effectively.,,[path],anytime,,,false,,
|
|
8
|
-
Core,bmad-editorial-review-prose,Editorial Review - Prose,EP,Use after drafting to polish written content.,,[path],anytime,,,false,report located with target document,three-column markdown table with suggested fixes
|
|
9
|
-
Core,bmad-editorial-review-structure,Editorial Review - Structure,ES,Use when doc produced from multiple subprocesses or needs structural improvement.,,[path],anytime,,,false,report located with target document,
|
|
10
|
-
Core,bmad-review-adversarial-general,Adversarial Review,AR,"Use for quality assurance or before finalizing deliverables. Code Review in other modules runs this automatically, but also useful for document reviews.",,[path],anytime,,,false,,
|
|
11
|
-
Core,bmad-review-edge-case-hunter,Edge Case Hunter Review,ECH,Use alongside adversarial review for orthogonal coverage — method-driven not attitude-driven.,,[path],anytime,,,false,,
|
|
12
|
-
Core,bmad-spec,Spec,SP,"Use to distill any intent input (brief, PRD, transcript, brain dump, design folder, mixed multi-source) into a succinct, no-fluff SPEC.md contract + companions that downstream work derives from. Locks the WHAT before the HOW. Works for software, game design, research, editorial, policy, business, anything intent-bearing. Validation mode also available.",,[path],anytime,,,false,{output_folder}/specs/spec-{slug},SPEC.md + companion files
|
|
13
6
|
Core,bmad-customize,BMad Customize,BC,"Use when you want to change how an agent or workflow behaves — add persistent facts, swap templates, insert activation hooks, or customize menus. Scans what's customizable, picks the right scope (agent vs workflow), writes the override to _bmad/custom/, and verifies the merge. No TOML hand-authoring required.",,,anytime,,,false,{project-root}/_bmad/custom,TOML override files
|
|
7
|
+
Core,bmad-advanced-elicitation,Advanced Elicitation,AE,"Use at any checkpoint to push a just-produced draft, section, or plan past its first version — pick from a menu of elicitation methods (pre-mortem, first principles, red team, socratic) and apply the improvements.",,,anytime,,,false,,
|
|
8
|
+
Core,bmad-review,Review,RV,"Use to review anything before it ships — a diff, branch, or uncommitted changes; a PRD, spec, story, or architecture doc; any prose document. Runs whichever installed lenses fit the content and reports findings in one shape: shipped lenses cover adversarial critique, edge cases, verification gaps, document structure (cuts, merges, moves), and prose copy-edit, and installs may add more. Reach for it to tighten a bloated or LLM-slop draft, pressure-test a plan before building, or check a change is adequately tested. Run every applicable lens or name the ones you want. Code Review in other modules calls it automatically.",,[path],anytime,,,false,,findings JSON array + markdown report
|
|
14
9
|
Core,bmad-forge-idea,Forge Idea,FI,"Use to pressure-test and harden an idea — software, business, creative, research, or life — until it proves out, hardens into something buildable, or dies cheaply. Persona-driven interrogation; optional handoff to bmad-spec or bmad-quick-dev.",,,anytime,,,false,{output_folder}/forge,refined-idea brief (optional)
|
|
10
|
+
Core,bmad-deep-recon,Deep Recon,RS,Decision-grade research three ways: draft a deep-research prompt for your own AI tool then process the returned report into a downstream-ready cited summary — or run the research directly via web fan-out. Types: market domain technical competitive user-voice academic-lit plus a select shape for choose-between decisions; claim verification and refresh lifecycle. Custom types via overrides.,,[type],anytime,,,false,{planning_artifacts}/research,research report/summary + optional html briefing
|
|
@@ -31,3 +31,8 @@ output_folder:
|
|
|
31
31
|
prompt: "Where should output files be saved?"
|
|
32
32
|
default: "_bmad-output"
|
|
33
33
|
result: "{project-root}/{value}"
|
|
34
|
+
|
|
35
|
+
# The one directory created at install time. Everything else (module artifact
|
|
36
|
+
# folders, project knowledge) is created lazily by the first skill that writes there.
|
|
37
|
+
directories:
|
|
38
|
+
- "{output_folder}"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# v6 Deprecation Shims
|
|
2
|
+
|
|
3
|
+
Skills in this folder are forwarders kept for backward compatibility with v6 skill IDs.
|
|
4
|
+
Each one holds no logic of its own — it forwards to the skill that replaced it, pinning
|
|
5
|
+
the legacy output contract so existing callers keep working.
|
|
6
|
+
|
|
7
|
+
| Shim | Forwards to |
|
|
8
|
+
| --------------------------------- | ---------------------------------------- |
|
|
9
|
+
| `bmad-editorial-review` | `bmad-review` (structure + prose lenses) |
|
|
10
|
+
| `bmad-editorial-review-prose` | `bmad-review` (prose lens) |
|
|
11
|
+
| `bmad-editorial-review-structure` | `bmad-review` (structure lens) |
|
|
12
|
+
| `bmad-review-adversarial-general` | `bmad-review` (adversarial lens) |
|
|
13
|
+
| `bmad-review-edge-case-hunter` | `bmad-review` (edge-case lens) |
|
|
14
|
+
| `bmad-review-verification-gap` | `bmad-review` (verification-gap lens) |
|
|
15
|
+
|
|
16
|
+
`bmad-editorial-review` keeps its `customize.toml` so existing team and user
|
|
17
|
+
overrides still resolve; the shim forwards those resolved values to `bmad-review`.
|
|
18
|
+
|
|
19
|
+
External module repos (gds, loop, tea, bmb, os-utils) still invoke these IDs, so they
|
|
20
|
+
ship by default. Removal rides the v7 cut — never a 6.x minor.
|
|
21
|
+
|
|
22
|
+
The folder is grouping only: the installer discovers skills recursively and installs each
|
|
23
|
+
one under its own `name`, so nesting here does not change any installed path or skill ID.
|
|
24
|
+
A future install option will let users include or exclude this folder before it is removed
|
|
25
|
+
outright.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-editorial-review
|
|
3
|
+
description: 'Deprecated — forwards to bmad-review.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Merged into `bmad-review`. Invoke the `bmad-review` skill on the same content with the `structure` and `prose` lenses — both, structure first, so prose runs on top of the structure findings — unless the caller asked for a structure-only or prose-only review, in which case pass only that lens. Pass through any `also_consider` areas, and forward this skill's resolved `[workflow]` fields as pre-resolved values — but only those that resolved to something, since an empty value here means no legacy override exists and bmad-review's own default should stand: `reader_type`, `style_guide`, `review_guidance`, `output_preferences`, `persistent_facts`, `activation_steps_prepend`, `activation_steps_append`, `on_complete`, and `review_output_path` as the report path. Present the findings in the legacy shape: the two-pass findings table `| Pass | Original Text | Revised Text | Changes |` with the purpose/audience read above it and, when the structure pass ran, the reduction summary below it — and no other lens's output.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# DO NOT EDIT -- overwritten on every update.
|
|
2
|
+
#
|
|
3
|
+
# Legacy override surface for bmad-editorial-review, which is deprecated and
|
|
4
|
+
# forwards to bmad-review's `structure` and `prose` lenses. These keys exist
|
|
5
|
+
# only so overrides written against the old skill keep resolving: the shim
|
|
6
|
+
# resolves them here and passes them to bmad-review as pre-resolved values,
|
|
7
|
+
# which bmad-review honors verbatim over its own.
|
|
8
|
+
#
|
|
9
|
+
# Every field is documented in bmad-review's customize.toml, which is where
|
|
10
|
+
# new customization belongs. Defaults are empty here so the shim contributes
|
|
11
|
+
# nothing of its own — an unset key falls through to bmad-review's default.
|
|
12
|
+
#
|
|
13
|
+
# Override files (not edited here):
|
|
14
|
+
# {project-root}/_bmad/custom/bmad-editorial-review.toml (team)
|
|
15
|
+
# {project-root}/_bmad/custom/bmad-editorial-review.user.toml (personal)
|
|
16
|
+
#
|
|
17
|
+
# Overrides merge per BMad structural rules: scalars win, arrays append.
|
|
18
|
+
|
|
19
|
+
[workflow]
|
|
20
|
+
|
|
21
|
+
activation_steps_prepend = []
|
|
22
|
+
activation_steps_append = []
|
|
23
|
+
persistent_facts = []
|
|
24
|
+
review_guidance = []
|
|
25
|
+
on_complete = ""
|
|
26
|
+
output_preferences = ""
|
|
27
|
+
reader_type = ""
|
|
28
|
+
style_guide = ""
|
|
29
|
+
|
|
30
|
+
# Where the findings table lands; forwarded as bmad-review's report path.
|
|
31
|
+
review_output_path = ""
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-editorial-review-prose
|
|
3
|
+
description: 'Deprecated — forwards to bmad-review.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Merged into `bmad-review`. Invoke the `bmad-review` skill on the same content with only the `prose` lens, passing through the same inputs and any `also_consider` areas. Present the findings in the legacy shape: a three-column markdown table `| Original Text | Revised Text | Changes |` — no Pass column, no preamble above the table. If no issues are found, output exactly: `No editorial issues identified`.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-editorial-review-structure
|
|
3
|
+
description: 'Deprecated — forwards to bmad-review.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Merged into `bmad-review`. Invoke the `bmad-review` skill on the same content with only the `structure` lens, passing through the same inputs and any `also_consider` areas. Present the findings in the legacy report shape: a `## Document Summary` block (purpose, audience, reader type, structure model, current length), a `## Recommendations` list of numbered `[CUT/MERGE/MOVE/CONDENSE/QUESTION/PRESERVE]` entries each with rationale and word impact, and a closing `## Summary` (total recommendations, estimated reduction) — not the findings table. If no structural issues are found, output exactly: `No substantive changes recommended`.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-review-adversarial-general
|
|
3
|
+
description: 'Deprecated — forwards to bmad-review.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Merged into `bmad-review`. Invoke the `bmad-review` skill on the same content with only the `adversarial` lens, passing through any `also_consider` areas. Present the findings as a Markdown list — descriptions only, no severity, priority, or ranking; no JSON block.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-review-edge-case-hunter
|
|
3
|
+
description: 'Deprecated — forwards to bmad-review.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Merged into `bmad-review`. Invoke the `bmad-review` skill on the same content with only the `edge-case-hunter` lens, passing through any `also_consider` areas. Output ONLY the raw findings JSON array in the legacy shape: the four standard fields (plus `kind`/`confidence` on deletion findings), no `lens` field, no markdown wrapping, no extra text. `[]` is valid when nothing is found.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-review-verification-gap
|
|
3
|
+
description: 'Deprecated — forwards to bmad-review.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Merged into `bmad-review`. Invoke the `bmad-review` skill on the same content with only the `verification-gap` lens. Present the markdown rendering only (no JSON block), listing any `gap_shape: "other"` findings under an `## Other findings` heading. When there are no findings at all, output exactly this single line: `No verification gaps found.`
|
|
@@ -35,6 +35,13 @@ platforms:
|
|
|
35
35
|
target_dir: .agent/skills
|
|
36
36
|
global_target_dir: ~/.gemini/antigravity/skills
|
|
37
37
|
|
|
38
|
+
antigravity-cli:
|
|
39
|
+
name: "Antigravity CLI (AGY)"
|
|
40
|
+
preferred: false
|
|
41
|
+
installer:
|
|
42
|
+
target_dir: .agents/skills
|
|
43
|
+
global_target_dir: ~/.gemini/antigravity-cli/skills
|
|
44
|
+
|
|
38
45
|
auggie:
|
|
39
46
|
name: "Auggie"
|
|
40
47
|
preferred: false
|
|
@@ -3,6 +3,7 @@ const os = require('node:os');
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
const { execSync } = require('node:child_process');
|
|
5
5
|
const prompts = require('../prompts');
|
|
6
|
+
const { gitEnv } = require('./git-env');
|
|
6
7
|
|
|
7
8
|
function quoteCustomRef(ref) {
|
|
8
9
|
if (typeof ref !== 'string' || !/^[\w.\-+/]+$/.test(ref)) {
|
|
@@ -418,7 +419,7 @@ class CustomModuleManager {
|
|
|
418
419
|
execSync('git fetch origin --depth 1', {
|
|
419
420
|
cwd: repoCacheDir,
|
|
420
421
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
421
|
-
env: {
|
|
422
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
422
423
|
});
|
|
423
424
|
if (effectiveVersion) {
|
|
424
425
|
// Fetch the ref as either a tag or a branch — `origin <ref>` works
|
|
@@ -427,11 +428,12 @@ class CustomModuleManager {
|
|
|
427
428
|
execSync(`git fetch --depth 1 origin ${quoteCustomRef(effectiveVersion)} --no-tags`, {
|
|
428
429
|
cwd: repoCacheDir,
|
|
429
430
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
430
|
-
env: {
|
|
431
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
431
432
|
});
|
|
432
433
|
execSync(`git checkout --quiet FETCH_HEAD`, {
|
|
433
434
|
cwd: repoCacheDir,
|
|
434
435
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
436
|
+
env: gitEnv(),
|
|
435
437
|
});
|
|
436
438
|
} else {
|
|
437
439
|
// Resolve the default branch (origin/HEAD) and fetch it explicitly.
|
|
@@ -442,6 +444,7 @@ class CustomModuleManager {
|
|
|
442
444
|
defaultBranch = execSync('git symbolic-ref refs/remotes/origin/HEAD --short', {
|
|
443
445
|
cwd: repoCacheDir,
|
|
444
446
|
stdio: 'pipe',
|
|
447
|
+
env: gitEnv(),
|
|
445
448
|
})
|
|
446
449
|
.toString()
|
|
447
450
|
.trim()
|
|
@@ -452,11 +455,12 @@ class CustomModuleManager {
|
|
|
452
455
|
execSync(`git fetch --depth 1 origin ${quoteCustomRef(defaultBranch)}`, {
|
|
453
456
|
cwd: repoCacheDir,
|
|
454
457
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
455
|
-
env: {
|
|
458
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
456
459
|
});
|
|
457
460
|
execSync(`git reset --hard origin/${quoteCustomRef(defaultBranch)}`, {
|
|
458
461
|
cwd: repoCacheDir,
|
|
459
462
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
463
|
+
env: gitEnv(),
|
|
460
464
|
});
|
|
461
465
|
}
|
|
462
466
|
fetchSpinner.stop(`Updated ${displayName}`);
|
|
@@ -477,12 +481,12 @@ class CustomModuleManager {
|
|
|
477
481
|
if (effectiveVersion) {
|
|
478
482
|
execSync(`git clone --depth 1 --branch ${quoteCustomRef(effectiveVersion)} "${parsed.cloneUrl}" "${repoCacheDir}"`, {
|
|
479
483
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
480
|
-
env: {
|
|
484
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
481
485
|
});
|
|
482
486
|
} else {
|
|
483
487
|
execSync(`git clone --depth 1 "${parsed.cloneUrl}" "${repoCacheDir}"`, {
|
|
484
488
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
485
|
-
env: {
|
|
489
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
486
490
|
});
|
|
487
491
|
}
|
|
488
492
|
fetchSpinner.stop(`Cloned ${displayName}`);
|
|
@@ -496,7 +500,7 @@ class CustomModuleManager {
|
|
|
496
500
|
// Record the resolved SHA for the manifest writer.
|
|
497
501
|
let resolvedSha = null;
|
|
498
502
|
try {
|
|
499
|
-
resolvedSha = execSync('git rev-parse HEAD', { cwd: repoCacheDir, stdio: 'pipe' }).toString().trim();
|
|
503
|
+
resolvedSha = execSync('git rev-parse HEAD', { cwd: repoCacheDir, stdio: 'pipe', env: gitEnv() }).toString().trim();
|
|
500
504
|
} catch {
|
|
501
505
|
// swallow — a non-git repo (local path) wouldn't reach here anyway
|
|
502
506
|
}
|
|
@@ -508,6 +512,7 @@ class CustomModuleManager {
|
|
|
508
512
|
const symbolic = execSync('git symbolic-ref --short refs/remotes/origin/HEAD', {
|
|
509
513
|
cwd: repoCacheDir,
|
|
510
514
|
stdio: 'pipe',
|
|
515
|
+
env: gitEnv(),
|
|
511
516
|
})
|
|
512
517
|
.toString()
|
|
513
518
|
.trim();
|
|
@@ -558,6 +563,7 @@ class CustomModuleManager {
|
|
|
558
563
|
cwd: repoCacheDir,
|
|
559
564
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
560
565
|
timeout: 120_000,
|
|
566
|
+
env: gitEnv(), // npm shells out to git for git-URL deps; keep hook GIT_* vars away from it
|
|
561
567
|
});
|
|
562
568
|
installSpinner.stop(`Installed dependencies for ${displayName}`);
|
|
563
569
|
} catch (error_) {
|
|
@@ -5,6 +5,7 @@ const { execSync } = require('node:child_process');
|
|
|
5
5
|
const yaml = require('yaml');
|
|
6
6
|
const prompts = require('../prompts');
|
|
7
7
|
const { resolveChannel, tagExists, parseGitHubRepo } = require('./channel-resolver');
|
|
8
|
+
const { gitEnv } = require('./git-env');
|
|
8
9
|
const { decideChannelForModule } = require('./channel-plan');
|
|
9
10
|
const { getProjectRoot } = require('../project-root');
|
|
10
11
|
|
|
@@ -370,33 +371,34 @@ class ExternalModuleManager {
|
|
|
370
371
|
const fetchSpinner = await createSpinner();
|
|
371
372
|
fetchSpinner.start(`Fetching ${moduleInfo.name}...`);
|
|
372
373
|
try {
|
|
373
|
-
const currentSha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
|
|
374
|
+
const currentSha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe', env: gitEnv() }).toString().trim();
|
|
374
375
|
|
|
375
376
|
if (resolved.channel === 'next') {
|
|
376
377
|
execSync('git fetch origin --depth 1', {
|
|
377
378
|
cwd: moduleCacheDir,
|
|
378
379
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
379
|
-
env: {
|
|
380
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
380
381
|
});
|
|
381
382
|
execSync('git reset --hard origin/HEAD', {
|
|
382
383
|
cwd: moduleCacheDir,
|
|
383
384
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
384
|
-
env: {
|
|
385
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
385
386
|
});
|
|
386
387
|
} else {
|
|
387
388
|
// stable or pinned — fetch the specific tag and check it out.
|
|
388
389
|
execSync(`git fetch --depth 1 origin tag ${quoteShell(resolved.ref)} --no-tags`, {
|
|
389
390
|
cwd: moduleCacheDir,
|
|
390
391
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
391
|
-
env: {
|
|
392
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
392
393
|
});
|
|
393
394
|
execSync(`git checkout --quiet FETCH_HEAD`, {
|
|
394
395
|
cwd: moduleCacheDir,
|
|
395
396
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
397
|
+
env: gitEnv(),
|
|
396
398
|
});
|
|
397
399
|
}
|
|
398
400
|
|
|
399
|
-
const newSha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
|
|
401
|
+
const newSha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe', env: gitEnv() }).toString().trim();
|
|
400
402
|
fetchSpinner.stop(`Fetched ${moduleInfo.name}`);
|
|
401
403
|
if (currentSha !== newSha) needsDependencyInstall = true;
|
|
402
404
|
} catch {
|
|
@@ -415,12 +417,12 @@ class ExternalModuleManager {
|
|
|
415
417
|
if (resolved.channel === 'next') {
|
|
416
418
|
execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, {
|
|
417
419
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
418
|
-
env: {
|
|
420
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
419
421
|
});
|
|
420
422
|
} else {
|
|
421
423
|
execSync(`git clone --depth 1 --branch ${quoteShell(resolved.ref)} "${moduleInfo.url}" "${moduleCacheDir}"`, {
|
|
422
424
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
423
|
-
env: {
|
|
425
|
+
env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),
|
|
424
426
|
});
|
|
425
427
|
}
|
|
426
428
|
fetchSpinner.stop(`Fetched ${moduleInfo.name}`);
|
|
@@ -431,7 +433,7 @@ class ExternalModuleManager {
|
|
|
431
433
|
}
|
|
432
434
|
|
|
433
435
|
// Record resolution (channel + tag + SHA) for the manifest writer to pick up.
|
|
434
|
-
const sha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
|
|
436
|
+
const sha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe', env: gitEnv() }).toString().trim();
|
|
435
437
|
ExternalModuleManager._resolutions.set(moduleCode, {
|
|
436
438
|
channel: resolved.channel,
|
|
437
439
|
version: resolved.version,
|
|
@@ -459,6 +461,7 @@ class ExternalModuleManager {
|
|
|
459
461
|
cwd: moduleCacheDir,
|
|
460
462
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
461
463
|
timeout: 120_000, // 2 minute timeout
|
|
464
|
+
env: gitEnv(), // npm shells out to git for git-URL deps; keep hook GIT_* vars away from it
|
|
462
465
|
});
|
|
463
466
|
installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`);
|
|
464
467
|
} catch (error) {
|
|
@@ -485,6 +488,7 @@ class ExternalModuleManager {
|
|
|
485
488
|
cwd: moduleCacheDir,
|
|
486
489
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
487
490
|
timeout: 120_000, // 2 minute timeout
|
|
491
|
+
env: gitEnv(), // npm shells out to git for git-URL deps; keep hook GIT_* vars away from it
|
|
488
492
|
});
|
|
489
493
|
installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`);
|
|
490
494
|
} catch (error) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitized environment for spawning git subprocesses.
|
|
3
|
+
*
|
|
4
|
+
* When the installer runs inside a git hook (e.g. `npm test` from a
|
|
5
|
+
* pre-commit hook), git exports repo-targeting variables — GIT_DIR,
|
|
6
|
+
* GIT_INDEX_FILE, GIT_WORK_TREE, etc. — into the hook's environment. A
|
|
7
|
+
* spawned `git` inherits them and silently operates on the hook's repository
|
|
8
|
+
* instead of the cwd passed to execSync (GIT_DIR overrides directory
|
|
9
|
+
* discovery, and the cwd then becomes its work tree). In a worktree checkout
|
|
10
|
+
* this let a cache refresh shallow-fetch and hard-reset the developer's own
|
|
11
|
+
* repo. Strip these variables so cache-directory git commands can only ever
|
|
12
|
+
* act on the repository at their cwd.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const REPO_TARGETING_VARS = [
|
|
16
|
+
'GIT_DIR',
|
|
17
|
+
'GIT_WORK_TREE',
|
|
18
|
+
'GIT_INDEX_FILE',
|
|
19
|
+
'GIT_COMMON_DIR',
|
|
20
|
+
'GIT_OBJECT_DIRECTORY',
|
|
21
|
+
'GIT_ALTERNATE_OBJECT_DIRECTORIES',
|
|
22
|
+
'GIT_PREFIX',
|
|
23
|
+
'GIT_NAMESPACE',
|
|
24
|
+
// `git -c key=val` exports its overrides to hook subprocesses through these;
|
|
25
|
+
// a core.worktree override can retarget the work tree just like GIT_WORK_TREE.
|
|
26
|
+
'GIT_CONFIG_PARAMETERS',
|
|
27
|
+
'GIT_CONFIG_COUNT',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// GIT_CONFIG_KEY_0 / GIT_CONFIG_VALUE_0 ... — the enumerated form of the same mechanism.
|
|
31
|
+
const CONFIG_PAIR_VAR = /^GIT_CONFIG_(KEY|VALUE)_\d+$/;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build the environment for a git child process.
|
|
35
|
+
* @param {Object} [extra] - Additional variables to set (e.g. GIT_TERMINAL_PROMPT)
|
|
36
|
+
* @returns {Object} process.env minus repo-targeting GIT_* vars, plus extras
|
|
37
|
+
*/
|
|
38
|
+
function gitEnv(extra = {}) {
|
|
39
|
+
const env = { ...process.env, ...extra };
|
|
40
|
+
for (const name of REPO_TARGETING_VARS) delete env[name];
|
|
41
|
+
for (const name of Object.keys(env)) {
|
|
42
|
+
if (CONFIG_PAIR_VAR.test(name)) delete env[name];
|
|
43
|
+
}
|
|
44
|
+
return env;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { gitEnv };
|
package/tools/skill-validator.md
CHANGED
|
@@ -10,7 +10,7 @@ Before running inference-based validation, run the deterministic validator:
|
|
|
10
10
|
node tools/validate-skills.js --json path/to/skill-dir
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
This checks
|
|
13
|
+
This checks 13 rules deterministically: SKILL-01, SKILL-02, SKILL-03, SKILL-04, SKILL-05, SKILL-06, SKILL-07, PATH-02, STEP-01, STEP-06, STEP-07, SEQ-02, TPL-01.
|
|
14
14
|
|
|
15
15
|
Review its JSON output. For any rule that produced **zero findings** in the first pass, **skip it** during inference-based validation below — it has already been verified. If a rule produced any findings, the inference validator should still review that rule (some rules like SKILL-04 and SKILL-06 have sub-checks that benefit from judgment). Focus your inference effort on the remaining rules that require judgment (PATH-01, PATH-03, PATH-04, PATH-05, WF-03, STEP-02, STEP-03, STEP-04, STEP-05, SEQ-01, REF-01, REF-02, REF-03).
|
|
16
16
|
|
|
@@ -253,6 +253,16 @@ If no findings are generated (from either pass), the skill passes validation.
|
|
|
253
253
|
|
|
254
254
|
---
|
|
255
255
|
|
|
256
|
+
### TPL-01 — Template Files Must Not Contain Compile-Time Substitutions
|
|
257
|
+
|
|
258
|
+
- **Severity:** HIGH
|
|
259
|
+
- **Applies to:** `.md` files whose name contains `template` (case-insensitive)
|
|
260
|
+
- **Rule:** Template files seed durable, version-controlled artifacts (e.g. spec files) that execute on other machines. A `{{.var}}` compile-time substitution would be baked at render time and freeze a machine-local value into every artifact produced from the template.
|
|
261
|
+
- **Detection:** Regex `\{\{\.\w+\}\}` match anywhere in a file whose basename matches `/template/i`.
|
|
262
|
+
- **Fix:** Remove the `{{.var}}` reference. Use single-curly `{var}` if the value should be resolved at LLM runtime by the consumer of the generated artifact.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
256
266
|
### REF-01 — Variable References Must Be Defined
|
|
257
267
|
|
|
258
268
|
- **Severity:** HIGH
|
package/tools/validate-skills.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* - STEP-06: step frontmatter has no name/description
|
|
18
18
|
* - STEP-07: step count 2-10
|
|
19
19
|
* - SEQ-02: no time estimates
|
|
20
|
+
* - TPL-01: template files must not contain compile-time {{.var}} substitutions
|
|
20
21
|
*
|
|
21
22
|
* Usage:
|
|
22
23
|
* node tools/validate-skills.js # All skills, human-readable
|
|
@@ -43,6 +44,8 @@ const positionalArgs = args.filter((a) => !a.startsWith('--'));
|
|
|
43
44
|
const NAME_REGEX = /^bmad-[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
44
45
|
const STEP_FILENAME_REGEX = /^step-\d{2}[a-z]?-[a-z0-9-]+\.md$/;
|
|
45
46
|
const TIME_ESTIMATE_PATTERNS = [/takes?\s+\d+\s*min/i, /~\s*\d+\s*min/i, /estimated\s+time/i, /\bETA\b/];
|
|
47
|
+
const TEMPLATE_FILENAME_REGEX = /template/i;
|
|
48
|
+
const COMPILE_TIME_SUB_REGEX = /\{\{\.\w+\}\}/;
|
|
46
49
|
|
|
47
50
|
const SEVERITY_ORDER = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
|
|
48
51
|
|
|
@@ -535,6 +538,36 @@ function validateSkill(skillDir) {
|
|
|
535
538
|
}
|
|
536
539
|
}
|
|
537
540
|
|
|
541
|
+
// --- TPL-01: template files must not contain compile-time {{.var}} substitutions ---
|
|
542
|
+
// Template files seed durable, version-controlled artifacts (spec files) that
|
|
543
|
+
// execute on other machines. Baking a {{.var}} at render time would freeze a
|
|
544
|
+
// machine-local value into every downstream artifact.
|
|
545
|
+
for (const filePath of allFiles) {
|
|
546
|
+
if (path.extname(filePath) !== '.md') continue;
|
|
547
|
+
const base = path.basename(filePath);
|
|
548
|
+
if (!TEMPLATE_FILENAME_REGEX.test(base)) continue;
|
|
549
|
+
|
|
550
|
+
const relFile = path.relative(skillDir, filePath);
|
|
551
|
+
const content = safeReadFile(filePath, findings, relFile);
|
|
552
|
+
if (content === null) continue;
|
|
553
|
+
|
|
554
|
+
const lines = content.split('\n');
|
|
555
|
+
for (const [i, line] of lines.entries()) {
|
|
556
|
+
const match = line.match(COMPILE_TIME_SUB_REGEX);
|
|
557
|
+
if (match) {
|
|
558
|
+
findings.push({
|
|
559
|
+
rule: 'TPL-01',
|
|
560
|
+
title: 'Template files must not contain compile-time substitutions',
|
|
561
|
+
severity: 'HIGH',
|
|
562
|
+
file: relFile,
|
|
563
|
+
line: i + 1,
|
|
564
|
+
detail: `Template file contains compile-time substitution \`${match[0]}\` — this would be baked at render time and leak a machine-local value into every spec produced from the template.`,
|
|
565
|
+
fix: 'Remove the `{{.var}}` reference. Use single-curly `{var}` if the value should be resolved at LLM runtime by the consumer of the generated spec.',
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
538
571
|
return findings;
|
|
539
572
|
}
|
|
540
573
|
|