ma-agents 3.13.2 → 3.14.0

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.
Files changed (70) hide show
  1. package/lib/agents.js +7 -0
  2. package/lib/bmad-cache/bmb/.claude-plugin/marketplace.json +3 -3
  3. package/lib/bmad-cache/bmb/_git_preserved/index +0 -0
  4. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-b388526edf307cf56f8e65673466cff074105abf.idx +0 -0
  5. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/{pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.pack → pack-b388526edf307cf56f8e65673466cff074105abf.pack} +0 -0
  6. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-b388526edf307cf56f8e65673466cff074105abf.rev +0 -0
  7. package/lib/bmad-cache/bmb/_git_preserved/packed-refs +1 -1
  8. package/lib/bmad-cache/bmb/_git_preserved/refs/heads/main +1 -1
  9. package/lib/bmad-cache/bmb/_git_preserved/shallow +1 -1
  10. package/lib/bmad-cache/bmb/package-lock.json +2 -2
  11. package/lib/bmad-cache/bmb/package.json +1 -1
  12. package/lib/bmad-cache/bmb/samples/bmad-agent-code-coach/scripts/wake.py +78 -0
  13. package/lib/bmad-cache/bmb/samples/bmad-agent-creative-muse/scripts/wake.py +78 -0
  14. package/lib/bmad-cache/bmb/samples/bmad-agent-sentinel/scripts/wake.py +78 -0
  15. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/assets/customize-template.toml +3 -0
  16. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/assets/init-sanctum-template.py +11 -5
  17. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/assets/report-shell.html +1073 -0
  18. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/assets/wake-template.py +78 -0
  19. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/customize.toml +48 -0
  20. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/count_tokens.py +78 -0
  21. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/prepass.py +258 -0
  22. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/process-template.py +20 -0
  23. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/render_report.py +387 -0
  24. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/assets/adapter-claude-code.json +9 -0
  25. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/aggregate_benchmark.py +236 -0
  26. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/memlog.py +197 -0
  27. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/run_evals.py +513 -390
  28. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/run_triggers.py +347 -251
  29. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/tests/test_env_isolation.py +79 -0
  30. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/tests/test_trigger_detection.py +123 -0
  31. package/lib/bmad-cache/bmb/skills/bmad-module-builder/scripts/tests/test-validate-module.py +82 -4
  32. package/lib/bmad-cache/bmb/skills/bmad-module-builder/scripts/validate-module.py +55 -11
  33. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/assets/customize-template.toml +3 -5
  34. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/assets/report-shell.html +860 -0
  35. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/customize.toml +59 -0
  36. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/count_tokens.py +77 -0
  37. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/init_skill.py +132 -0
  38. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/prepass-prompt-metrics.py +186 -221
  39. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/quick_validate.py +117 -0
  40. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/render_report.py +387 -0
  41. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/tests/test_canon_sync.py +46 -0
  42. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/tests/test_count_tokens.py +180 -0
  43. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/tests/test_render_report.py +171 -0
  44. package/lib/bmad-cache/cache-manifest.json +4 -4
  45. package/lib/bmad-extension/.claude-plugin/marketplace.json.template +1 -1
  46. package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +2 -2
  47. package/lib/bmad.js +6 -1
  48. package/lib/templates/instruction-block-git.template.md +25 -25
  49. package/lib/templates/instruction-block-onprem.template.md +86 -86
  50. package/lib/templates/instruction-block-universal.template.md +29 -29
  51. package/package.json +3 -3
  52. package/lib/.bmad-extension-plugin.build-22612-1782454014750/.claude-plugin/marketplace.json +0 -109
  53. package/lib/.bmad-extension-plugin.build-22612-1782454014750/skills/module-help.csv +0 -62
  54. package/lib/.bmad-extension-plugin.build-22612-1782454014750/skills/module.yaml +0 -20
  55. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.idx +0 -0
  56. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.rev +0 -0
  57. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/references/sample-init-sanctum.py +0 -274
  58. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/generate-html-report.py +0 -534
  59. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/prepass-execution-deps.py +0 -337
  60. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/prepass-prompt-metrics.py +0 -425
  61. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/prepass-sanctum-architecture.py +0 -385
  62. package/lib/bmad-cache/bmb/skills/bmad-agent-builder/scripts/prepass-structure-capabilities.py +0 -482
  63. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/assets/Dockerfile +0 -29
  64. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/docker_setup.py +0 -115
  65. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/generate_report.py +0 -184
  66. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/pty_runner.py +0 -171
  67. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/utils.py +0 -260
  68. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/extract-report-json.py +0 -287
  69. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/generate-html-report.py +0 -588
  70. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/prepass-execution-deps.py +0 -288
@@ -0,0 +1,59 @@
1
+ # DO NOT EDIT -- overwritten on every update.
2
+ #
3
+ # Customization surface for bmad-workflow-builder. This governs how the builder
4
+ # builds: the org-wide context, standards, budgets, and gates applied to every
5
+ # skill it produces. It is distinct from the per-built-skill customize.toml the
6
+ # builder decides on during an individual build.
7
+ #
8
+ # Override files (not edited here):
9
+ # {project-root}/_bmad/custom/bmad-workflow-builder.toml (team)
10
+ # {project-root}/_bmad/custom/bmad-workflow-builder.user.toml (personal)
11
+
12
+ [workflow]
13
+
14
+ # --- Configurable below. Overrides merge per BMad structural rules: ---
15
+ # scalars: override wins • arrays: append
16
+
17
+ # Steps to run before standard activation (config load, greet).
18
+ # Use for org pre-flight loads or compliance checks.
19
+ activation_steps_prepend = []
20
+
21
+ # Steps to run after greet, before the build/analyze loop begins.
22
+ # Use for context-heavy setup once the user has been acknowledged.
23
+ activation_steps_append = []
24
+
25
+ # Standards the builder keeps in mind for the whole session, loaded as context
26
+ # into every build and analyze. Each entry is a literal sentence, a `skill:`
27
+ # skill, or a `file:` path/glob whose contents load as facts. Use for house
28
+ # conventions you want present but not hard-gated (for gates, see build_standards).
29
+ # "Name the output consumer in every skill's overview."
30
+ # "file:{project-root}/_bmad/standards/skill-house-style.md"
31
+ persistent_facts = ["file:{project-root}/**/project-context.md"]
32
+
33
+ # Executed when a build or analyze run completes, after the user has been told
34
+ # the artifact is ready. String scalar (one instruction) or array (in order).
35
+ on_complete = ""
36
+
37
+ # --- Builder gates and budgets ---
38
+
39
+ # Hard standards every BUILT skill must satisfy. Unlike persistent_facts
40
+ # (context), these are enforced: applied as build criteria and checked again as
41
+ # a conformance pass during Analyze. Each entry is a `skill:`, `file:`, or
42
+ # plain-text directive. Append-only. Empty by default (no org gates).
43
+ # "Every skill must ship at least one eval case."
44
+ # "skill:acme-co:security-review"
45
+ build_standards = []
46
+
47
+ # Eval requirement for a build to be declared done. Empty (default) keeps evals
48
+ # opt-in, offered at the eval beat but never forced. Set a directive to gate the
49
+ # build on evals and to flag their absence during Analyze:
50
+ # "baseline" -- require a passing baseline run (skill beats the bare model)
51
+ # "any" -- require at least one eval case to exist and pass
52
+ evals_required = ""
53
+
54
+ # SKILL.md token budget, measured via scripts/count_tokens.py (cl100k_base).
55
+ # Tiered: aim under _desired; between _desired and _budget warns the user; over
56
+ # _budget is a hard finding the builder resolves by progressive disclosure
57
+ # (lifting sections to references/ or assets/) until it is back under budget.
58
+ skill_md_token_desired = 2000
59
+ skill_md_token_budget = 3000
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.9"
4
+ # dependencies = ["tiktoken"]
5
+ # ///
6
+ """count_tokens — the single length metric for skill authoring.
7
+
8
+ Token counts replace line counts everywhere in the builder and eval-runner.
9
+ This script reports the token length of a file or of text piped on stdin, using
10
+ the tiktoken cl100k_base encoding. When tiktoken is not installed it falls back
11
+ to a character-based estimate (len(text) // 4) and says so, so the script always
12
+ runs under a bare python3 even with no third-party packages present.
13
+
14
+ Usage:
15
+ count_tokens.py <file> count the tokens in a file
16
+ count_tokens.py --stdin count the tokens read from stdin
17
+
18
+ Output (one line of JSON on stdout):
19
+ {"tokens": <int>, "method": "tiktoken"} when tiktoken loaded
20
+ {"tokens": <int>, "method": "fallback"} when it fell back to chars // 4
21
+
22
+ Budgets this feeds: SKILL.md ~1500-2500, multi-branch reference ~4500,
23
+ single-purpose reference ~9000.
24
+ """
25
+ import argparse
26
+ import json
27
+ import sys
28
+
29
+ ENCODING = "cl100k_base"
30
+
31
+
32
+ def count_tokens(text: str) -> tuple[int, str]:
33
+ """Return (token_count, method).
34
+
35
+ Tries tiktoken's cl100k_base encoding first. If tiktoken cannot be imported
36
+ or initialized, estimates with len(text) // 4 and reports method "fallback".
37
+ """
38
+ try:
39
+ import tiktoken
40
+ except Exception:
41
+ return len(text) // 4, "fallback"
42
+ try:
43
+ enc = tiktoken.get_encoding(ENCODING)
44
+ except Exception:
45
+ return len(text) // 4, "fallback"
46
+ return len(enc.encode(text)), "tiktoken"
47
+
48
+
49
+ def read_input(args) -> str:
50
+ if args.stdin:
51
+ return sys.stdin.read()
52
+ with open(args.file, encoding="utf-8") as f:
53
+ return f.read()
54
+
55
+
56
+ def main(argv: list[str] | None = None) -> int:
57
+ p = argparse.ArgumentParser(
58
+ description=__doc__,
59
+ formatter_class=argparse.RawDescriptionHelpFormatter,
60
+ )
61
+ p.add_argument("file", nargs="?", help="path to the file to count")
62
+ p.add_argument("--stdin", action="store_true", help="read text from stdin instead of a file")
63
+ args = p.parse_args(argv)
64
+
65
+ if not args.stdin and not args.file:
66
+ p.error("provide a file path or --stdin")
67
+ if args.stdin and args.file:
68
+ p.error("provide either a file path or --stdin, not both")
69
+
70
+ text = read_input(args)
71
+ tokens, method = count_tokens(text)
72
+ print(json.dumps({"tokens": tokens, "method": method}))
73
+ return 0
74
+
75
+
76
+ if __name__ == "__main__":
77
+ sys.exit(main())
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.9"
4
+ # ///
5
+ """init_skill — deterministic scaffolder for a new skill.
6
+
7
+ Creates the skill directory and writes SKILL.md from the builder's template, which
8
+ carries the embedded archetype guidance and the delete-when-done marker. The name
9
+ is normalized to hyphen-case and capped at 64 chars. Only the resource directories
10
+ the build flow asked for are stubbed, so the skill starts as small as it can. A
11
+ customize.toml is emitted only when customization was accepted, never by default.
12
+
13
+ This script does the mechanical scaffolding so the model spends its turns on the
14
+ content, not on mkdir and string substitution.
15
+
16
+ Usage:
17
+ init_skill.py --name "My New Skill" --dest /path/to/skills
18
+ init_skill.py --name foo --dest DIR --dirs references,scripts,assets
19
+ init_skill.py --name foo --dest DIR --customizable
20
+ init_skill.py --name foo --dest DIR \
21
+ --template /abs/SKILL-template.md --customize-template /abs/customize-template.toml
22
+
23
+ Output: one JSON object on stdout describing what was created.
24
+ Exit code 0 on success, 1 on failure (e.g. the target already exists).
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import argparse
29
+ import json
30
+ import re
31
+ import sys
32
+ from pathlib import Path
33
+
34
+ KNOWN_DIRS = ("references", "scripts", "assets", "agents")
35
+ SCRIPT_DIR = Path(__file__).resolve().parent
36
+ DEFAULT_TEMPLATE = SCRIPT_DIR.parent / "assets" / "SKILL-template.md"
37
+ DEFAULT_CUSTOMIZE = SCRIPT_DIR.parent / "assets" / "customize-template.toml"
38
+
39
+
40
+ def normalize_name(raw: str, max_len: int = 64) -> str:
41
+ """Lowercase, collapse non-alphanumerics to single hyphens, trim, cap at max_len."""
42
+ s = raw.strip().lower()
43
+ s = re.sub(r"[^a-z0-9]+", "-", s)
44
+ s = s.strip("-")
45
+ if len(s) > max_len:
46
+ s = s[:max_len].rstrip("-")
47
+ return s
48
+
49
+
50
+ def fill_template(template: str, skill_name: str) -> str:
51
+ return template.replace("{skill-name}", skill_name)
52
+
53
+
54
+ def scaffold(args) -> dict:
55
+ skill_name = normalize_name(args.name)
56
+ if not skill_name:
57
+ raise ValueError(f"name {args.name!r} normalized to an empty string")
58
+
59
+ skill_dir = Path(args.dest) / skill_name
60
+ if skill_dir.exists():
61
+ raise FileExistsError(f"{skill_dir} already exists")
62
+
63
+ template_path = Path(args.template) if args.template else DEFAULT_TEMPLATE
64
+ if not template_path.is_file():
65
+ raise FileNotFoundError(f"template not found: {template_path}")
66
+
67
+ requested = []
68
+ for d in (args.dirs or "").split(","):
69
+ d = d.strip()
70
+ if not d:
71
+ continue
72
+ if d not in KNOWN_DIRS:
73
+ raise ValueError(f"unknown resource dir {d!r}; known: {', '.join(KNOWN_DIRS)}")
74
+ requested.append(d)
75
+
76
+ skill_dir.mkdir(parents=True)
77
+ created = [str(skill_dir)]
78
+
79
+ skill_md = skill_dir / "SKILL.md"
80
+ skill_md.write_text(fill_template(template_path.read_text(encoding="utf-8"), skill_name), encoding="utf-8")
81
+ created.append(str(skill_md))
82
+
83
+ for d in requested:
84
+ sub = skill_dir / d
85
+ sub.mkdir()
86
+ created.append(str(sub))
87
+
88
+ customize_emitted = False
89
+ if args.customizable:
90
+ ct_path = Path(args.customize_template) if args.customize_template else DEFAULT_CUSTOMIZE
91
+ if not ct_path.is_file():
92
+ raise FileNotFoundError(f"customize template not found: {ct_path}")
93
+ target = skill_dir / "customize.toml"
94
+ target.write_text(
95
+ ct_path.read_text(encoding="utf-8").replace("{skill-name}", skill_name),
96
+ encoding="utf-8",
97
+ )
98
+ created.append(str(target))
99
+ customize_emitted = True
100
+
101
+ return {
102
+ "ok": True,
103
+ "skill_name": skill_name,
104
+ "skill_dir": str(skill_dir),
105
+ "dirs_stubbed": requested,
106
+ "customize_toml": customize_emitted,
107
+ "created": created,
108
+ }
109
+
110
+
111
+ def main(argv: list[str] | None = None) -> int:
112
+ p = argparse.ArgumentParser(description="Deterministic scaffolder for a new skill")
113
+ p.add_argument("--name", required=True, help="raw skill name; normalized to hyphen-case <=64")
114
+ p.add_argument("--dest", required=True, help="parent directory the skill folder is created under")
115
+ p.add_argument("--dirs", default="", help="comma-separated resource dirs to stub (references,scripts,assets,agents)")
116
+ p.add_argument("--customizable", action="store_true", help="emit customize.toml (only when customization was accepted)")
117
+ p.add_argument("--template", help="override path to the SKILL.md template")
118
+ p.add_argument("--customize-template", help="override path to the customize.toml template")
119
+ args = p.parse_args(argv)
120
+
121
+ try:
122
+ result = scaffold(args)
123
+ except (FileExistsError, FileNotFoundError, ValueError) as e:
124
+ print(json.dumps({"ok": False, "error": str(e)}))
125
+ return 1
126
+
127
+ print(json.dumps(result, indent=2))
128
+ return 0
129
+
130
+
131
+ if __name__ == "__main__":
132
+ sys.exit(main())