bmad-method 6.10.1-next.47 → 6.10.1-next.49
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/README.md +11 -7
- package/README_CN.md +10 -8
- package/README_VN.md +10 -8
- package/bmad-modules.yaml +43 -39
- package/package.json +1 -1
- package/src/bmm-skills/module.yaml +1 -1
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-build/review-prompts/verification-gap.md +4 -0
- package/src/bmm-skills/ship/bmad-build-auto/review-prompts/verification-gap.md +4 -0
- package/src/bmm-skills/ship/bmad-code-review/review-prompts/verification-gap.md +4 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/bmad-review/references/lens-verification-gap.md +4 -0
- package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
- package/tools/installer/cli-utils.js +6 -2
- package/tools/installer/prompts.js +41 -102
- package/tools/installer/ui.js +62 -9
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Agile Ai Driven Development — turn an idea or change request into working software without giving up the thinking.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Ai Driven Development (AiDD) covers the whole effort, not only the code: what to build, how it holds together, and how it changes as you learn. BMad Method is the agile way to do it — decisions stay explicit, context carries forward, and the process sizes itself to the work. Small changes go straight to build. Complex work gets the depth it needs. The same method covers a weekend prototype and a system with years of history behind it.
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -20,6 +20,8 @@ Open your project in your AI coding tool, invoke `bmad-build` with what you want
|
|
|
20
20
|
|
|
21
21
|
**[Build your first project with BMad →](https://docs.bmad-method.org/tutorials/getting-started/)**
|
|
22
22
|
|
|
23
|
+
**[Add BMad to an existing codebase →](https://docs.bmad-method.org/how-to/established-projects/)**
|
|
24
|
+
|
|
23
25
|
BMad is free and open source, with no paywalled workflows or gated community. For prerelease builds, CI/CD, configuration overrides, and non-interactive setup, see the [installation guide](https://docs.bmad-method.org/how-to/install-bmad/).
|
|
24
26
|
|
|
25
27
|
## Why BMad?
|
|
@@ -27,6 +29,7 @@ BMad is free and open source, with no paywalled workflows or gated community. Fo
|
|
|
27
29
|
Coding assistants are effective at implementation, but they often turn unstated assumptions into code. BMad keeps you in control while its agents and workflows make the important decisions explicit and preserve them as context for the work that follows.
|
|
28
30
|
|
|
29
31
|
- **Right-sized process** — Go directly to implementation for clear changes or add deeper planning for larger initiatives.
|
|
32
|
+
- **New or existing code** — Start from nothing, or establish verified context on a codebase you inherited and work from what is actually there.
|
|
30
33
|
- **Durable context** — Carry product and technical decisions forward instead of re-explaining them in every chat.
|
|
31
34
|
- **Specialized perspectives** — Bring in product, architecture, UX, development, and testing expertise when it helps.
|
|
32
35
|
- **Guided collaboration** — Use structured workflows and multiple-agent discussions without handing over judgment.
|
|
@@ -40,11 +43,12 @@ Install the core method or add official modules for specialized work.
|
|
|
40
43
|
|
|
41
44
|
| Module | Purpose |
|
|
42
45
|
| --- | --- |
|
|
43
|
-
| **[BMad Method
|
|
44
|
-
| **[BMad Builder
|
|
45
|
-
| **[
|
|
46
|
-
| **[
|
|
47
|
-
| **[
|
|
46
|
+
| **[BMad Method](https://github.com/bmad-code-org/BMAD-METHOD)** | Plan and deliver software, from new prototypes to established codebases |
|
|
47
|
+
| **[BMad Builder](https://github.com/bmad-code-org/bmad-builder)** | Skill, workflow, and agent builder |
|
|
48
|
+
| **[BMad Creative Intelligence Suite](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite)** | Creative thinking partners for innovation, design thinking, and storytelling |
|
|
49
|
+
| **[BMad Test Architect](https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise)** | Enterprise testing add-on for BMad Method |
|
|
50
|
+
| **[BMad Loop](https://github.com/bmad-code-org/bmad-loop)** | Builds, verifies, and retros a whole epic unattended |
|
|
51
|
+
| **[BMad Game Dev Studio](https://github.com/bmad-code-org/bmad-module-game-dev-studio)** | Ideate, design, and build games in any framework, including Unity, Unreal, Godot, and Phaser |
|
|
48
52
|
|
|
49
53
|
## Plan on the Web
|
|
50
54
|
|
package/README_CN.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
[](https://discord.gg/gk8jAdXWmj)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**Agile Ai Driven Development(敏捷 AI 驱动开发)** —— Ai Driven Development(AiDD)关注的不只是代码,还包括做什么、如何组织,以及在认知变化时如何调整。BMad Method 是实践 AiDD 的敏捷方式:决策保持显式,上下文持续传递,流程随工作量自动调整。同一套方法既适用于周末原型,也适用于有多年历史的系统。
|
|
9
9
|
|
|
10
10
|
**100% 免费且开源。** 没有付费墙,没有封闭内容,也没有封闭 Discord。我们希望每个人都能平等获得高质量的人机协作开发方法。
|
|
11
11
|
|
|
@@ -56,19 +56,21 @@ npx bmad-method install --directory /path/to/project --modules bmm --tools claud
|
|
|
56
56
|
|
|
57
57
|
BMad 可通过官方模块扩展到不同专业场景。你可以在安装时选择,也可以后续随时补装。
|
|
58
58
|
|
|
59
|
-
| 模块
|
|
60
|
-
|
|
|
61
|
-
| **[BMad Method
|
|
62
|
-
| **[BMad Builder
|
|
63
|
-
| **[
|
|
64
|
-
| **[
|
|
65
|
-
| **[
|
|
59
|
+
| 模块 | 用途 |
|
|
60
|
+
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
61
|
+
| **[BMad Method](https://github.com/bmad-code-org/BMAD-METHOD)** | 规划并交付软件,覆盖全新原型到成熟代码库 |
|
|
62
|
+
| **[BMad Builder](https://github.com/bmad-code-org/bmad-builder)** | 技能、工作流与智能体构建器 |
|
|
63
|
+
| **[BMad Creative Intelligence Suite](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite)** | 创意思考伙伴:创新、设计思维与叙事 |
|
|
64
|
+
| **[BMad Test Architect](https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise)** | 面向 BMad Method 的企业级测试扩展模块 |
|
|
65
|
+
| **[BMad Loop](https://github.com/bmad-code-org/bmad-loop)** | 无人值守地构建、验证并复盘整个 Epic |
|
|
66
|
+
| **[BMad Game Dev Studio](https://github.com/bmad-code-org/bmad-module-game-dev-studio)** | 构思、设计并开发游戏,支持任意框架,包括 Unity、Unreal、Godot 与 Phaser |
|
|
66
67
|
|
|
67
68
|
## 文档
|
|
68
69
|
|
|
69
70
|
[BMad 方法文档站点](https://docs.bmad-method.org/zh-cn/) — 教程、指南、概念和参考
|
|
70
71
|
|
|
71
72
|
**快速链接:**
|
|
73
|
+
|
|
72
74
|
- [入门教程](https://docs.bmad-method.org/zh-cn/tutorials/getting-started/)
|
|
73
75
|
- [从旧版本升级](https://docs.bmad-method.org/zh-cn/how-to/upgrade-to-v6/)
|
|
74
76
|
- [测试架构师文档(英文)](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/)
|
package/README_VN.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
[English](README.md) | [简体中文](README_CN.md) | Tiếng Việt
|
|
11
11
|
|
|
12
|
-
**
|
|
12
|
+
**Agile Ai Driven Development (Phát triển hướng AI theo lối agile)** - Ai Driven Development (AiDD) bao trùm toàn bộ công việc chứ không chỉ phần mã: xây dựng cái gì, các phần gắn kết ra sao, và thay đổi thế nào khi bạn hiểu thêm. BMad Method là cách làm AiDD theo lối agile: quyết định luôn tường minh, ngữ cảnh được giữ lại xuyên suốt, và quy trình tự co giãn theo khối lượng công việc. Cùng một phương pháp dùng được cho nguyên mẫu cuối tuần lẫn hệ thống đã có nhiều năm lịch sử.
|
|
13
13
|
|
|
14
14
|
**100% miễn phí và mã nguồn mở.** Không có tường phí. Không có nội dung bị khóa. Không có Discord giới hạn quyền truy cập. Chúng tôi tin vào việc trao quyền cho mọi người, không chỉ cho những ai có thể trả tiền để vào một cộng đồng hay khóa học khép kín.
|
|
15
15
|
|
|
@@ -60,19 +60,21 @@ npx bmad-method install --directory /path/to/project --modules bmm --tools claud
|
|
|
60
60
|
|
|
61
61
|
BMad Method có thể được mở rộng bằng các mô-đun chính thức cho những miền chuyên biệt. Chúng có sẵn trong lúc cài đặt hoặc bất kỳ lúc nào sau đó.
|
|
62
62
|
|
|
63
|
-
| Module
|
|
64
|
-
|
|
|
65
|
-
| **[BMad Method
|
|
66
|
-
| **[BMad Builder
|
|
67
|
-
| **[
|
|
68
|
-
| **[
|
|
69
|
-
| **[
|
|
63
|
+
| Module | Mục đích |
|
|
64
|
+
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
65
|
+
| **[BMad Method](https://github.com/bmad-code-org/BMAD-METHOD)** | Lập kế hoạch và bàn giao phần mềm, từ nguyên mẫu mới đến codebase lâu năm |
|
|
66
|
+
| **[BMad Builder](https://github.com/bmad-code-org/bmad-builder)** | Trình tạo skill, quy trình và agent |
|
|
67
|
+
| **[BMad Creative Intelligence Suite](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite)** | Đối tác tư duy sáng tạo cho đổi mới, tư duy thiết kế và kể chuyện |
|
|
68
|
+
| **[BMad Test Architect](https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise)** | Mô-đun kiểm thử doanh nghiệp bổ trợ cho BMad Method |
|
|
69
|
+
| **[BMad Loop](https://github.com/bmad-code-org/bmad-loop)** | Tự động xây dựng, kiểm chứng và tổng kết cả một Epic |
|
|
70
|
+
| **[BMad Game Dev Studio](https://github.com/bmad-code-org/bmad-module-game-dev-studio)** | Lên ý tưởng, thiết kế và phát triển game trên mọi framework, gồm Unity, Unreal, Godot và Phaser |
|
|
70
71
|
|
|
71
72
|
## Tài liệu
|
|
72
73
|
|
|
73
74
|
[Trang tài liệu BMad Method](https://docs.bmad-method.org/vi-vn/) - bài hướng dẫn, hướng dẫn tác vụ, giải thích khái niệm và tài liệu tham chiếu
|
|
74
75
|
|
|
75
76
|
**Liên kết nhanh:**
|
|
77
|
+
|
|
76
78
|
- [Hướng dẫn bắt đầu](https://docs.bmad-method.org/vi-vn/tutorials/getting-started/)
|
|
77
79
|
- [Nâng cấp từ các phiên bản trước](https://docs.bmad-method.org/vi-vn/how-to/upgrade-to-v6/)
|
|
78
80
|
- [Tài liệu Test Architect](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/)
|
package/bmad-modules.yaml
CHANGED
|
@@ -34,6 +34,39 @@
|
|
|
34
34
|
# install to the new code and removes the stale `_bmad/<alias>/` directory.
|
|
35
35
|
|
|
36
36
|
modules:
|
|
37
|
+
bmad-builder:
|
|
38
|
+
url: https://github.com/bmad-code-org/bmad-builder
|
|
39
|
+
module-definition: skills/module.yaml
|
|
40
|
+
code: bmb
|
|
41
|
+
name: "BMad Builder"
|
|
42
|
+
description: "Skill, workflow, and agent builder"
|
|
43
|
+
defaultSelected: false
|
|
44
|
+
type: bmad-org
|
|
45
|
+
npmPackage: bmad-builder
|
|
46
|
+
default_channel: stable
|
|
47
|
+
|
|
48
|
+
bmad-creative-intelligence-suite:
|
|
49
|
+
url: https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite
|
|
50
|
+
module-definition: src/module.yaml
|
|
51
|
+
code: cis
|
|
52
|
+
name: "BMad Creative Intelligence Suite"
|
|
53
|
+
description: "Creative thinking partners"
|
|
54
|
+
defaultSelected: false
|
|
55
|
+
type: bmad-org
|
|
56
|
+
npmPackage: bmad-creative-intelligence-suite
|
|
57
|
+
default_channel: stable
|
|
58
|
+
|
|
59
|
+
bmad-method-test-architecture-enterprise:
|
|
60
|
+
url: https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise
|
|
61
|
+
module-definition: src/module.yaml
|
|
62
|
+
code: tea
|
|
63
|
+
name: "BMad Test Architect"
|
|
64
|
+
description: "Enterprise testing BMM add-on"
|
|
65
|
+
defaultSelected: false
|
|
66
|
+
type: bmad-org
|
|
67
|
+
npmPackage: bmad-method-test-architecture-enterprise
|
|
68
|
+
default_channel: stable
|
|
69
|
+
|
|
37
70
|
bmad-loop:
|
|
38
71
|
url: https://github.com/bmad-code-org/bmad-loop
|
|
39
72
|
module-definition: src/bmad_loop/data/skills/bmad-loop-setup/assets/module.yaml
|
|
@@ -43,7 +76,7 @@ modules:
|
|
|
43
76
|
# installs migrating forward instead of being orphaned.
|
|
44
77
|
aliases: [bauto]
|
|
45
78
|
name: "BMad Loop"
|
|
46
|
-
description: "
|
|
79
|
+
description: "Builds, verifies, and retros a whole epic unattended"
|
|
47
80
|
defaultSelected: false
|
|
48
81
|
type: bmad-org
|
|
49
82
|
default_channel: stable
|
|
@@ -59,27 +92,18 @@ modules:
|
|
|
59
92
|
It installs the bmad-loop orchestrator tool and wires up the per-project
|
|
60
93
|
hooks and policy. The automation skills don't run until setup completes.
|
|
61
94
|
|
|
62
|
-
bmad-
|
|
63
|
-
url: https://github.com/bmad-code-org/bmad-
|
|
95
|
+
bmad-game-dev-studio:
|
|
96
|
+
url: https://github.com/bmad-code-org/bmad-module-game-dev-studio.git
|
|
64
97
|
module-definition: src/module.yaml
|
|
65
|
-
code:
|
|
66
|
-
name: "BMad
|
|
67
|
-
description: "
|
|
98
|
+
code: gds
|
|
99
|
+
name: "BMad Game Dev Studio"
|
|
100
|
+
description: "Ideate, design, and build games"
|
|
68
101
|
defaultSelected: false
|
|
69
102
|
type: bmad-org
|
|
70
|
-
npmPackage: bmad-
|
|
103
|
+
npmPackage: bmad-game-dev-studio
|
|
71
104
|
default_channel: stable
|
|
72
105
|
|
|
73
|
-
|
|
74
|
-
url: https://github.com/bmad-code-org/bmad-builder
|
|
75
|
-
module-definition: skills/module.yaml
|
|
76
|
-
code: bmb
|
|
77
|
-
name: "BMad Builder"
|
|
78
|
-
description: "Build AI agents, workflows, and modules from a conversation"
|
|
79
|
-
defaultSelected: false
|
|
80
|
-
type: bmad-org
|
|
81
|
-
npmPackage: bmad-builder
|
|
82
|
-
default_channel: stable
|
|
106
|
+
# --- Deprecated: hidden from the picker unless already installed ---
|
|
83
107
|
|
|
84
108
|
bmad-automator:
|
|
85
109
|
url: https://github.com/bmad-code-org/bmad-automator
|
|
@@ -94,28 +118,6 @@ modules:
|
|
|
94
118
|
deprecated: true
|
|
95
119
|
deprecation-message: "BMad Automator has been deprecated and is replaced by BMad Loop (bmad-loop). Install BMad Loop instead."
|
|
96
120
|
|
|
97
|
-
bmad-creative-intelligence-suite:
|
|
98
|
-
url: https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite
|
|
99
|
-
module-definition: src/module.yaml
|
|
100
|
-
code: cis
|
|
101
|
-
name: "BMad Creative Intelligence Suite"
|
|
102
|
-
description: "Brainstorming, ideation, storytelling, design thinking, and problem-solving"
|
|
103
|
-
defaultSelected: false
|
|
104
|
-
type: bmad-org
|
|
105
|
-
npmPackage: bmad-creative-intelligence-suite
|
|
106
|
-
default_channel: stable
|
|
107
|
-
|
|
108
|
-
bmad-game-dev-studio:
|
|
109
|
-
url: https://github.com/bmad-code-org/bmad-module-game-dev-studio.git
|
|
110
|
-
module-definition: src/module.yaml
|
|
111
|
-
code: gds
|
|
112
|
-
name: "BMad Game Dev Studio"
|
|
113
|
-
description: "Game design and development for Unity, Unreal, Godot, and Phaser."
|
|
114
|
-
defaultSelected: false
|
|
115
|
-
type: bmad-org
|
|
116
|
-
npmPackage: bmad-game-dev-studio
|
|
117
|
-
default_channel: stable
|
|
118
|
-
|
|
119
121
|
bmad-method-wds-expansion:
|
|
120
122
|
url: https://github.com/bmad-code-org/bmad-method-wds-expansion
|
|
121
123
|
module-definition: src/module.yaml
|
|
@@ -127,3 +129,5 @@ modules:
|
|
|
127
129
|
type: bmad-org
|
|
128
130
|
npmPackage: bmad-wds
|
|
129
131
|
default_channel: stable
|
|
132
|
+
deprecated: true
|
|
133
|
+
deprecation-message: "Whiteport Design Studio is no longer receiving updates. Its capabilities are being folded into BMad Method (bmm) as enhanced UX features. Your existing install is kept as-is."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
code: bmm
|
|
2
2
|
name: "BMad Method"
|
|
3
|
-
description: "
|
|
3
|
+
description: "Agile Ai Driven Development"
|
|
4
4
|
default_selected: true # This module will be selected by default for new installations
|
|
5
5
|
|
|
6
6
|
# Variables from Core Config inserted:
|
package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -54,6 +54,8 @@ Find and read the relevant test. Ask whether the Demonstration would make an ass
|
|
|
54
54
|
|
|
55
55
|
A test counts only if it runs normally and an assertion observes the changed output, branch, or contract. These do not count: no execution; source-text assertions that match a file's wording instead of running it; success/no-throw/snapshot-only checks; mock/log-call checks; human-only checks; tests that mock away the integration; e2e tests that pass through without checking the changed output; stale assertions or fixtures.
|
|
56
56
|
|
|
57
|
+
For example, `expect(x ?? DEFAULT).toBe(DEFAULT)` passes when `x` is missing.
|
|
58
|
+
|
|
57
59
|
Common patterns:
|
|
58
60
|
|
|
59
61
|
- **Caller-path gap** — helper test covers the branch, but caller values skip it.
|
|
@@ -67,6 +69,8 @@ Common patterns:
|
|
|
67
69
|
|
|
68
70
|
Before writing a finding, re-open the specific tests or search results the finding relies on. Verify the Demonstration would not make any test you checked fail, or that the absence claim is backed by the symbol/import-reference search. Do not claim more than you verified; drop any finding you cannot ground.
|
|
69
71
|
|
|
72
|
+
Explain why the test misses the bug using what the test sets up and checks.
|
|
73
|
+
|
|
70
74
|
Do not report: compiler/type-checker-enforced cases; behavior already verified by an integration, contract, or e2e test; implementation-detail or mock-only tests; low coverage or a missing test file by itself; legacy untested code the change did not affect.
|
|
71
75
|
|
|
72
76
|
Report genuine problems you noticed while tracing verification, even if they are not verification gaps. Put them under `Other findings` in the output. This permits reporting what you already reached, not extra hunting.
|
|
@@ -54,6 +54,8 @@ Find and read the relevant test. Ask whether the Demonstration would make an ass
|
|
|
54
54
|
|
|
55
55
|
A test counts only if it runs normally and an assertion observes the changed output, branch, or contract. These do not count: no execution; source-text assertions that match a file's wording instead of running it; success/no-throw/snapshot-only checks; mock/log-call checks; human-only checks; tests that mock away the integration; e2e tests that pass through without checking the changed output; stale assertions or fixtures.
|
|
56
56
|
|
|
57
|
+
For example, `expect(x ?? DEFAULT).toBe(DEFAULT)` passes when `x` is missing.
|
|
58
|
+
|
|
57
59
|
Common patterns:
|
|
58
60
|
|
|
59
61
|
- **Caller-path gap** — helper test covers the branch, but caller values skip it.
|
|
@@ -67,6 +69,8 @@ Common patterns:
|
|
|
67
69
|
|
|
68
70
|
Before writing a finding, re-open the specific tests or search results the finding relies on. Verify the Demonstration would not make any test you checked fail, or that the absence claim is backed by the symbol/import-reference search. Do not claim more than you verified; drop any finding you cannot ground.
|
|
69
71
|
|
|
72
|
+
Explain why the test misses the bug using what the test sets up and checks.
|
|
73
|
+
|
|
70
74
|
Do not report: compiler/type-checker-enforced cases; behavior already verified by an integration, contract, or e2e test; implementation-detail or mock-only tests; low coverage or a missing test file by itself; legacy untested code the change did not affect.
|
|
71
75
|
|
|
72
76
|
Report genuine problems you noticed while tracing verification, even if they are not verification gaps. Put them under `Other findings` in the output. This permits reporting what you already reached, not extra hunting.
|
|
@@ -54,6 +54,8 @@ Find and read the relevant test. Ask whether the Demonstration would make an ass
|
|
|
54
54
|
|
|
55
55
|
A test counts only if it runs normally and an assertion observes the changed output, branch, or contract. These do not count: no execution; source-text assertions that match a file's wording instead of running it; success/no-throw/snapshot-only checks; mock/log-call checks; human-only checks; tests that mock away the integration; e2e tests that pass through without checking the changed output; stale assertions or fixtures.
|
|
56
56
|
|
|
57
|
+
For example, `expect(x ?? DEFAULT).toBe(DEFAULT)` passes when `x` is missing.
|
|
58
|
+
|
|
57
59
|
Common patterns:
|
|
58
60
|
|
|
59
61
|
- **Caller-path gap** — helper test covers the branch, but caller values skip it.
|
|
@@ -67,6 +69,8 @@ Common patterns:
|
|
|
67
69
|
|
|
68
70
|
Before writing a finding, re-open the specific tests or search results the finding relies on. Verify the Demonstration would not make any test you checked fail, or that the absence claim is backed by the symbol/import-reference search. Do not claim more than you verified; drop any finding you cannot ground.
|
|
69
71
|
|
|
72
|
+
Explain why the test misses the bug using what the test sets up and checks.
|
|
73
|
+
|
|
70
74
|
Do not report: compiler/type-checker-enforced cases; behavior already verified by an integration, contract, or e2e test; implementation-detail or mock-only tests; low coverage or a missing test file by itself; legacy untested code the change did not affect.
|
|
71
75
|
|
|
72
76
|
Report genuine problems you noticed while tracing verification, even if they are not verification gaps. Put them under `Other findings` in the output. This permits reporting what you already reached, not extra hunting.
|
package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -56,6 +56,8 @@ Find and read the relevant test. Ask whether the Demonstration would make an ass
|
|
|
56
56
|
|
|
57
57
|
A test counts only if it runs normally and an assertion observes the changed output, branch, or contract. These do not count: no execution; success/no-throw/snapshot-only checks; mock/log-call checks; human-only checks; tests that mock away the integration; e2e tests that pass through without checking the changed output; stale assertions or fixtures.
|
|
58
58
|
|
|
59
|
+
For example, `expect(x ?? DEFAULT).toBe(DEFAULT)` passes when `x` is missing.
|
|
60
|
+
|
|
59
61
|
Common patterns:
|
|
60
62
|
|
|
61
63
|
- **Caller-path gap** — helper test covers the branch, but caller values skip it.
|
|
@@ -69,6 +71,8 @@ Common patterns:
|
|
|
69
71
|
|
|
70
72
|
Before writing a finding, re-open the specific tests or search results the finding relies on. Verify the Demonstration would not make any test you checked fail, or that the absence claim is backed by the symbol/import-reference search. Do not claim more than you verified; drop any finding you cannot ground.
|
|
71
73
|
|
|
74
|
+
Explain why the test misses the bug using what the test sets up and checks.
|
|
75
|
+
|
|
72
76
|
Do not report: compiler/type-checker-enforced cases; behavior already verified by an integration, contract, or e2e test; implementation-detail or mock-only tests; low coverage or a missing test file by itself; legacy untested code the change did not affect.
|
|
73
77
|
|
|
74
78
|
Report genuine problems you noticed while tracing verification, even if they are not verification gaps — emit them as findings with `gap_shape: "other"`. This permits reporting what you already reached, not extra hunting.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -29,9 +29,13 @@ const CLIUtils = {
|
|
|
29
29
|
|
|
30
30
|
const logoLines = termWidth >= 95 ? logoWide : logoNarrow;
|
|
31
31
|
const logo = logoLines.map((line) => color.blue(line)).join('\n');
|
|
32
|
-
|
|
32
|
+
// The wordmark supplies "BMad Method", so the lines below read as its
|
|
33
|
+
// tagline, then its positioning, then the company credit.
|
|
34
|
+
const tagline = color.white(' Agile Ai Driven Development');
|
|
35
|
+
const slogan = color.dim(' the agile way to do AiDD');
|
|
36
|
+
const credit = color.dim(' Build More, Architect Dreams · © BMad Code');
|
|
33
37
|
|
|
34
|
-
await prompts.box(`${logo}\n${tagline}`, '', {
|
|
38
|
+
await prompts.box(`${logo}\n${tagline}\n${slogan}\n${credit}`, '', {
|
|
35
39
|
contentAlign: 'center',
|
|
36
40
|
rounded: true,
|
|
37
41
|
formatBorder: color.blue,
|
|
@@ -578,10 +578,6 @@ async function autocomplete(options) {
|
|
|
578
578
|
return result;
|
|
579
579
|
}
|
|
580
580
|
|
|
581
|
-
function hasPathSeparator(value) {
|
|
582
|
-
return value.endsWith('/') || value.endsWith('\\');
|
|
583
|
-
}
|
|
584
|
-
|
|
585
581
|
function expandHome(input) {
|
|
586
582
|
if (!input) return input;
|
|
587
583
|
if (input === '~') return os.homedir();
|
|
@@ -591,91 +587,54 @@ function expandHome(input) {
|
|
|
591
587
|
return input;
|
|
592
588
|
}
|
|
593
589
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
return fs.existsSync(value) && fs.statSync(value).isDirectory();
|
|
601
|
-
} catch {
|
|
602
|
-
return false;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
function listDirectoryOptions(input, options) {
|
|
590
|
+
/**
|
|
591
|
+
* Resolve raw prompt input to an absolute directory path.
|
|
592
|
+
* Mirrors UI.expandUserPath so what the prompt returns matches what the
|
|
593
|
+
* installer later resolves.
|
|
594
|
+
*/
|
|
595
|
+
function resolveDirectoryInput(input, options = {}) {
|
|
607
596
|
const cwd = options.cwd || process.cwd();
|
|
608
|
-
const rawInput = input.trim();
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
const results = [];
|
|
615
|
-
|
|
616
|
-
if (!trailingSep && isExistingDirectory(resolvedInput)) {
|
|
617
|
-
results.push(toDirectoryOption(resolvedInput, `. (use this directory)`));
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
if (isExistingDirectory(browseDir)) {
|
|
621
|
-
try {
|
|
622
|
-
for (const entry of fs.readdirSync(browseDir, { withFileTypes: true })) {
|
|
623
|
-
if (!entry.isDirectory()) continue;
|
|
624
|
-
if (prefix && !entry.name.toLowerCase().startsWith(prefix)) continue;
|
|
625
|
-
const fullPath = path.join(browseDir, entry.name);
|
|
626
|
-
if (!results.some((option) => option.value === fullPath)) {
|
|
627
|
-
results.push(toDirectoryOption(fullPath));
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
} catch {
|
|
631
|
-
// Skip unreadable directories; validation still reports path issues.
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
const validation = options.validate?.(rawInput);
|
|
636
|
-
const hasMatchingOption = results.some((option) => option.value === resolvedInput);
|
|
637
|
-
if (expandedInput && !validation && !hasMatchingOption) {
|
|
638
|
-
results.unshift(toDirectoryOption(resolvedInput, `Create/use: ${resolvedInput}`, true));
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
return results;
|
|
597
|
+
const rawInput = typeof input === 'string' ? input.trim() : '';
|
|
598
|
+
// An empty line means "use the default", which is resolved the same way as
|
|
599
|
+
// typed text so a `~/…` or relative default still returns an absolute path.
|
|
600
|
+
const effective = rawInput || (options.default || '').trim();
|
|
601
|
+
if (!effective) return cwd;
|
|
602
|
+
return path.resolve(cwd, expandHome(effective));
|
|
642
603
|
}
|
|
643
604
|
|
|
644
605
|
/**
|
|
645
|
-
* Directory prompt
|
|
646
|
-
*
|
|
647
|
-
*
|
|
606
|
+
* Directory prompt.
|
|
607
|
+
*
|
|
608
|
+
* A plain text entry: what is on the input line is what gets submitted,
|
|
609
|
+
* resolved to an absolute path.
|
|
610
|
+
*
|
|
611
|
+
* The line is pre-filled with the default (the current working directory,
|
|
612
|
+
* which is where installs usually run from) as real editable text rather than
|
|
613
|
+
* a placeholder, so it can be edited down or extended instead of retyped.
|
|
614
|
+
* Clearing it and pressing Enter still accepts the default.
|
|
615
|
+
*
|
|
648
616
|
* @param {Object} options - Prompt options
|
|
649
617
|
* @param {string} options.message - Prompt message
|
|
650
|
-
* @param {string} [options.default] - Default directory
|
|
651
|
-
* @param {string} [options.placeholder] - Placeholder
|
|
618
|
+
* @param {string} [options.default] - Default directory, pre-filled on the input line
|
|
619
|
+
* @param {string} [options.placeholder] - Placeholder shown only if the line is cleared
|
|
652
620
|
* @param {Function} [options.validate] - Sync validation function
|
|
653
|
-
* @
|
|
621
|
+
* @param {Object} [options.input] - Input stream (defaults to process.stdin; tests inject)
|
|
622
|
+
* @param {Object} [options.output] - Output stream (defaults to process.stdout; tests inject)
|
|
623
|
+
* @returns {Promise<string>} Resolved absolute directory path
|
|
654
624
|
*/
|
|
655
625
|
async function directory(options) {
|
|
656
626
|
const core = await getClackCore();
|
|
657
627
|
const color = await getPicocolors();
|
|
658
|
-
const tabCompletion = {
|
|
659
|
-
prefix: '',
|
|
660
|
-
index: -1,
|
|
661
|
-
options: [],
|
|
662
|
-
lastValue: '',
|
|
663
|
-
};
|
|
664
628
|
|
|
665
|
-
|
|
666
|
-
|
|
629
|
+
const prompt = new core.TextPrompt({
|
|
630
|
+
...(options.input ? { input: options.input } : {}),
|
|
631
|
+
...(options.output ? { output: options.output } : {}),
|
|
667
632
|
initialValue: options.default,
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
validate: (value) => options.validate?.(value ?? prompt.userInput),
|
|
633
|
+
defaultValue: options.default,
|
|
634
|
+
validate: options.validate,
|
|
671
635
|
render() {
|
|
672
|
-
const title = `${color.gray('◆')} ${options.message}`;
|
|
673
636
|
const bar = color.gray('│');
|
|
674
|
-
const barEnd = color.gray('└');
|
|
675
637
|
const userInput = this.userInput;
|
|
676
|
-
const placeholder = options.placeholder || options.default;
|
|
677
|
-
const inputDisplay = userInput ? this.userInputWithCursor : `${color.inverse(color.hidden('_'))}${color.dim(placeholder || '')}`;
|
|
678
|
-
const errorLine = this.state === 'error' ? [`${color.yellow('│')} ${color.yellow(this.error)}`] : [];
|
|
679
638
|
|
|
680
639
|
switch (this.state) {
|
|
681
640
|
case 'submit': {
|
|
@@ -685,42 +644,20 @@ async function directory(options) {
|
|
|
685
644
|
return `${color.gray('◇')} ${options.message}\n${bar} ${color.strikethrough(color.dim(userInput || ''))}`;
|
|
686
645
|
}
|
|
687
646
|
default: {
|
|
688
|
-
|
|
647
|
+
const placeholder = options.placeholder || options.default;
|
|
648
|
+
const inputDisplay = userInput ? this.userInputWithCursor : `${color.inverse(color.hidden('_'))}${color.dim(placeholder || '')}`;
|
|
649
|
+
const lines = [`${color.gray('◆')} ${options.message}`, `${bar} ${inputDisplay}`];
|
|
650
|
+
if (this.state === 'error') lines.push(`${color.yellow('│')} ${color.yellow(this.error)}`);
|
|
651
|
+
lines.push(color.gray('└'));
|
|
652
|
+
return lines.join('\n');
|
|
689
653
|
}
|
|
690
654
|
}
|
|
691
655
|
},
|
|
692
656
|
});
|
|
693
657
|
|
|
694
|
-
const hasSetUserInput = typeof prompt._setUserInput === 'function';
|
|
695
|
-
const hasClearUserInput = typeof prompt._clearUserInput === 'function';
|
|
696
|
-
|
|
697
|
-
prompt.on('key', (_, key) => {
|
|
698
|
-
if (key?.name !== 'tab') return;
|
|
699
|
-
if (!hasSetUserInput) return; // @clack/core API surface changed — skip Tab silently.
|
|
700
|
-
const currentInput = prompt.userInput;
|
|
701
|
-
const isContinuingCycle = tabCompletion.lastValue && currentInput === tabCompletion.lastValue;
|
|
702
|
-
const completionOptions = isContinuingCycle ? tabCompletion.options : prompt.filteredOptions.filter((option) => !option.synthetic);
|
|
703
|
-
if (completionOptions.length === 0) return;
|
|
704
|
-
|
|
705
|
-
if (isContinuingCycle) {
|
|
706
|
-
tabCompletion.index = (tabCompletion.index + 1) % completionOptions.length;
|
|
707
|
-
} else {
|
|
708
|
-
tabCompletion.prefix = currentInput;
|
|
709
|
-
tabCompletion.options = completionOptions;
|
|
710
|
-
tabCompletion.index = 0;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
const focusedOption = completionOptions[tabCompletion.index];
|
|
714
|
-
if (!focusedOption) return;
|
|
715
|
-
const completedValue = focusedOption.value;
|
|
716
|
-
tabCompletion.lastValue = completedValue;
|
|
717
|
-
if (hasClearUserInput) prompt._clearUserInput();
|
|
718
|
-
prompt._setUserInput(completedValue, true);
|
|
719
|
-
});
|
|
720
|
-
|
|
721
658
|
const result = await prompt.prompt();
|
|
722
659
|
await handleCancel(result);
|
|
723
|
-
return result;
|
|
660
|
+
return resolveDirectoryInput(result, options);
|
|
724
661
|
}
|
|
725
662
|
|
|
726
663
|
/**
|
|
@@ -843,6 +780,8 @@ module.exports = {
|
|
|
843
780
|
autocompleteMultiselect,
|
|
844
781
|
autocomplete,
|
|
845
782
|
directory,
|
|
783
|
+
// Exported for tests
|
|
784
|
+
resolveDirectoryInput,
|
|
846
785
|
confirm,
|
|
847
786
|
text,
|
|
848
787
|
password,
|
package/tools/installer/ui.js
CHANGED
|
@@ -110,6 +110,44 @@ async function getModuleVersion(moduleCode, { repoUrl = null, registryDefault =
|
|
|
110
110
|
* UI utilities for the installer
|
|
111
111
|
*/
|
|
112
112
|
class UI {
|
|
113
|
+
/**
|
|
114
|
+
* Warn once for each selected module the registry marks deprecated.
|
|
115
|
+
*
|
|
116
|
+
* A deprecated module is never dropped from the selection — an existing
|
|
117
|
+
* install keeps working and keeps being updated on request. The warning is
|
|
118
|
+
* the only behavior change, and it is what tells CLI users (`--modules`,
|
|
119
|
+
* `--yes`) what the interactive picker shows as an option hint.
|
|
120
|
+
*
|
|
121
|
+
* @param {Array<string>} selectedModules - Module codes about to be installed
|
|
122
|
+
* @returns {Promise<Array<string>>} The deprecated codes that were warned about
|
|
123
|
+
*/
|
|
124
|
+
async _warnDeprecatedModules(selectedModules = []) {
|
|
125
|
+
const externalManager = new ExternalModuleManager();
|
|
126
|
+
let registryModules;
|
|
127
|
+
try {
|
|
128
|
+
registryModules = await externalManager.listAvailable();
|
|
129
|
+
} catch {
|
|
130
|
+
return []; // Registry unreadable — never block an install over a notice.
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const deprecatedByCode = new Map();
|
|
134
|
+
for (const mod of registryModules) {
|
|
135
|
+
if (!mod.deprecated) continue;
|
|
136
|
+
deprecatedByCode.set(mod.code, mod);
|
|
137
|
+
for (const alias of mod.aliases) deprecatedByCode.set(alias, mod);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const warned = [];
|
|
141
|
+
for (const code of selectedModules) {
|
|
142
|
+
const mod = deprecatedByCode.get(code);
|
|
143
|
+
if (!mod || warned.includes(mod.code)) continue;
|
|
144
|
+
warned.push(mod.code);
|
|
145
|
+
const detail = mod.deprecationMessage || 'It is no longer receiving updates.';
|
|
146
|
+
await prompts.log.warn(`${mod.name} (${mod.code}) is deprecated. ${detail}`);
|
|
147
|
+
}
|
|
148
|
+
return warned;
|
|
149
|
+
}
|
|
150
|
+
|
|
113
151
|
async _retainUnavailableInstalledModules(selectedModules, installedModuleIds, bmadDir, options = {}) {
|
|
114
152
|
const { OfficialModules } = require('./modules/official-modules');
|
|
115
153
|
const officialCodes = new Set(['core']);
|
|
@@ -275,6 +313,9 @@ class UI {
|
|
|
275
313
|
|
|
276
314
|
// Handle quick update separately
|
|
277
315
|
if (actionType === 'quick-update') {
|
|
316
|
+
// Quick update never shows the module picker, so this is the only
|
|
317
|
+
// place an existing install of a deprecated module hears about it.
|
|
318
|
+
await this._warnDeprecatedModules(existingInstall.moduleIds || []);
|
|
278
319
|
return {
|
|
279
320
|
actionType: 'quick-update',
|
|
280
321
|
directory: confirmedDirectory,
|
|
@@ -339,6 +380,11 @@ class UI {
|
|
|
339
380
|
);
|
|
340
381
|
}
|
|
341
382
|
|
|
383
|
+
// Surface deprecation notices for whatever ended up selected. The
|
|
384
|
+
// interactive picker only hints at them in the option list, and the
|
|
385
|
+
// --modules / --yes paths never see that list at all.
|
|
386
|
+
await this._warnDeprecatedModules(selectedModules);
|
|
387
|
+
|
|
342
388
|
// For existing installs, resolve per-module update decisions BEFORE
|
|
343
389
|
// we clone anything. Reads the existing manifest's recorded channel
|
|
344
390
|
// per module and prompts the user on available upgrades (patch/minor
|
|
@@ -424,6 +470,8 @@ class UI {
|
|
|
424
470
|
selectedModules.unshift('core');
|
|
425
471
|
}
|
|
426
472
|
|
|
473
|
+
await this._warnDeprecatedModules(selectedModules);
|
|
474
|
+
|
|
427
475
|
// Interactive channel gate: "Ready to install (all stable)? [Y/n]"
|
|
428
476
|
// Only shown for fresh installs with no channel flags and an external module
|
|
429
477
|
// selected. Skipped for prerelease launches because channelOptions.global
|
|
@@ -901,7 +949,7 @@ class UI {
|
|
|
901
949
|
* @param {Set} installedModuleIds - Currently installed module IDs
|
|
902
950
|
* @param {Map<string, string>} installedModuleVersions - Installed module versions from the local manifest
|
|
903
951
|
* @param {Object|null} channelOptions - Parsed installer channel options
|
|
904
|
-
* @returns {Array} Selected module codes
|
|
952
|
+
* @returns {Array} Selected module codes, always including core
|
|
905
953
|
*/
|
|
906
954
|
async selectAllModules(installedModuleIds = new Set(), installedModuleVersions = new Map(), channelOptions = null) {
|
|
907
955
|
// Phase 1: Official modules
|
|
@@ -942,7 +990,6 @@ class UI {
|
|
|
942
990
|
|
|
943
991
|
const allOptions = [];
|
|
944
992
|
const initialValues = [];
|
|
945
|
-
const lockedValues = ['core'];
|
|
946
993
|
|
|
947
994
|
const buildModuleEntry = async (code, name, description, isDefault, repoUrl = null, registryDefault = null) => {
|
|
948
995
|
const isInstalled = installedModuleIds.has(code);
|
|
@@ -959,11 +1006,15 @@ class UI {
|
|
|
959
1006
|
};
|
|
960
1007
|
};
|
|
961
1008
|
|
|
962
|
-
// Add built-in modules first (always available regardless of network)
|
|
1009
|
+
// Add built-in modules first (always available regardless of network).
|
|
1010
|
+
// core is not offered as a row: it is a dependency of every module, always
|
|
1011
|
+
// installed, and was only ever rendered as a locked always-on checkbox.
|
|
1012
|
+
// It is still added back to the result below.
|
|
963
1013
|
const builtInCodes = new Set();
|
|
964
1014
|
for (const mod of builtInModules) {
|
|
965
1015
|
const code = mod.id;
|
|
966
1016
|
builtInCodes.add(code);
|
|
1017
|
+
if (code === 'core') continue;
|
|
967
1018
|
const entry = await buildModuleEntry(code, mod.name, mod.description, mod.defaultSelected);
|
|
968
1019
|
allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint });
|
|
969
1020
|
if (entry.selected) {
|
|
@@ -1018,22 +1069,24 @@ class UI {
|
|
|
1018
1069
|
message: 'Select official modules to install:',
|
|
1019
1070
|
options: allOptions,
|
|
1020
1071
|
initialValues: initialValues.length > 0 ? initialValues : undefined,
|
|
1021
|
-
|
|
1022
|
-
|
|
1072
|
+
// Not required: core is installed either way, so an empty selection is a
|
|
1073
|
+
// legitimate "core only" install rather than a mistake to block on.
|
|
1074
|
+
required: false,
|
|
1023
1075
|
maxItems: allOptions.length,
|
|
1024
1076
|
});
|
|
1025
1077
|
|
|
1026
|
-
const
|
|
1078
|
+
const chosen = selected ? [...selected] : [];
|
|
1027
1079
|
|
|
1028
|
-
if (
|
|
1029
|
-
const moduleLines =
|
|
1080
|
+
if (chosen.length > 0) {
|
|
1081
|
+
const moduleLines = chosen.map((moduleId) => {
|
|
1030
1082
|
const opt = allOptions.find((o) => o.value === moduleId);
|
|
1031
1083
|
return ` \u2022 ${opt?.label || moduleId}`;
|
|
1032
1084
|
});
|
|
1033
1085
|
await prompts.log.message('Selected official modules:\n' + moduleLines.join('\n'));
|
|
1034
1086
|
}
|
|
1035
1087
|
|
|
1036
|
-
|
|
1088
|
+
// core is never shown but always installed.
|
|
1089
|
+
return chosen.includes('core') ? chosen : ['core', ...chosen];
|
|
1037
1090
|
}
|
|
1038
1091
|
|
|
1039
1092
|
/**
|