ma-agents 3.12.2 → 3.13.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.
- package/bin/cli.js +11 -6
- package/docs/architecture.md +18 -0
- package/lib/bmad-cache/bmb/.claude-plugin/marketplace.json +1 -1
- package/lib/bmad-cache/bmb/_git_preserved/hooks/commit-msg.sample +52 -2
- package/lib/bmad-cache/bmb/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
- package/lib/bmad-cache/bmb/_git_preserved/index +0 -0
- package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.idx +0 -0
- package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.pack +0 -0
- package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.rev +0 -0
- package/lib/bmad-cache/bmb/_git_preserved/packed-refs +1 -1
- package/lib/bmad-cache/bmb/_git_preserved/refs/heads/main +1 -1
- package/lib/bmad-cache/bmb/_git_preserved/shallow +1 -1
- package/lib/bmad-cache/bmb/package-lock.json +2 -2
- package/lib/bmad-cache/bmb/package.json +1 -1
- package/lib/bmad-cache/bmb/samples/bmad-agent-dream-weaver/assets/module-help.csv +1 -1
- package/lib/bmad-cache/bmb/samples/bmad-agent-dream-weaver/scripts/merge-config.py +33 -0
- package/lib/bmad-cache/bmb/samples/bmad-agent-dream-weaver/scripts/merge-help-csv.py +28 -0
- package/lib/bmad-cache/bmb/samples/sample-module-setup/assets/module-help.csv +1 -1
- package/lib/bmad-cache/bmb/samples/sample-module-setup/scripts/cleanup-legacy.py +28 -0
- package/lib/bmad-cache/bmb/samples/sample-module-setup/scripts/merge-config.py +33 -0
- package/lib/bmad-cache/bmb/samples/sample-module-setup/scripts/merge-help-csv.py +28 -0
- package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/assets/module-help.csv +1 -1
- package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/scripts/cleanup-legacy.py +28 -0
- package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/scripts/merge-config.py +33 -0
- package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/scripts/merge-help-csv.py +28 -0
- package/lib/bmad-cache/bmb/skills/bmad-eval-runner/assets/Dockerfile +29 -0
- package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/docker_setup.py +115 -0
- package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/generate_report.py +184 -0
- package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/pty_runner.py +171 -0
- package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/run_evals.py +492 -0
- package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/run_triggers.py +366 -0
- package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/utils.py +260 -0
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/assets/module-help.csv +1 -1
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/scripts/cleanup-legacy.py +28 -0
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/scripts/merge-config.py +33 -0
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/scripts/merge-help-csv.py +28 -0
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/standalone-module-template/merge-config.py +33 -0
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/standalone-module-template/merge-help-csv.py +28 -0
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/scripts/tests/test-validate-module.py +74 -1
- package/lib/bmad-cache/bmb/skills/bmad-module-builder/scripts/validate-module.py +24 -13
- package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/assets/sample-customize-product-brief.toml +48 -33
- package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/extract-report-json.py +287 -0
- package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/generate-html-report.py +57 -8
- package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/prepass-prompt-metrics.py +7 -7
- package/lib/bmad-cache/bmb/skills/module-help.csv +1 -1
- package/lib/bmad-cache/bmb/website/public/img/eval-test-types.png +0 -0
- package/lib/bmad-cache/cache-manifest.json +17 -18
- package/lib/bmad-cache/cis/_git_preserved/hooks/commit-msg.sample +52 -2
- package/lib/bmad-cache/cis/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
- package/lib/bmad-cache/cis/_git_preserved/index +0 -0
- package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-18c8290560a98bcb7bf0676e6cc9b2ac5ca2823e.idx +0 -0
- package/lib/bmad-cache/cis/_git_preserved/objects/pack/{pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.pack → pack-18c8290560a98bcb7bf0676e6cc9b2ac5ca2823e.pack} +0 -0
- package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-18c8290560a98bcb7bf0676e6cc9b2ac5ca2823e.rev +0 -0
- package/lib/bmad-cache/cis/_git_preserved/packed-refs +1 -1
- package/lib/bmad-cache/cis/_git_preserved/refs/heads/main +1 -1
- package/lib/bmad-cache/cis/_git_preserved/refs/tags/v0.2.1 +1 -0
- package/lib/bmad-cache/cis/_git_preserved/shallow +1 -1
- package/lib/bmad-cache/cis/package-lock.json +2 -2
- package/lib/bmad-cache/cis/package.json +1 -1
- package/lib/bmad-cache/cis/src/module-help.csv +1 -1
- package/lib/bmad-cache/gds/.claude-plugin/marketplace.json +4 -7
- package/lib/bmad-cache/gds/README.md +3 -1
- package/lib/bmad-cache/gds/_git_preserved/hooks/commit-msg.sample +52 -2
- package/lib/bmad-cache/gds/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
- package/lib/bmad-cache/gds/_git_preserved/index +0 -0
- package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-dcb7c556d9bb6b6b70d2301e094eaac6d7300552.idx +0 -0
- package/lib/bmad-cache/gds/_git_preserved/objects/pack/{pack-9427a146a90c00bb542cba038874bf9671ba4dc0.pack → pack-dcb7c556d9bb6b6b70d2301e094eaac6d7300552.pack} +0 -0
- package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-dcb7c556d9bb6b6b70d2301e094eaac6d7300552.rev +0 -0
- package/lib/bmad-cache/gds/_git_preserved/packed-refs +1 -1
- package/lib/bmad-cache/gds/_git_preserved/refs/heads/main +1 -1
- package/lib/bmad-cache/gds/_git_preserved/shallow +1 -1
- package/lib/bmad-cache/gds/package.json +1 -1
- package/lib/bmad-cache/gds/src/agents/gds-agent-game-designer/customize.toml +5 -5
- package/lib/bmad-cache/gds/src/agents/gds-agent-game-dev/customize.toml +5 -5
- package/lib/bmad-cache/gds/src/agents/gds-agent-game-solo-dev/customize.toml +0 -5
- package/lib/bmad-cache/gds/src/module-help.csv +6 -12
- package/lib/bmad-cache/gds/src/module.yaml +1 -1
- package/lib/bmad-cache/gds/src/workflows/1-preproduction/gds-create-game-brief/customize.toml +97 -22
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-gdd/assets/validation-report-template.html +190 -0
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-gdd/customize.toml +99 -0
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-gdd/scripts/render-validation-html.py +290 -0
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-prd/assets/validation-report-template.html +190 -0
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-prd/customize.toml +84 -0
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-ux/assets/validation-report-template.html +319 -0
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-ux/customize.toml +101 -0
- package/lib/bmad-cache/gds/src/workflows/3-technical/gds-game-architecture/architecture-patterns.yaml +1 -0
- package/lib/bmad-cache/gds/src/workflows/3-technical/gds-game-architecture/decision-catalog.yaml +88 -0
- package/lib/bmad-cache/gds/src/workflows/3-technical/gds-game-architecture/engine-mcps.yaml +124 -2
- package/lib/bmad-cache/gds/src/workflows/4-production/gds-investigate/customize.toml +62 -0
- package/lib/bmad-cache/tea/.claude-plugin/marketplace.json +1 -1
- package/lib/bmad-cache/tea/.github/workflows/docs.yaml +3 -3
- package/lib/bmad-cache/tea/.github/workflows/quality.yaml +10 -10
- package/lib/bmad-cache/tea/AGENTS.md +31 -0
- package/lib/bmad-cache/tea/CHANGELOG.md +42 -1
- package/lib/bmad-cache/tea/README.md +8 -5
- package/lib/bmad-cache/tea/_git_preserved/hooks/commit-msg.sample +52 -2
- package/lib/bmad-cache/tea/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
- package/lib/bmad-cache/tea/_git_preserved/index +0 -0
- package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-9e4197e37df7763dd7a05c2965ee921dfd2eb617.idx +0 -0
- package/lib/bmad-cache/tea/_git_preserved/objects/pack/{pack-f0df537f2649464ff6c5aee241165eb9c8664227.pack → pack-9e4197e37df7763dd7a05c2965ee921dfd2eb617.pack} +0 -0
- package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-9e4197e37df7763dd7a05c2965ee921dfd2eb617.rev +0 -0
- package/lib/bmad-cache/tea/_git_preserved/packed-refs +1 -1
- package/lib/bmad-cache/tea/_git_preserved/refs/heads/main +1 -1
- package/lib/bmad-cache/tea/_git_preserved/refs/tags/v1.19.0 +1 -0
- package/lib/bmad-cache/tea/_git_preserved/shallow +1 -1
- package/lib/bmad-cache/tea/docs/explanation/engagement-models.md +15 -16
- package/lib/bmad-cache/tea/docs/explanation/knowledge-base-system.md +2 -0
- package/lib/bmad-cache/tea/docs/explanation/risk-based-testing.md +1 -1
- package/lib/bmad-cache/tea/docs/explanation/tea-overview.md +88 -52
- package/lib/bmad-cache/tea/docs/explanation/testing-as-engineering.md +13 -12
- package/lib/bmad-cache/tea/docs/glossary/index.md +2 -2
- package/lib/bmad-cache/tea/docs/how-to/brownfield/use-tea-for-enterprise.md +19 -18
- package/lib/bmad-cache/tea/docs/how-to/brownfield/use-tea-with-existing-tests.md +1 -1
- package/lib/bmad-cache/tea/docs/how-to/workflows/run-nfr-assess.md +32 -26
- package/lib/bmad-cache/tea/docs/how-to/workflows/run-test-design.md +20 -14
- package/lib/bmad-cache/tea/docs/how-to/workflows/run-trace.md +3 -3
- package/lib/bmad-cache/tea/docs/index.md +13 -11
- package/lib/bmad-cache/tea/docs/reference/commands.md +37 -13
- package/lib/bmad-cache/tea/docs/reference/knowledge-base.md +2 -2
- package/lib/bmad-cache/tea/package-lock.json +2 -2
- package/lib/bmad-cache/tea/package.json +1 -1
- package/lib/bmad-cache/tea/src/agents/bmad-tea/customize.toml +20 -15
- package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/confidence-gate.md +73 -0
- package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/test-quality.md +1 -0
- package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/tea-index.csv +2 -1
- package/lib/bmad-cache/tea/src/module-help.csv +2 -2
- package/lib/bmad-cache/tea/src/workflows/testarch/README.md +5 -4
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/data/role-paths.yaml +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/data/tea-resources-index.yaml +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/steps-c/step-04-session-01.md +2 -2
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/steps-c/step-04-session-07.md +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/templates/certificate-template.md +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-atdd/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-automate/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-ci/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-framework/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/SKILL.md +3 -3
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/checklist.md +11 -11
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/instructions.md +4 -2
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/nfr-report-template.md +5 -5
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-01-load-context.md +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-01b-resume.md +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-02-define-thresholds.md +14 -3
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04-evaluate-and-score.md +7 -7
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04a-subagent-security.md +4 -4
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04b-subagent-performance.md +4 -4
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04c-subagent-reliability.md +4 -4
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04d-subagent-scalability.md +4 -4
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04e-aggregate-nfr.md +4 -4
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-05-generate-report.md +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/workflow-plan.md +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/workflow.yaml +3 -3
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/checklist.md +23 -3
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-02-load-context.md +7 -0
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-03-risk-and-testability.md +16 -2
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-04-coverage-plan.md +20 -4
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-05-generate-output.md +2 -0
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/test-design-architecture-template.md +17 -0
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/test-design-qa-template.md +15 -0
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/test-design-template.md +16 -0
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-review/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-trace/checklist.md +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-trace/resources/tea-index.csv +1 -1
- package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-trace/trace-template.md +1 -1
- package/lib/bmad-cache/tea/test/test-installation-components.js +49 -0
- package/lib/bmad-cache/tea/website/astro.config.mjs +2 -2
- package/lib/bmad-cache/wds/README.md +1 -1
- package/lib/bmad-cache/wds/_git_preserved/hooks/commit-msg.sample +52 -2
- package/lib/bmad-cache/wds/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
- package/lib/bmad-cache/wds/_git_preserved/index +0 -0
- package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-656c3d8d5426e73043b6a7f45eedaab74e3c419e.idx +0 -0
- package/lib/bmad-cache/wds/_git_preserved/objects/pack/{pack-96877c1c09123cccb1f91c1412184b11d2b492ad.pack → pack-656c3d8d5426e73043b6a7f45eedaab74e3c419e.pack} +0 -0
- package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-656c3d8d5426e73043b6a7f45eedaab74e3c419e.rev +0 -0
- package/lib/bmad-cache/wds/_git_preserved/packed-refs +1 -1
- package/lib/bmad-cache/wds/_git_preserved/refs/heads/main +1 -1
- package/lib/bmad-cache/wds/_git_preserved/refs/tags/v0.4.3 +1 -0
- package/lib/bmad-cache/wds/_git_preserved/shallow +1 -1
- package/lib/bmad-cache/wds/eslint.config.mjs +1 -1
- package/lib/bmad-cache/wds/package.json +1 -1
- package/lib/bmad-cache/wds/src/agents/wds-agent-freya-ux/customize.toml +80 -0
- package/lib/bmad-cache/wds/src/agents/wds-agent-mimir-builder/customize.toml +52 -0
- package/lib/bmad-cache/wds/src/agents/wds-agent-saga-analyst/customize.toml +70 -0
- package/lib/bmad-cache/wds/src/module-help.csv +19 -19
- package/lib/bmad-cache/wds/src/module.yaml +28 -0
- package/lib/bmad-cache/wds/src/scripts/README.md +155 -0
- package/lib/bmad-cache/wds/src/scripts/wds-add-object.js +202 -0
- package/lib/bmad-cache/wds/src/scripts/wds-add-spacing.js +158 -0
- package/lib/bmad-cache/wds/src/scripts/wds-init-page.js +229 -0
- package/lib/bmad-cache/wds/src/scripts/wds-init-scenario.js +120 -0
- package/lib/bmad-cache/wds/src/scripts/wds-nav.js +201 -0
- package/lib/bmad-cache/wds/src/scripts/wds-validate.js +301 -0
- package/lib/bmad-cache/wds/src/workflows/wds-3-scenarios/workflow.xml +450 -0
- package/lib/bmad-cache/wds/src/workflows/wds-4-ux-design/workflow-specify.xml +387 -0
- package/lib/bmad-extension/.claude-plugin/marketplace.json.template +1 -1
- package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +2 -2
- package/lib/bmad.js +91 -7
- package/lib/installer.js +28 -6
- package/lib/mil498-templates/OCD.md +169 -169
- package/lib/mil498-templates/README.md +4 -4
- package/lib/mil498-templates/SDD.md +163 -163
- package/lib/mil498-templates/SDP.md +307 -307
- package/lib/mil498-templates/SRS.md +219 -219
- package/lib/mil498-templates/SSDD.md +154 -154
- package/lib/mil498-templates/SSS.md +225 -225
- package/lib/mil498-templates/STD.md +188 -188
- package/lib/templates/instruction-block-git.template.md +25 -0
- package/package.json +5 -4
- package/scripts/build-bmad-cache.js +143 -42
- package/skills/git-workflow-skill/skill.json +21 -21
- package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-6ecd9fc6445b1281449c5ec49a6c5794708e662e.idx +0 -0
- package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-6ecd9fc6445b1281449c5ec49a6c5794708e662e.pack +0 -0
- package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-6ecd9fc6445b1281449c5ec49a6c5794708e662e.rev +0 -0
- package/lib/bmad-cache/bmb/_git_preserved/refs/remotes/origin/HEAD +0 -1
- package/lib/bmad-cache/bmb/_git_preserved/refs/tags/v1.7.0 +0 -1
- package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/generate-convert-report.py +0 -406
- package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/tests/test_generate_convert_report.py +0 -243
- package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.idx +0 -0
- package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.rev +0 -0
- package/lib/bmad-cache/cis/_git_preserved/refs/remotes/origin/HEAD +0 -1
- package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-9427a146a90c00bb542cba038874bf9671ba4dc0.idx +0 -0
- package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-9427a146a90c00bb542cba038874bf9671ba4dc0.rev +0 -0
- package/lib/bmad-cache/gds/_git_preserved/refs/remotes/origin/HEAD +0 -1
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-gdd/customize.toml +0 -41
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-prd/customize.toml +0 -41
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-prd/data/domain-complexity.csv +0 -15
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-prd/data/project-types.csv +0 -11
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-ux-design/customize.toml +0 -41
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-edit-gdd/customize.toml +0 -41
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-edit-prd/customize.toml +0 -41
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-gdd/customize.toml +0 -41
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-prd/customize.toml +0 -41
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-prd/data/domain-complexity.csv +0 -15
- package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-prd/data/project-types.csv +0 -11
- package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-f0df537f2649464ff6c5aee241165eb9c8664227.idx +0 -0
- package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-f0df537f2649464ff6c5aee241165eb9c8664227.rev +0 -0
- package/lib/bmad-cache/tea/_git_preserved/refs/remotes/origin/HEAD +0 -1
- package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-96877c1c09123cccb1f91c1412184b11d2b492ad.idx +0 -0
- package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-96877c1c09123cccb1f91c1412184b11d2b492ad.rev +0 -0
- package/lib/bmad-cache/wds/_git_preserved/refs/remotes/origin/HEAD +0 -1
- package/lib/bmad-cache/wds/src/agents/wds-agent-freya-ux/bmad-skill-manifest.yaml +0 -12
- package/lib/bmad-cache/wds/src/agents/wds-agent-saga-analyst/bmad-skill-manifest.yaml +0 -12
- package/lib/bmad-cache/wds/src/workflows/wds-0-alignment-signoff/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-0-project-setup/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-1-project-brief/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-2-trigger-mapping/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-3-scenarios/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-4-ux-design/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-5-agentic-development/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-6-asset-generation/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-7-design-system/bmad-skill-manifest.yaml +0 -1
- package/lib/bmad-cache/wds/src/workflows/wds-8-product-evolution/bmad-skill-manifest.yaml +0 -1
- /package/lib/bmad-cache/gds/src/workflows/2-design/{gds-create-gdd → gds-gdd/assets}/game-types.csv +0 -0
- /package/lib/bmad-cache/gds/src/workflows/2-design/{gds-validate-gdd/data → gds-gdd/assets}/genre-complexity.csv +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# DO NOT EDIT -- overwritten on every update.
|
|
2
|
+
#
|
|
3
|
+
# Workflow customization surface for gds-gdd.
|
|
4
|
+
#
|
|
5
|
+
# Override files (not edited here):
|
|
6
|
+
# {project-root}/_bmad/custom/gds-gdd.toml (team)
|
|
7
|
+
# {project-root}/_bmad/custom/gds-gdd.user.toml (personal)
|
|
8
|
+
|
|
9
|
+
[workflow]
|
|
10
|
+
|
|
11
|
+
# --- Configurable below. Overrides merge per BMad structural rules: ---
|
|
12
|
+
# scalars: override wins • arrays: append
|
|
13
|
+
|
|
14
|
+
# Steps to run before the standard activation (config load, greet).
|
|
15
|
+
# Use for pre-flight loads, compliance checks, etc.
|
|
16
|
+
activation_steps_prepend = []
|
|
17
|
+
|
|
18
|
+
# Steps to run after greet but before the workflow begins.
|
|
19
|
+
# Use for context-heavy setup that should happen once the user has been acknowledged.
|
|
20
|
+
activation_steps_append = []
|
|
21
|
+
|
|
22
|
+
# Persistent facts the workflow keeps in mind for the whole run
|
|
23
|
+
# (standards, compliance constraints, stylistic guardrails).
|
|
24
|
+
# Each entry is either a literal sentence, a skill prefixed with `skill:`, or a `file:`-prefixed
|
|
25
|
+
# path/glob whose contents are loaded as facts.
|
|
26
|
+
#
|
|
27
|
+
# Default loads project-context.md if gds-generate-project-context has produced one — this gives
|
|
28
|
+
# the facilitator persistent awareness of the project's tech, domain, and constraints without
|
|
29
|
+
# re-asking. Common opt-ins (set in team/user override TOML):
|
|
30
|
+
# "skill:acme-studio:house-game-pillars" # a skill that contains relevant info
|
|
31
|
+
# "Every mechanic in the GDD must trace back to a documented pillar." # generic agent instruction
|
|
32
|
+
persistent_facts = [
|
|
33
|
+
"file:{project-root}/**/project-context.md",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
# Executed when the workflow completes (after the user has been told the
|
|
37
|
+
# GDD is ready). Accepts either a string scalar (single instruction)
|
|
38
|
+
# or an array of instructions executed in order. Empty for none.
|
|
39
|
+
on_complete = ""
|
|
40
|
+
|
|
41
|
+
# Default GDD structure. Treated as a starting point — the LLM adapts it
|
|
42
|
+
# to the game type and project scope. The {{GAME_TYPE_SPECIFIC_SECTIONS}}
|
|
43
|
+
# slot is filled from the matched genre guide. Override the path in
|
|
44
|
+
# team/user TOML to enforce a different structure (e.g. studio-standard GDD).
|
|
45
|
+
gdd_template = "assets/gdd-template.md"
|
|
46
|
+
|
|
47
|
+
# Validation checklist used at the Validate intent and at Finalize step 3.
|
|
48
|
+
# A subagent walks the checklist against gdd.md and returns structured findings.
|
|
49
|
+
# The genre and game-type checks read game_types_csv and genre_complexity_csv.
|
|
50
|
+
# Override the path in team/user TOML to enforce a studio-specific checklist.
|
|
51
|
+
validation_checklist = "assets/gdd-validation-checklist.md"
|
|
52
|
+
|
|
53
|
+
# HTML template used to render validation findings into a styled, scannable
|
|
54
|
+
# report. The renderer (scripts/render-validation-html.py) substitutes
|
|
55
|
+
# structured findings + summary stats into this template; the template is
|
|
56
|
+
# fully overridable to match studio branding. The default uses inline CSS, no
|
|
57
|
+
# external dependencies, and native HTML <details> for collapse — no JS.
|
|
58
|
+
validation_report_template = "assets/validation-report-template.html"
|
|
59
|
+
|
|
60
|
+
# Game-type taxonomy. Drives game-type detection during Discovery and the
|
|
61
|
+
# game-type cross-reference check during Validate. Columns: id, name,
|
|
62
|
+
# description, genre_tags, fragment_file. Each fragment_file names a genre
|
|
63
|
+
# guide under assets/game-types/ that scaffolds the GameType Specific Design
|
|
64
|
+
# section. Override the path in team/user TOML to extend the taxonomy.
|
|
65
|
+
game_types_csv = "assets/game-types.csv"
|
|
66
|
+
|
|
67
|
+
# Genre-complexity ratings. Drives the genre-compliance check during Validate
|
|
68
|
+
# and tells Discovery which genres carry must-document conventions. Columns:
|
|
69
|
+
# genre, signals, complexity, key_concerns, required_knowledge,
|
|
70
|
+
# suggested_workflow, special_sections.
|
|
71
|
+
genre_complexity_csv = "assets/genre-complexity.csv"
|
|
72
|
+
|
|
73
|
+
# Run folder location. The GDD, epics file, decision log, and optional
|
|
74
|
+
# validation report all land inside `{output_dir}/{output_folder_name}/`.
|
|
75
|
+
output_dir = "{planning_artifacts}/gdds"
|
|
76
|
+
output_folder_name = "gdd-{project_name}-{date}"
|
|
77
|
+
|
|
78
|
+
# Document standards applied to human-consumed docs at Finalize. Each entry is
|
|
79
|
+
# a `skill:`, `file:`, or plain-text directive; the parent LLM applies the
|
|
80
|
+
# findings before the user sees the draft. Empty by default — Game Dev Studio
|
|
81
|
+
# ships no editorial-review skills. Add your own in team/user override TOML:
|
|
82
|
+
# "skill:my-studio:editorial-review-prose"
|
|
83
|
+
# "file:{project-root}/_bmad/style-guides/studio-voice.md"
|
|
84
|
+
# "Convert all dates to ISO 8601 format."
|
|
85
|
+
doc_standards = []
|
|
86
|
+
|
|
87
|
+
# External-source registry. Natural-language directives describing knowledge
|
|
88
|
+
# bases, MCP tools, or internal systems the LLM may consult during the workflow
|
|
89
|
+
# when a relevant need surfaces. The LLM does NOT query these preemptively —
|
|
90
|
+
# it consults them on demand. If a named MCP tool is unavailable at runtime,
|
|
91
|
+
# the LLM falls back to standard behavior and notes the gap. Empty by default.
|
|
92
|
+
external_sources = []
|
|
93
|
+
|
|
94
|
+
# External-handoff routing. Natural-language directives the LLM applies at
|
|
95
|
+
# Finalize to route outputs beyond local files (Confluence, Notion, Google
|
|
96
|
+
# Drive, ticket systems, etc.). Handoffs run after the artifact is polished
|
|
97
|
+
# and before the final user-facing message. URLs or IDs returned by the
|
|
98
|
+
# destination are captured and surfaced to the user. Empty by default.
|
|
99
|
+
external_handoffs = []
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.10"
|
|
4
|
+
# ///
|
|
5
|
+
"""Render a PRD validation findings JSON into HTML + markdown reports.
|
|
6
|
+
|
|
7
|
+
Reads structured findings produced by the validator subagent, groups them by
|
|
8
|
+
category (explicit `category` field, else derived from ID prefix), computes a
|
|
9
|
+
pass/warn/fail summary and grade, substitutes into the configured HTML
|
|
10
|
+
template, writes a markdown companion at the same path with `.md` extension,
|
|
11
|
+
and optionally opens the HTML in the default browser.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import html
|
|
16
|
+
import json
|
|
17
|
+
import string
|
|
18
|
+
import sys
|
|
19
|
+
import webbrowser
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
CATEGORY_FROM_PREFIX = {
|
|
24
|
+
"Q": "Quality",
|
|
25
|
+
"D": "Discipline",
|
|
26
|
+
"S": "Structural integrity",
|
|
27
|
+
"STK": "Stakes-gated",
|
|
28
|
+
"M": "Mechanical",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
CATEGORY_ORDER = ["Quality", "Discipline", "Structural integrity", "Stakes-gated", "Mechanical"]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def category_for(finding: dict) -> str:
|
|
35
|
+
explicit = finding.get("category")
|
|
36
|
+
if explicit:
|
|
37
|
+
return explicit
|
|
38
|
+
fid = finding.get("id", "")
|
|
39
|
+
prefix = fid.split("-", 1)[0] if "-" in fid else fid
|
|
40
|
+
return CATEGORY_FROM_PREFIX.get(prefix, prefix or "Other")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def compute_stats(findings: list[dict]) -> dict:
|
|
44
|
+
total = len(findings)
|
|
45
|
+
by_status = {"pass": 0, "warn": 0, "fail": 0, "n/a": 0}
|
|
46
|
+
failed_critical = 0
|
|
47
|
+
failed_high = 0
|
|
48
|
+
for f in findings:
|
|
49
|
+
status = (f.get("status") or "n/a").lower()
|
|
50
|
+
if status in by_status:
|
|
51
|
+
by_status[status] += 1
|
|
52
|
+
if status == "fail":
|
|
53
|
+
sev = (f.get("severity") or "low").lower()
|
|
54
|
+
if sev == "critical":
|
|
55
|
+
failed_critical += 1
|
|
56
|
+
elif sev == "high":
|
|
57
|
+
failed_high += 1
|
|
58
|
+
return {
|
|
59
|
+
"total": total,
|
|
60
|
+
"passed": by_status["pass"],
|
|
61
|
+
"warned": by_status["warn"],
|
|
62
|
+
"failed": by_status["fail"],
|
|
63
|
+
"na": by_status["n/a"],
|
|
64
|
+
"failed_critical": failed_critical,
|
|
65
|
+
"failed_high": failed_high,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def grade_from(stats: dict) -> tuple[str, str]:
|
|
70
|
+
if stats["failed_critical"] > 0:
|
|
71
|
+
return "Poor", "grade-poor"
|
|
72
|
+
if stats["failed_high"] >= 1 or stats["failed"] >= 4:
|
|
73
|
+
return "Fair", "grade-fair"
|
|
74
|
+
if stats["failed"] > 0 or stats["warned"] > 2:
|
|
75
|
+
return "Good", "grade-good"
|
|
76
|
+
return "Excellent", "grade-excellent"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def render_score_bar(stats: dict, width: int = 480, height: int = 22) -> str:
|
|
80
|
+
total = max(stats["total"], 1)
|
|
81
|
+
p = stats["passed"] / total * width
|
|
82
|
+
w = stats["warned"] / total * width
|
|
83
|
+
f = stats["failed"] / total * width
|
|
84
|
+
n = stats["na"] / total * width
|
|
85
|
+
return (
|
|
86
|
+
f'<svg width="{width}" height="{height}" viewBox="0 0 {width} {height}" role="img" '
|
|
87
|
+
f'aria-label="Pass / warn / fail / n-a breakdown">'
|
|
88
|
+
f'<rect x="0" y="0" width="{p:.1f}" height="{height}" fill="#22c55e"/>'
|
|
89
|
+
f'<rect x="{p:.1f}" y="0" width="{w:.1f}" height="{height}" fill="#eab308"/>'
|
|
90
|
+
f'<rect x="{p + w:.1f}" y="0" width="{f:.1f}" height="{height}" fill="#ef4444"/>'
|
|
91
|
+
f'<rect x="{p + w + f:.1f}" y="0" width="{n:.1f}" height="{height}" fill="#94a3b8"/>'
|
|
92
|
+
f"</svg>"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def render_finding(f: dict) -> str:
|
|
97
|
+
status = (f.get("status") or "n/a").lower()
|
|
98
|
+
severity = (f.get("severity") or "low").lower()
|
|
99
|
+
fid = html.escape(f.get("id") or "")
|
|
100
|
+
title = html.escape(f.get("title") or fid)
|
|
101
|
+
location = html.escape(f.get("location") or "")
|
|
102
|
+
note = html.escape(f.get("note") or "")
|
|
103
|
+
fix = html.escape(f.get("suggested_fix") or "")
|
|
104
|
+
|
|
105
|
+
status_class = "na" if status == "n/a" else status
|
|
106
|
+
parts = [
|
|
107
|
+
f'<article class="finding finding-{status_class}">',
|
|
108
|
+
'<header>',
|
|
109
|
+
f'<span class="badge badge-status badge-{status_class}">{status.upper()}</span>',
|
|
110
|
+
f'<span class="badge badge-severity badge-sev-{severity}">{severity}</span>',
|
|
111
|
+
f'<span class="finding-id">{fid}</span>',
|
|
112
|
+
f'<h3 class="finding-title">{title}</h3>',
|
|
113
|
+
'</header>',
|
|
114
|
+
]
|
|
115
|
+
if location:
|
|
116
|
+
parts.append(f'<div class="finding-location"><strong>Location:</strong> {location}</div>')
|
|
117
|
+
if note:
|
|
118
|
+
parts.append(f'<div class="finding-note">{note}</div>')
|
|
119
|
+
if fix:
|
|
120
|
+
parts.append(f'<div class="finding-fix"><strong>Suggested fix:</strong> {fix}</div>')
|
|
121
|
+
parts.append("</article>")
|
|
122
|
+
return "\n".join(parts)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def render_category(name: str, findings: list[dict]) -> str:
|
|
126
|
+
items = "\n".join(render_finding(f) for f in findings)
|
|
127
|
+
name_e = html.escape(name)
|
|
128
|
+
return (
|
|
129
|
+
f'<section class="category">'
|
|
130
|
+
f"<details open>"
|
|
131
|
+
f'<summary><h2>{name_e} <span class="count">({len(findings)})</span></h2></summary>'
|
|
132
|
+
f"{items}"
|
|
133
|
+
f"</details>"
|
|
134
|
+
f"</section>"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
SEVERITY_ORDER = ["critical", "high", "medium", "low"]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def render_finding_md(f: dict) -> str:
|
|
142
|
+
status = (f.get("status") or "n/a").upper()
|
|
143
|
+
severity = (f.get("severity") or "low").lower()
|
|
144
|
+
fid = f.get("id") or ""
|
|
145
|
+
title = f.get("title") or fid
|
|
146
|
+
location = f.get("location") or ""
|
|
147
|
+
note = f.get("note") or ""
|
|
148
|
+
fix = f.get("suggested_fix") or ""
|
|
149
|
+
|
|
150
|
+
lines = [f"### [{status}] {fid} — {title} _(severity: {severity})_"]
|
|
151
|
+
if location:
|
|
152
|
+
lines.append(f"- **Location:** {location}")
|
|
153
|
+
if note:
|
|
154
|
+
lines.append(f"- **Finding:** {note}")
|
|
155
|
+
if fix:
|
|
156
|
+
lines.append(f"- **Suggested fix:** {fix}")
|
|
157
|
+
return "\n".join(lines)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def render_markdown_report(data: dict, findings: list[dict], stats: dict, grade: str) -> str:
|
|
161
|
+
prd_name = data.get("prd_name") or "PRD"
|
|
162
|
+
prd_path = data.get("prd_path") or ""
|
|
163
|
+
checklist_path = data.get("checklist_path") or ""
|
|
164
|
+
timestamp = data.get("timestamp") or datetime.now().isoformat(timespec="seconds")
|
|
165
|
+
synthesis = data.get("overall_synthesis") or ""
|
|
166
|
+
|
|
167
|
+
out = [
|
|
168
|
+
f"# Validation Report — {prd_name}",
|
|
169
|
+
"",
|
|
170
|
+
f"- **PRD:** `{prd_path}`",
|
|
171
|
+
f"- **Checklist:** `{checklist_path}`",
|
|
172
|
+
f"- **Run at:** {timestamp}",
|
|
173
|
+
f"- **Grade:** {grade}",
|
|
174
|
+
"",
|
|
175
|
+
f"**Summary:** {stats['passed']} pass · {stats['warned']} warn · {stats['failed']} fail · {stats['na']} n/a "
|
|
176
|
+
f"(total {stats['total']}; critical fails: {stats['failed_critical']}, high fails: {stats['failed_high']})",
|
|
177
|
+
]
|
|
178
|
+
if synthesis:
|
|
179
|
+
out += ["", "## Overall synthesis", "", synthesis]
|
|
180
|
+
|
|
181
|
+
# Group by severity then status: failed criticals first, then highs, etc.
|
|
182
|
+
by_sev: dict[str, list[dict]] = {s: [] for s in SEVERITY_ORDER}
|
|
183
|
+
other: list[dict] = []
|
|
184
|
+
for f in findings:
|
|
185
|
+
sev = (f.get("severity") or "low").lower()
|
|
186
|
+
if sev in by_sev:
|
|
187
|
+
by_sev[sev].append(f)
|
|
188
|
+
else:
|
|
189
|
+
other.append(f)
|
|
190
|
+
|
|
191
|
+
out += ["", "## Findings by severity"]
|
|
192
|
+
any_findings = False
|
|
193
|
+
for sev in SEVERITY_ORDER:
|
|
194
|
+
items = by_sev[sev]
|
|
195
|
+
if not items:
|
|
196
|
+
continue
|
|
197
|
+
any_findings = True
|
|
198
|
+
out += ["", f"### {sev.capitalize()} ({len(items)})", ""]
|
|
199
|
+
out += [render_finding_md(f) for f in items]
|
|
200
|
+
if other:
|
|
201
|
+
any_findings = True
|
|
202
|
+
out += ["", f"### Other ({len(other)})", ""]
|
|
203
|
+
out += [render_finding_md(f) for f in other]
|
|
204
|
+
if not any_findings:
|
|
205
|
+
out += ["", "_No findings._"]
|
|
206
|
+
|
|
207
|
+
return "\n".join(out) + "\n"
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def main(argv: list[str]) -> int:
|
|
211
|
+
parser = argparse.ArgumentParser(description="Render PRD validation findings to HTML.")
|
|
212
|
+
parser.add_argument("--findings", required=True, help="Path to validation-findings.json")
|
|
213
|
+
parser.add_argument("--template", required=True, help="Path to HTML template")
|
|
214
|
+
parser.add_argument("--output", required=True, help="Path to write the rendered HTML")
|
|
215
|
+
parser.add_argument("--open", action="store_true", help="Open the rendered HTML in the default browser")
|
|
216
|
+
args = parser.parse_args(argv)
|
|
217
|
+
|
|
218
|
+
findings_path = Path(args.findings)
|
|
219
|
+
template_path = Path(args.template)
|
|
220
|
+
output_path = Path(args.output)
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
data = json.loads(findings_path.read_text(encoding="utf-8"))
|
|
224
|
+
except FileNotFoundError:
|
|
225
|
+
print(f"error: findings file not found: {findings_path}", file=sys.stderr)
|
|
226
|
+
return 1
|
|
227
|
+
except json.JSONDecodeError as e:
|
|
228
|
+
print(f"error: findings file is not valid JSON ({findings_path}): {e}", file=sys.stderr)
|
|
229
|
+
return 1
|
|
230
|
+
try:
|
|
231
|
+
template = template_path.read_text(encoding="utf-8")
|
|
232
|
+
except FileNotFoundError:
|
|
233
|
+
print(f"error: template file not found: {template_path}", file=sys.stderr)
|
|
234
|
+
return 1
|
|
235
|
+
|
|
236
|
+
findings = data.get("findings", []) or []
|
|
237
|
+
|
|
238
|
+
by_cat: dict[str, list[dict]] = {}
|
|
239
|
+
for f in findings:
|
|
240
|
+
by_cat.setdefault(category_for(f), []).append(f)
|
|
241
|
+
|
|
242
|
+
sorted_cats = sorted(
|
|
243
|
+
by_cat.keys(),
|
|
244
|
+
key=lambda c: (CATEGORY_ORDER.index(c) if c in CATEGORY_ORDER else 99, c),
|
|
245
|
+
)
|
|
246
|
+
categories_html = "\n".join(render_category(c, by_cat[c]) for c in sorted_cats)
|
|
247
|
+
|
|
248
|
+
stats = compute_stats(findings)
|
|
249
|
+
grade, grade_class = grade_from(stats)
|
|
250
|
+
score_svg = render_score_bar(stats)
|
|
251
|
+
|
|
252
|
+
timestamp = data.get("timestamp") or datetime.now().isoformat(timespec="seconds")
|
|
253
|
+
substitutions = {
|
|
254
|
+
"prd_name": html.escape(str(data.get("prd_name") or "PRD")),
|
|
255
|
+
"prd_path": html.escape(str(data.get("prd_path") or "")),
|
|
256
|
+
"checklist_path": html.escape(str(data.get("checklist_path") or "")),
|
|
257
|
+
"timestamp": html.escape(timestamp),
|
|
258
|
+
"overall_synthesis": html.escape(str(data.get("overall_synthesis") or "")),
|
|
259
|
+
"grade": grade,
|
|
260
|
+
"grade_class": grade_class,
|
|
261
|
+
"total": str(stats["total"]),
|
|
262
|
+
"passed": str(stats["passed"]),
|
|
263
|
+
"failed": str(stats["failed"]),
|
|
264
|
+
"warned": str(stats["warned"]),
|
|
265
|
+
"na": str(stats["na"]),
|
|
266
|
+
"score_svg": score_svg,
|
|
267
|
+
"categories_html": categories_html,
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
rendered = string.Template(template).safe_substitute(substitutions)
|
|
271
|
+
output_path.write_text(rendered, encoding="utf-8")
|
|
272
|
+
|
|
273
|
+
md_path = output_path.with_suffix(".md")
|
|
274
|
+
md_path.write_text(render_markdown_report(data, findings, stats, grade), encoding="utf-8")
|
|
275
|
+
|
|
276
|
+
print(json.dumps({
|
|
277
|
+
"output": str(output_path),
|
|
278
|
+
"markdown": str(md_path),
|
|
279
|
+
"grade": grade,
|
|
280
|
+
"stats": stats,
|
|
281
|
+
}))
|
|
282
|
+
|
|
283
|
+
if args.open:
|
|
284
|
+
webbrowser.open(output_path.resolve().as_uri())
|
|
285
|
+
|
|
286
|
+
return 0
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
if __name__ == "__main__":
|
|
290
|
+
sys.exit(main(sys.argv[1:]))
|
package/lib/bmad-cache/gds/src/workflows/2-design/gds-prd/assets/validation-report-template.html
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>PRD Validation: $prd_name</title>
|
|
6
|
+
<style>
|
|
7
|
+
:root {
|
|
8
|
+
--bg: #fafaf9;
|
|
9
|
+
--surface: #ffffff;
|
|
10
|
+
--border: #e7e5e4;
|
|
11
|
+
--text: #1c1917;
|
|
12
|
+
--muted: #78716c;
|
|
13
|
+
--pass: #22c55e;
|
|
14
|
+
--warn: #eab308;
|
|
15
|
+
--fail: #ef4444;
|
|
16
|
+
--na: #94a3b8;
|
|
17
|
+
--sev-low: #64748b;
|
|
18
|
+
--sev-medium: #ca8a04;
|
|
19
|
+
--sev-high: #ea580c;
|
|
20
|
+
--sev-critical: #dc2626;
|
|
21
|
+
--grade-exc: #16a34a;
|
|
22
|
+
--grade-good: #65a30d;
|
|
23
|
+
--grade-fair: #d97706;
|
|
24
|
+
--grade-poor: #dc2626;
|
|
25
|
+
}
|
|
26
|
+
* { box-sizing: border-box; }
|
|
27
|
+
html, body { margin: 0; padding: 0; }
|
|
28
|
+
body {
|
|
29
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif;
|
|
30
|
+
background: var(--bg);
|
|
31
|
+
color: var(--text);
|
|
32
|
+
line-height: 1.55;
|
|
33
|
+
font-size: 15px;
|
|
34
|
+
}
|
|
35
|
+
.container { max-width: 960px; margin: 0 auto; padding: 32px 24px 64px; }
|
|
36
|
+
|
|
37
|
+
header.report-header {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: space-between;
|
|
41
|
+
gap: 24px;
|
|
42
|
+
padding-bottom: 16px;
|
|
43
|
+
border-bottom: 1px solid var(--border);
|
|
44
|
+
margin-bottom: 24px;
|
|
45
|
+
}
|
|
46
|
+
.title h1 { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
|
|
47
|
+
.title .subtitle { color: var(--muted); font-size: 13px; margin-top: 4px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
|
|
48
|
+
.grade {
|
|
49
|
+
padding: 10px 18px;
|
|
50
|
+
border-radius: 8px;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
color: white;
|
|
53
|
+
font-size: 15px;
|
|
54
|
+
white-space: nowrap;
|
|
55
|
+
}
|
|
56
|
+
.grade-excellent { background: var(--grade-exc); }
|
|
57
|
+
.grade-good { background: var(--grade-good); }
|
|
58
|
+
.grade-fair { background: var(--grade-fair); }
|
|
59
|
+
.grade-poor { background: var(--grade-poor); }
|
|
60
|
+
|
|
61
|
+
.synthesis {
|
|
62
|
+
background: var(--surface);
|
|
63
|
+
border: 1px solid var(--border);
|
|
64
|
+
border-left: 3px solid var(--muted);
|
|
65
|
+
border-radius: 8px;
|
|
66
|
+
padding: 16px 20px;
|
|
67
|
+
margin-bottom: 24px;
|
|
68
|
+
color: var(--text);
|
|
69
|
+
font-size: 15px;
|
|
70
|
+
}
|
|
71
|
+
.synthesis:empty { display: none; }
|
|
72
|
+
|
|
73
|
+
.scoreboard {
|
|
74
|
+
background: var(--surface);
|
|
75
|
+
border: 1px solid var(--border);
|
|
76
|
+
border-radius: 8px;
|
|
77
|
+
padding: 18px 20px;
|
|
78
|
+
margin-bottom: 24px;
|
|
79
|
+
}
|
|
80
|
+
.score-bar { margin: 0 0 14px; line-height: 0; }
|
|
81
|
+
.score-stats { display: flex; gap: 22px; font-size: 14px; flex-wrap: wrap; }
|
|
82
|
+
.score-stats span { display: inline-flex; align-items: center; gap: 6px; }
|
|
83
|
+
.score-stats .dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
|
|
84
|
+
.dot-pass { background: var(--pass); }
|
|
85
|
+
.dot-warn { background: var(--warn); }
|
|
86
|
+
.dot-fail { background: var(--fail); }
|
|
87
|
+
.dot-na { background: var(--na); }
|
|
88
|
+
.total-count { margin-left: auto; color: var(--muted); }
|
|
89
|
+
|
|
90
|
+
section.category { margin-bottom: 16px; }
|
|
91
|
+
section.category details {
|
|
92
|
+
background: var(--surface);
|
|
93
|
+
border: 1px solid var(--border);
|
|
94
|
+
border-radius: 8px;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
}
|
|
97
|
+
section.category summary {
|
|
98
|
+
padding: 14px 20px;
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
user-select: none;
|
|
101
|
+
list-style: none;
|
|
102
|
+
}
|
|
103
|
+
section.category summary::-webkit-details-marker { display: none; }
|
|
104
|
+
section.category summary::before {
|
|
105
|
+
content: "▸";
|
|
106
|
+
display: inline-block;
|
|
107
|
+
margin-right: 10px;
|
|
108
|
+
color: var(--muted);
|
|
109
|
+
transition: transform 0.15s ease;
|
|
110
|
+
}
|
|
111
|
+
section.category details[open] summary::before { transform: rotate(90deg); }
|
|
112
|
+
section.category summary h2 { display: inline; margin: 0; font-size: 16px; font-weight: 600; letter-spacing: -0.005em; }
|
|
113
|
+
section.category .count { color: var(--muted); font-weight: 400; margin-left: 6px; font-size: 14px; }
|
|
114
|
+
|
|
115
|
+
article.finding { padding: 16px 20px; border-top: 1px solid var(--border); }
|
|
116
|
+
article.finding-fail { background: rgba(239, 68, 68, 0.025); }
|
|
117
|
+
article.finding header {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: 10px;
|
|
121
|
+
flex-wrap: wrap;
|
|
122
|
+
margin-bottom: 8px;
|
|
123
|
+
}
|
|
124
|
+
.badge {
|
|
125
|
+
font-size: 10.5px;
|
|
126
|
+
padding: 3px 8px;
|
|
127
|
+
border-radius: 4px;
|
|
128
|
+
font-weight: 600;
|
|
129
|
+
text-transform: uppercase;
|
|
130
|
+
letter-spacing: 0.04em;
|
|
131
|
+
line-height: 1.4;
|
|
132
|
+
}
|
|
133
|
+
.badge-pass { background: rgba(34, 197, 94, 0.12); color: #15803d; }
|
|
134
|
+
.badge-warn { background: rgba(234, 179, 8, 0.14); color: #854d0e; }
|
|
135
|
+
.badge-fail { background: rgba(239, 68, 68, 0.12); color: #b91c1c; }
|
|
136
|
+
.badge-na { background: rgba(148, 163, 184, 0.16); color: #475569; }
|
|
137
|
+
.badge-sev-low { background: rgba(100, 116, 139, 0.12); color: var(--sev-low); }
|
|
138
|
+
.badge-sev-medium { background: rgba(202, 138, 4, 0.14); color: var(--sev-medium); }
|
|
139
|
+
.badge-sev-high { background: rgba(234, 88, 12, 0.14); color: var(--sev-high); }
|
|
140
|
+
.badge-sev-critical { background: rgba(220, 38, 38, 0.14); color: var(--sev-critical); }
|
|
141
|
+
.finding-id { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; color: var(--muted); }
|
|
142
|
+
.finding-title { margin: 0; font-size: 15px; font-weight: 500; flex: 1; min-width: 200px; }
|
|
143
|
+
.finding-location, .finding-note, .finding-fix { margin-top: 6px; font-size: 14px; color: var(--text); }
|
|
144
|
+
.finding-location strong, .finding-fix strong { color: var(--muted); font-weight: 500; }
|
|
145
|
+
|
|
146
|
+
footer.report-footer {
|
|
147
|
+
margin-top: 40px;
|
|
148
|
+
padding-top: 16px;
|
|
149
|
+
border-top: 1px solid var(--border);
|
|
150
|
+
font-size: 12px;
|
|
151
|
+
color: var(--muted);
|
|
152
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
153
|
+
}
|
|
154
|
+
footer .meta { display: flex; gap: 24px; flex-wrap: wrap; }
|
|
155
|
+
</style>
|
|
156
|
+
</head>
|
|
157
|
+
<body>
|
|
158
|
+
<div class="container">
|
|
159
|
+
<header class="report-header">
|
|
160
|
+
<div class="title">
|
|
161
|
+
<h1>$prd_name — Validation Report</h1>
|
|
162
|
+
<div class="subtitle">$prd_path</div>
|
|
163
|
+
</div>
|
|
164
|
+
<div class="grade $grade_class">$grade</div>
|
|
165
|
+
</header>
|
|
166
|
+
|
|
167
|
+
<div class="synthesis">$overall_synthesis</div>
|
|
168
|
+
|
|
169
|
+
<div class="scoreboard">
|
|
170
|
+
<div class="score-bar">$score_svg</div>
|
|
171
|
+
<div class="score-stats">
|
|
172
|
+
<span><span class="dot dot-pass"></span>$passed pass</span>
|
|
173
|
+
<span><span class="dot dot-warn"></span>$warned warn</span>
|
|
174
|
+
<span><span class="dot dot-fail"></span>$failed fail</span>
|
|
175
|
+
<span><span class="dot dot-na"></span>$na n/a</span>
|
|
176
|
+
<span class="total-count">$total items checked</span>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
$categories_html
|
|
181
|
+
|
|
182
|
+
<footer class="report-footer">
|
|
183
|
+
<div class="meta">
|
|
184
|
+
<span>Checklist: $checklist_path</span>
|
|
185
|
+
<span>Generated: $timestamp</span>
|
|
186
|
+
</div>
|
|
187
|
+
</footer>
|
|
188
|
+
</div>
|
|
189
|
+
</body>
|
|
190
|
+
</html>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# DO NOT EDIT -- overwritten on every update.
|
|
2
|
+
#
|
|
3
|
+
# Workflow customization surface for gds-prd.
|
|
4
|
+
#
|
|
5
|
+
# Override files (not edited here):
|
|
6
|
+
# {project-root}/_bmad/custom/gds-prd.toml (team)
|
|
7
|
+
# {project-root}/_bmad/custom/gds-prd.user.toml (personal)
|
|
8
|
+
|
|
9
|
+
[workflow]
|
|
10
|
+
|
|
11
|
+
# --- Configurable below. Overrides merge per BMad structural rules: ---
|
|
12
|
+
# scalars: override wins • arrays: append
|
|
13
|
+
|
|
14
|
+
# Steps to run before the standard activation (config load, greet).
|
|
15
|
+
# Use for pre-flight loads, compliance checks, etc.
|
|
16
|
+
activation_steps_prepend = []
|
|
17
|
+
|
|
18
|
+
# Steps to run after greet but before the workflow begins.
|
|
19
|
+
# Use for context-heavy setup that should happen once the user has been acknowledged.
|
|
20
|
+
activation_steps_append = []
|
|
21
|
+
|
|
22
|
+
# Persistent facts the workflow keeps in mind for the whole run
|
|
23
|
+
# (standards, compliance constraints, stylistic guardrails).
|
|
24
|
+
# Each entry is either a literal sentence, a skill prefixed with `skill:`, or a `file:`-prefixed
|
|
25
|
+
# path/glob whose contents are loaded as facts.
|
|
26
|
+
#
|
|
27
|
+
# Default loads project-context.md if gds-generate-project-context has produced one — this gives
|
|
28
|
+
# the facilitator persistent awareness of the project's tech, domain, and constraints without
|
|
29
|
+
# re-asking. Common opt-ins (set in team/user override TOML):
|
|
30
|
+
# "skill:acme-studio:terms-and-conditions" # a skill that contains relevant info
|
|
31
|
+
# "Every PRD requirement must be testable and traceable to a GDD pillar." # generic agent instruction
|
|
32
|
+
persistent_facts = [
|
|
33
|
+
"file:{project-root}/**/project-context.md",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
# Executed when the workflow completes (after the user has been told the
|
|
37
|
+
# PRD is ready). Accepts either a string scalar (single instruction)
|
|
38
|
+
# or an array of instructions executed in order. Empty for none.
|
|
39
|
+
on_complete = ""
|
|
40
|
+
|
|
41
|
+
# Default PRD structure. Treated as a starting point — the LLM adapts it
|
|
42
|
+
# to the product, project type, and domain. Override the path in team/user TOML
|
|
43
|
+
# to enforce a different structure (e.g. regulated-industry, internal-tool).
|
|
44
|
+
prd_template = "assets/prd-template.md"
|
|
45
|
+
|
|
46
|
+
# Validation checklist used at the Validate intent and at Finalize step 3.
|
|
47
|
+
# A subagent walks the checklist against prd.md and returns structured findings.
|
|
48
|
+
# Override the path in team/user TOML to enforce a studio-specific checklist.
|
|
49
|
+
validation_checklist = "assets/prd-validation-checklist.md"
|
|
50
|
+
|
|
51
|
+
# HTML skeleton the synthesis pass fills directly when consolidating reviewer
|
|
52
|
+
# outputs into a validation report. No substitution engine — the parent LLM
|
|
53
|
+
# writes the final HTML. Fully overridable to match studio branding.
|
|
54
|
+
# Uses inline CSS, no external dependencies, and native HTML <details> for
|
|
55
|
+
# collapse — no JS.
|
|
56
|
+
validation_report_template = "assets/validation-report-template.html"
|
|
57
|
+
|
|
58
|
+
# Run folder location. The PRD, optional addendum, decision log, and optional
|
|
59
|
+
# validation report all land inside `{output_dir}/{output_folder_name}/`.
|
|
60
|
+
output_dir = "{planning_artifacts}/prds"
|
|
61
|
+
output_folder_name = "prd-{project_name}-{date}"
|
|
62
|
+
|
|
63
|
+
# Document standards applied to human-consumed docs at Finalize. Each entry is
|
|
64
|
+
# a `skill:`, `file:`, or plain-text directive; the parent LLM applies the
|
|
65
|
+
# findings before the user sees the draft. Empty by default — Game Dev Studio
|
|
66
|
+
# ships no editorial-review skills. Add your own in team/user override TOML:
|
|
67
|
+
# "skill:my-studio:editorial-review-prose"
|
|
68
|
+
# "file:{project-root}/_bmad/style-guides/studio-voice.md"
|
|
69
|
+
# "Convert all dates to ISO 8601 format."
|
|
70
|
+
doc_standards = []
|
|
71
|
+
|
|
72
|
+
# External-source registry. Natural-language directives describing knowledge
|
|
73
|
+
# bases, MCP tools, or internal systems the LLM may consult during the workflow
|
|
74
|
+
# when a relevant need surfaces. The LLM does NOT query these preemptively —
|
|
75
|
+
# it consults them on demand. If a named MCP tool is unavailable at runtime,
|
|
76
|
+
# the LLM falls back to standard behavior and notes the gap. Empty by default.
|
|
77
|
+
external_sources = []
|
|
78
|
+
|
|
79
|
+
# External-handoff routing. Natural-language directives the LLM applies at
|
|
80
|
+
# Finalize to route outputs beyond local files (Confluence, Notion, Google
|
|
81
|
+
# Drive, ticket systems, etc.). Handoffs run after the artifact is polished
|
|
82
|
+
# and before the final user-facing message. URLs or IDs returned by the
|
|
83
|
+
# destination are captured and surfaced to the user. Empty by default.
|
|
84
|
+
external_handoffs = []
|