Compare commits
1 Commits
bc15eee25a
...
d207f3a958
| Author | SHA1 | Date |
|---|---|---|
|
|
d207f3a958 |
|
|
@ -1,70 +0,0 @@
|
|||
---
|
||||
title: "分析阶段:从想法到基础"
|
||||
description: 头脑风暴、调研、产品简报和 PRFAQ 分别是什么——以及何时使用
|
||||
sidebar:
|
||||
order: 1
|
||||
---
|
||||
|
||||
分析阶段(Phase 1)帮助你在决定动手构建之前,把产品想清楚。这个阶段的每个工具都是可选的,但如果完全跳过分析,你的 PRD 就是建立在假设而非洞察之上。
|
||||
|
||||
## 为什么先分析再规划?
|
||||
|
||||
PRD 回答的是"我们应该构建什么、为什么?"如果输入的是模糊的思考,得到的就是模糊的 PRD——而下游的每一份文档都会继承这种模糊。基于薄弱 PRD 搭建的架构会押错技术方向;从薄弱架构派生的 story 会遗漏边界场景。代价是层层叠加的。
|
||||
|
||||
分析工具的作用就是让你的 PRD 变得锐利。它们从不同角度攻击问题——创意探索、市场现实、客户画像、可行性——这样当你坐下来和 PM agent 协作时,你已经清楚要构建什么、为谁构建。
|
||||
|
||||
## 工具介绍
|
||||
|
||||
### 头脑风暴
|
||||
|
||||
**是什么。** 一个使用经过验证的创意技法的引导式创意会议。AI 充当教练,通过结构化练习从你身上引出想法——而不是替你生成想法。
|
||||
|
||||
**为什么在这里。** 原始想法需要发展空间,然后才能被锁定为需求。头脑风暴创造了这个空间。当你有一个问题领域但还没有清晰的解决方案时,或者你想在确定方向之前探索多种可能性时,它尤其有价值。
|
||||
|
||||
**何时使用。** 你对想要构建什么有一个模糊的感觉,但概念尚未结晶。或者你有了概念,但想在备选方案中做压力测试。
|
||||
|
||||
详见[头脑风暴](./brainstorming.md)了解会议的具体运作方式。
|
||||
|
||||
### 调研(市场、领域、技术)
|
||||
|
||||
**是什么。** 三个聚焦的调研工作流,分别调查你的想法的不同维度。市场调研考察竞争对手、趋势和用户情绪;领域调研建立专业知识和术语体系;技术调研评估可行性、架构选项和实现方案。
|
||||
|
||||
**为什么在这里。** 基于假设构建产品是最快做出没人需要的东西的方式。调研让你的概念扎根于现实——已有哪些竞争对手、用户真正的痛点是什么、技术上是否可行、所在行业有哪些特定约束。
|
||||
|
||||
**何时使用。** 你正在进入一个不熟悉的领域,你怀疑竞品存在但还没有做过梳理,或者你的概念依赖于尚未验证的技术能力。可以只做一项、两项或三项全做——每项都是独立的。
|
||||
|
||||
### 产品简报
|
||||
|
||||
**是什么。** 一个引导式发现会议,输出 1-2 页的产品概念执行摘要。AI 充当协作式业务分析师,帮你阐明愿景、目标受众、价值主张和范围。
|
||||
|
||||
**为什么在这里。** 产品简报是进入规划阶段的较温和路径。它以结构化格式捕获你的战略愿景,可以直接输入到 PRD 的创建中。当你已经对概念有了信心——你了解客户、了解问题、大致知道想构建什么时——它效果最好。简报的作用是组织和打磨这些思考。
|
||||
|
||||
**何时使用。** 你的概念相对清晰,希望在创建 PRD 之前高效地记录下来。你对方向有信心,不需要有人来激烈挑战你的假设。
|
||||
|
||||
### PRFAQ(逆向工作法)
|
||||
|
||||
**是什么。** 亚马逊的逆向工作法(Working Backwards),改编为交互式挑战。你在写一行代码之前,先撰写宣布成品的新闻稿,然后回答客户和利益相关者会提出的最刁钻的问题。AI 充当不留情面但有建设性的产品教练。
|
||||
|
||||
**为什么在这里。** PRFAQ 是进入规划阶段的严格路径。它通过让你为每一个论断辩护,来强制实现以客户为中心的清晰度。如果你写不出一篇有说服力的新闻稿,说明产品还没准备好。如果客户 FAQ 的回答暴露了缺口,那些就是你在实现阶段才会——以更高代价——发现的缺口。这道关卡在成本最低的时候暴露薄弱的思考。
|
||||
|
||||
**何时使用。** 你希望在投入资源之前对概念进行压力测试。你不确定用户是否真的在意。你想验证自己能否阐述一个清晰、站得住脚的价值主张。或者你只是想借助逆向工作法的纪律来打磨你的思考。
|
||||
|
||||
## 我该用哪个?
|
||||
|
||||
| 情境 | 推荐工具 |
|
||||
| ---- | -------- |
|
||||
| "我有一个模糊的想法,不知道从哪里开始" | 头脑风暴 |
|
||||
| "我需要先了解市场再做决定" | 调研 |
|
||||
| "我知道要构建什么,只需要记录下来" | 产品简报 |
|
||||
| "我想确认这个想法是否真的值得构建" | PRFAQ |
|
||||
| "我想先探索,再验证,再记录" | 头脑风暴 → 调研 → PRFAQ 或 简报 |
|
||||
|
||||
产品简报和 PRFAQ 都会为 PRD 提供输入——根据你想要多大程度的挑战来选择。简报是协作式发现,PRFAQ 是严格的关卡挑战。两者通往同一个目的地;PRFAQ 检验你的概念是否配得上到达那里。
|
||||
|
||||
:::tip[不确定?]
|
||||
运行 `bmad-help`,描述你的情况。它会根据你已经做了什么、想达成什么来推荐合适的起点。
|
||||
:::
|
||||
|
||||
## 分析之后呢?
|
||||
|
||||
分析阶段的输出直接进入 Phase 2(规划)。PRD 工作流接受产品简报、PRFAQ 文档、调研成果和头脑风暴报告作为输入——它会将你产出的所有内容综合成结构化需求。分析做得越充分,PRD 就越锐利。
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
---
|
||||
title: "检查点预览"
|
||||
description: LLM 辅助的人机协作审查,引导你从目的到细节逐步走过一个变更
|
||||
sidebar:
|
||||
order: 3
|
||||
---
|
||||
|
||||
`bmad-checkpoint-preview` 是一个交互式的、LLM 辅助的人机协作审查工作流。它带你逐步走过一个代码变更——从目的和上下文到细节——让你能做出知情决策:是发布、返工,还是深入挖掘。
|
||||
|
||||

|
||||
|
||||
## 典型流程
|
||||
|
||||
你运行 `bmad-quick-dev`。它澄清你的意图、构建规范、实现变更,完成后将审查线索追加到 spec 文件并在编辑器中打开。你查看 spec,发现这次变更涉及跨多个模块的 20 个文件。
|
||||
|
||||
你可以肉眼扫一遍 diff。但 20 个文件正是肉眼审查开始失效的临界点——你会丢失线索,漏掉两个相距甚远的变更之间的关联,或者批准了自己没有完全理解的东西。所以你改为说 "checkpoint",让 LLM 带你走一遍。
|
||||
|
||||
这种交接——从自主实现回到人工判断——就是核心使用场景。Quick-dev 以最少的监督长时间运行,检查点预览则是你重新掌舵的地方。
|
||||
|
||||
## 为什么需要它
|
||||
|
||||
代码审查有两种失败模式。一种是审查者浏览 diff,什么也没发现,直接批准。另一种是逐文件仔细阅读,但丢失了全局线索——见树不见林。两种模式的结果相同:审查没有抓住真正重要的东西。
|
||||
|
||||
根本问题在于顺序。原始 diff 按文件顺序呈现变更,而这几乎从来不是构建理解的顺序。你先看到一个辅助函数,却不知道它存在的原因;先看到一个 schema 变更,却不了解它支撑什么功能。审查者必须从零散的线索中重建作者的意图,而这个重建过程正是注意力失效的地方。
|
||||
|
||||
检查点预览通过让 LLM 完成重建工作来解决这个问题。它读取 diff、spec(如果有的话)和周围的代码库,然后按照有利于理解的顺序——而不是 `git diff` 的顺序——呈现变更。
|
||||
|
||||
## 工作原理
|
||||
|
||||
工作流分为五个步骤。每一步都建立在前一步的基础上,逐步从"这是什么?"过渡到"我们该不该发布?"
|
||||
|
||||
### 1. 定向
|
||||
|
||||
工作流识别变更来源(来自 PR、commit、分支、spec 文件或当前 git 状态),生成一行意图摘要以及表面积统计:变更文件数、涉及模块数、逻辑行数、边界穿越数和新增公共接口数。
|
||||
|
||||
这是"这是不是我以为的那个东西?"的时刻。在阅读任何代码之前,审查者确认自己看的是正确的东西,并对范围建立预期。
|
||||
|
||||
### 2. 走查
|
||||
|
||||
变更按**关注点**——而非按文件——组织。关注点是内聚的设计意图,例如"输入验证"或"API 契约"。每个关注点附带简短说明——*为什么选择这种方案*,然后列出可点击的 `path:line` 停靠点,审查者可以沿着这些停靠点在代码中导航。
|
||||
|
||||
这是设计判断步骤。审查者评估的是方案对系统是否合理,而不是代码是否正确。关注点按自顶向下排列:最高层意图在前,支撑实现在后。审查者永远不会遇到引用了自己尚未看过的内容。
|
||||
|
||||
### 3. 细节审视
|
||||
|
||||
在审查者理解了设计之后,工作流浮出 2-5 个"出错代价最高"的位置。这些位置按风险类别标记——`[auth]`、`[schema]`、`[billing]`、`[public API]`、`[security]` 等——并按出错后的影响范围排序。
|
||||
|
||||
这不是找 bug。自动化测试和 CI 负责正确性。细节审视激活的是风险意识:"这些是出错成本最高的地方。"如果审查者想在某个领域深入,可以说 "dig into [area]" 来触发一次聚焦正确性的重新审查。
|
||||
|
||||
如果 spec 经过了对抗性审查循环(机器硬化),那些发现也会在这里浮出——不是已修复的 bug,而是审查循环标记出的、审查者应当知晓的决策。
|
||||
|
||||
### 4. 测试
|
||||
|
||||
建议 2-5 种手动观察变更生效的方式。不是自动化测试命令——而是能构建信心、但测试套件无法提供的手动观察。一个可以尝试的 UI 交互、一条可以运行的 CLI 命令、一个可以发送的 API 请求,以及每项的预期结果。
|
||||
|
||||
如果变更没有用户可见的行为,它会明确说明。不发明多余的忙活。
|
||||
|
||||
### 5. 总结
|
||||
|
||||
审查者做出决定:批准、返工或继续讨论。如果批准 PR,工作流可以协助执行 `gh pr review --approve`。如果需要返工,它帮助诊断问题出在方案、spec 还是实现,并帮助起草与具体代码位置关联的可操作反馈。
|
||||
|
||||
## 它是对话,不是报告
|
||||
|
||||
工作流将每一步呈现为起点,而非定论。在步骤之间——或步骤中间——你可以与 LLM 对话、提问、挑战它的框架,或调用其他技能来获取不同视角:
|
||||
|
||||
- **"run advanced elicitation on the error handling"** — 推动 LLM 重新思考并细化对特定领域的分析
|
||||
- **"party mode on whether this schema migration is safe"** — 引入多个 agent 视角进行聚焦辩论
|
||||
- **"run code review"** — 生成包含对抗性和边界场景分析的结构化 agentic 审查报告
|
||||
|
||||
检查点工作流不会把你锁在线性路径上。它在你需要结构时提供结构,在你想探索时让开。五个步骤确保你看到全貌,但每一步深入到什么程度——以及调用什么工具——完全由你决定。
|
||||
|
||||
## 审查线索
|
||||
|
||||
走查步骤在有**建议审查顺序**时效果最好——这是 spec 作者编写的停靠点列表,用于引导审查者走过变更。当 spec 包含此内容时,工作流直接使用它。
|
||||
|
||||
当没有作者提供的线索时,工作流会从 diff 和代码库上下文生成一份。生成的线索质量不如作者编写的,但远好于按文件顺序阅读变更。
|
||||
|
||||
## 何时使用
|
||||
|
||||
主要场景是 `bmad-quick-dev` 的交接:实现完成,spec 文件在编辑器中打开并追加了审查线索,你需要决定是否发布。说 "checkpoint" 即可开始。
|
||||
|
||||
它也可以独立使用:
|
||||
|
||||
- **审查 PR** — 尤其是涉及多个文件或跨模块变更的 PR
|
||||
- **了解一个变更** — 当你需要理解一个不是你写的分支上发生了什么
|
||||
- **Sprint 审查** — 工作流可以提取 sprint 状态文件中标记为 `review` 的 story
|
||||
|
||||
通过说 "checkpoint" 或 "walk me through this change" 来调用。它在任何终端中都能工作,但在 IDE 中——VS Code、Cursor 或类似工具——你会获得更多,因为工作流在每一步都生成 `path:line` 引用。在嵌入 IDE 的终端中,这些引用是可点击的,你可以沿着审查线索在文件间跳转。
|
||||
|
||||
## 它不是什么
|
||||
|
||||
检查点预览不是自动化审查的替代品。它不运行 linter、类型检查器或测试套件。它不打分也不给出通过/不通过的判定。它是一份阅读指南,帮助人类在最重要的地方运用自己的判断力。
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
---
|
||||
title: "安装自定义和社区模块"
|
||||
description: 从社区注册表、Git 仓库或本地路径安装第三方模块
|
||||
sidebar:
|
||||
order: 3
|
||||
---
|
||||
|
||||
使用 BMad 安装程序从社区注册表、第三方 Git 仓库或本地文件路径添加模块。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- 从 BMad 注册表安装社区贡献的模块
|
||||
- 从第三方 Git 仓库安装模块(GitHub、GitLab、Bitbucket、自托管)
|
||||
- 使用 BMad Builder 测试本地开发中的模块
|
||||
- 从私有或自托管 Git 服务器安装模块
|
||||
|
||||
:::note[前置条件]
|
||||
需要 [Node.js](https://nodejs.org) v20+ 和 `npx`(npm 自带)。自定义和社区模块可以在全新安装时选择,也可以添加到现有安装中。
|
||||
:::
|
||||
|
||||
## 社区模块
|
||||
|
||||
社区模块收录在 [BMad 插件市场](https://github.com/bmad-code-org/bmad-plugins-marketplace)。它们按类别组织,并锁定在经过审核的 commit 上以确保安全。
|
||||
|
||||
### 1. 运行安装程序
|
||||
|
||||
```bash
|
||||
npx bmad-method install
|
||||
```
|
||||
|
||||
### 2. 浏览社区目录
|
||||
|
||||
选择官方模块后,安装程序会询问:
|
||||
|
||||
```
|
||||
Would you like to browse community modules?
|
||||
```
|
||||
|
||||
选择 **Yes** 进入目录浏览器。你可以:
|
||||
|
||||
- 按类别浏览
|
||||
- 查看推荐模块
|
||||
- 查看所有可用模块
|
||||
- 按关键词搜索
|
||||
|
||||
### 3. 选择模块
|
||||
|
||||
从任意类别中选取模块。安装程序显示描述、版本和信任等级。已安装的模块会预选以便更新。
|
||||
|
||||
### 4. 继续安装
|
||||
|
||||
选择社区模块后,安装程序将继续到自定义来源,然后是工具/IDE 配置及其余安装流程。
|
||||
|
||||
## 自定义来源(Git URL 和本地路径)
|
||||
|
||||
自定义模块可以来自任何 Git 仓库或本地目录。安装程序会解析来源、分析模块结构,并将其与其他模块一起安装。
|
||||
|
||||
### 交互式安装
|
||||
|
||||
安装过程中,在社区模块步骤之后,安装程序会询问:
|
||||
|
||||
```
|
||||
Would you like to install from a custom source (Git URL or local path)?
|
||||
```
|
||||
|
||||
选择 **Yes**,然后提供来源:
|
||||
|
||||
| 输入类型 | 示例 |
|
||||
| -------- | ---- |
|
||||
| HTTPS URL(任意主机) | `https://github.com/org/repo` |
|
||||
| 带子目录的 HTTPS URL | `https://github.com/org/repo/tree/main/my-module` |
|
||||
| SSH URL | `git@github.com:org/repo.git` |
|
||||
| 本地路径 | `/Users/me/projects/my-module` |
|
||||
| 使用 ~ 的本地路径 | `~/projects/my-module` |
|
||||
|
||||
安装程序会克隆仓库(URL 来源)或直接从磁盘读取(本地路径),然后展示发现的模块供你选择。
|
||||
|
||||
### 非交互式安装
|
||||
|
||||
使用 `--custom-source` 标志从命令行安装自定义模块:
|
||||
|
||||
```bash
|
||||
npx bmad-method install \
|
||||
--directory . \
|
||||
--custom-source /path/to/my-module \
|
||||
--tools claude-code \
|
||||
--yes
|
||||
```
|
||||
|
||||
提供 `--custom-source` 但未指定 `--modules` 时,只安装 core 和自定义模块。要同时包含官方模块,需添加 `--modules`:
|
||||
|
||||
```bash
|
||||
npx bmad-method install \
|
||||
--directory . \
|
||||
--modules bmm \
|
||||
--custom-source https://gitlab.com/myorg/my-module \
|
||||
--tools claude-code \
|
||||
--yes
|
||||
```
|
||||
|
||||
多个来源可用逗号分隔:
|
||||
|
||||
```bash
|
||||
--custom-source /path/one,https://github.com/org/repo,/path/two
|
||||
```
|
||||
|
||||
## 模块发现机制
|
||||
|
||||
安装程序使用两种模式在来源中查找可安装的模块:
|
||||
|
||||
| 模式 | 触发条件 | 行为 |
|
||||
| ---- | -------- | ---- |
|
||||
| 发现模式 | 来源包含 `.claude-plugin/marketplace.json` | 列出清单中的所有插件;你选择要安装哪些 |
|
||||
| 直接模式 | 未找到 marketplace.json | 扫描目录中的 skill(包含 `SKILL.md` 的子目录),作为单个模块解析 |
|
||||
|
||||
发现模式适用于已发布的模块。直接模式适合本地开发时指向 skills 目录。
|
||||
|
||||
:::note[关于 `.claude-plugin/`]
|
||||
`.claude-plugin/marketplace.json` 路径是多个 AI 工具安装程序采用的标准约定,用于插件可发现性。它不依赖 Claude,不使用 Claude API,也不影响你使用哪个 AI 工具。任何包含此文件的模块都可以被遵循此约定的安装程序发现。
|
||||
:::
|
||||
|
||||
## 本地开发工作流
|
||||
|
||||
如果你正在使用 [BMad Builder](https://github.com/bmad-code-org/bmad-builder) 构建模块,可以直接从工作目录安装:
|
||||
|
||||
```bash
|
||||
npx bmad-method install \
|
||||
--directory ~/my-project \
|
||||
--custom-source ~/my-module-repo/skills \
|
||||
--tools claude-code \
|
||||
--yes
|
||||
```
|
||||
|
||||
本地来源通过路径引用,不会复制到缓存。当你更新模块源码并重新安装时,安装程序会获取最新变更。
|
||||
|
||||
:::caution[来源移除]
|
||||
如果你在安装后删除了本地来源目录,`_bmad/` 中已安装的模块文件会保留。在恢复来源路径之前,该模块在更新时会被跳过。
|
||||
:::
|
||||
|
||||
## 安装结果
|
||||
|
||||
安装后,自定义模块与官方模块一起出现在 `_bmad/` 中:
|
||||
|
||||
```
|
||||
your-project/
|
||||
├── _bmad/
|
||||
│ ├── core/ # 内置核心模块
|
||||
│ ├── bmm/ # 官方模块(如已选择)
|
||||
│ ├── my-module/ # 你的自定义模块
|
||||
│ │ ├── my-skill/
|
||||
│ │ │ └── SKILL.md
|
||||
│ │ └── module-help.csv
|
||||
│ └── _config/
|
||||
│ └── manifest.yaml # 跟踪所有模块、版本和来源
|
||||
└── ...
|
||||
```
|
||||
|
||||
manifest 记录每个自定义模块的来源(Git 来源为 `repoUrl`,本地来源为 `localPath`),以便快速更新时能重新定位来源。
|
||||
|
||||
## 更新自定义模块
|
||||
|
||||
自定义模块参与正常的更新流程:
|
||||
|
||||
- **快速更新**(`--action quick-update`):从原始来源刷新所有模块。基于 Git 的模块会重新拉取;本地模块会从来源路径重新读取。
|
||||
- **完整更新**:重新运行模块选择,你可以添加或移除自定义模块。
|
||||
|
||||
## 创建自己的模块
|
||||
|
||||
使用 [BMad Builder](https://github.com/bmad-code-org/bmad-builder) 创建可供他人安装的模块:
|
||||
|
||||
1. 运行 `bmad-module-builder` 搭建模块结构
|
||||
2. 使用各种 BMad Builder 工具添加 skill、agent 和 workflow
|
||||
3. 发布到 Git 仓库或共享文件夹集合
|
||||
4. 他人使用 `--custom-source <your-repo-url>` 安装
|
||||
|
||||
要让模块支持发现模式,请在仓库根目录包含 `.claude-plugin/marketplace.json`(这是跨工具约定,非 Claude 专属)。格式详见 [BMad Builder 文档](https://github.com/bmad-code-org/bmad-builder)。
|
||||
|
||||
:::tip[先在本地测试]
|
||||
开发期间,使用本地路径安装模块以快速迭代,发布到 Git 仓库之前先确认一切正常。
|
||||
:::
|
||||
|
|
@ -70,6 +70,7 @@
|
|||
"chalk": "^4.1.2",
|
||||
"commander": "^14.0.0",
|
||||
"csv-parse": "^6.1.0",
|
||||
"fs-extra": "^11.3.0",
|
||||
"glob": "^11.0.3",
|
||||
"ignore": "^7.0.5",
|
||||
"js-yaml": "^4.1.0",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Step 8: Scoping Exercise - Scope Definition (Phased or Single-Release)
|
||||
# Step 8: Scoping Exercise - MVP & Future Features
|
||||
|
||||
**Progress: Step 8 of 11** - Next: Functional Requirements
|
||||
|
||||
|
|
@ -12,8 +12,6 @@
|
|||
- 📋 YOU ARE A FACILITATOR, not a content generator
|
||||
- 💬 FOCUS on strategic scope decisions that keep projects viable
|
||||
- 🎯 EMPHASIZE lean MVP thinking while preserving long-term vision
|
||||
- ⚠️ NEVER de-scope, defer, or phase out requirements that the user explicitly included in their input documents without asking first
|
||||
- ⚠️ NEVER invent phasing (MVP/Growth/Vision) unless the user requests phased delivery — if input documents define all components as core requirements, they are ALL in scope
|
||||
- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
|
||||
- ✅ YOU MUST ALWAYS WRITE all artifact and document content in `{document_output_language}`
|
||||
|
||||
|
|
@ -36,7 +34,7 @@
|
|||
|
||||
## YOUR TASK:
|
||||
|
||||
Conduct comprehensive scoping exercise to define release boundaries and prioritize features based on the user's chosen delivery mode (phased or single-release).
|
||||
Conduct comprehensive scoping exercise to define MVP boundaries and prioritize features across development phases.
|
||||
|
||||
## SCOPING SEQUENCE:
|
||||
|
||||
|
|
@ -77,41 +75,30 @@ Use structured decision-making for scope:
|
|||
- Advanced functionality that builds on MVP
|
||||
- Ask what features could be added in versions 2, 3, etc.
|
||||
|
||||
**⚠️ SCOPE CHANGE CONFIRMATION GATE:**
|
||||
- If you believe any user-specified requirement should be deferred or de-scoped, you MUST present this to the user and get explicit confirmation BEFORE removing it from scope
|
||||
- Frame it as a recommendation, not a decision: "I'd recommend deferring X because [reason]. Do you agree, or should it stay in scope?"
|
||||
- NEVER silently move user requirements to a later phase or exclude them from MVP
|
||||
- Before creating any consequential phase-based artifacts (e.g., phase tags, labels, or follow-on prompts), present artifact creation as a recommendation and proceed only after explicit user approval
|
||||
|
||||
### 4. Progressive Feature Roadmap
|
||||
|
||||
**CRITICAL: Phasing is NOT automatic. Check the user's input first.**
|
||||
Create phased development approach:
|
||||
- Guide mapping of features across development phases
|
||||
- Structure as Phase 1 (MVP), Phase 2 (Growth), Phase 3 (Vision)
|
||||
- Ensure clear progression and dependencies
|
||||
|
||||
Before proposing any phased approach, review the user's input documents:
|
||||
- Core user value delivery
|
||||
- Essential user journeys
|
||||
- Basic functionality that works reliably
|
||||
|
||||
- **If the input documents define all components as core requirements with no mention of phases:** Present all requirements as a single release scope. Do NOT invent phases or move requirements to fabricated future phases.
|
||||
- **If the input documents explicitly request phased delivery:** Guide mapping of features across the phases the user defined.
|
||||
- **If scope is unclear:** ASK the user whether they want phased delivery or a single release before proceeding.
|
||||
**Phase 2: Growth**
|
||||
|
||||
**When the user requests phased delivery**, guide mapping of features across the phases the user defines:
|
||||
- Additional user types
|
||||
- Enhanced features
|
||||
- Scale improvements
|
||||
|
||||
- Use user-provided phase labels and count; if none are provided, propose a default (e.g., MVP/Growth/Vision) and ask for confirmation
|
||||
- Ensure clear progression and dependencies between phases
|
||||
**Phase 3: Expansion**
|
||||
|
||||
**Each phase should address:**
|
||||
- Advanced capabilities
|
||||
- Platform features
|
||||
- New markets or use cases
|
||||
|
||||
- Core user value delivery and essential journeys for that phase
|
||||
- Clear boundaries on what ships in each phase
|
||||
- Dependencies on prior phases
|
||||
|
||||
**When the user chooses a single release**, define the complete scope:
|
||||
|
||||
- All user-specified requirements are in scope
|
||||
- Focus must-have vs nice-to-have analysis on what ships in this release
|
||||
- Do NOT create phases — use must-have/nice-to-have priority within the single release
|
||||
|
||||
**If phased delivery:** "Where does your current vision fit in this development sequence?"
|
||||
**If single release:** "How does your current vision map to this upcoming release?"
|
||||
**Where does your current vision fit in this development sequence?**"
|
||||
|
||||
### 5. Risk-Based Scoping
|
||||
|
||||
|
|
@ -142,8 +129,6 @@ Prepare comprehensive scoping section:
|
|||
|
||||
#### Content Structure:
|
||||
|
||||
**If user chose phased delivery:**
|
||||
|
||||
```markdown
|
||||
## Project Scoping & Phased Development
|
||||
|
||||
|
|
@ -175,39 +160,11 @@ Prepare comprehensive scoping section:
|
|||
**Resource Risks:** {{contingency_approach}}
|
||||
```
|
||||
|
||||
**If user chose single release (no phasing):**
|
||||
|
||||
```markdown
|
||||
## Project Scoping
|
||||
|
||||
### Strategy & Philosophy
|
||||
|
||||
**Approach:** {{chosen_approach}}
|
||||
**Resource Requirements:** {{team_size_and_skills}}
|
||||
|
||||
### Complete Feature Set
|
||||
|
||||
**Core User Journeys Supported:**
|
||||
{{all_journeys}}
|
||||
|
||||
**Must-Have Capabilities:**
|
||||
{{list_of_must_have_features}}
|
||||
|
||||
**Nice-to-Have Capabilities:**
|
||||
{{list_of_nice_to_have_features}}
|
||||
|
||||
### Risk Mitigation Strategy
|
||||
|
||||
**Technical Risks:** {{mitigation_approach}}
|
||||
**Market Risks:** {{validation_approach}}
|
||||
**Resource Risks:** {{contingency_approach}}
|
||||
```
|
||||
|
||||
### 7. Present MENU OPTIONS
|
||||
|
||||
Present the scoping decisions for review, then display menu:
|
||||
- Show strategic scoping plan (using structure from step 6)
|
||||
- Highlight release boundaries and prioritization (phased roadmap only if phased delivery was selected)
|
||||
- Highlight MVP boundaries and phased roadmap
|
||||
- Ask if they'd like to refine further, get other perspectives, or proceed
|
||||
- Present menu options naturally as part of conversation
|
||||
|
||||
|
|
@ -216,7 +173,7 @@ Display: "**Select:** [A] Advanced Elicitation [P] Party Mode [C] Continue to Fu
|
|||
#### Menu Handling Logic:
|
||||
- IF A: Invoke the `bmad-advanced-elicitation` skill with the current scoping analysis, process the enhanced insights that come back, ask user if they accept the improvements, if yes update content then redisplay menu, if no keep original content then redisplay menu
|
||||
- IF P: Invoke the `bmad-party-mode` skill with the scoping context, process the collaborative insights on MVP and roadmap decisions, ask user if they accept the changes, if yes update content then redisplay menu, if no keep original content then redisplay menu
|
||||
- IF C: Append the final content to {outputFile}, update frontmatter by adding this step name to the end of the stepsCompleted array (also add `releaseMode: phased` or `releaseMode: single-release` to frontmatter based on user's choice), then read fully and follow: ./step-09-functional.md
|
||||
- IF C: Append the final content to {outputFile}, update frontmatter by adding this step name to the end of the stepsCompleted array, then read fully and follow: ./step-09-functional.md
|
||||
- IF Any other: help user respond, then redisplay menu
|
||||
|
||||
#### EXECUTION RULES:
|
||||
|
|
@ -232,9 +189,8 @@ When user selects 'C', append the content directly to the document using the str
|
|||
|
||||
✅ Complete PRD document analyzed for scope implications
|
||||
✅ Strategic MVP approach defined and justified
|
||||
✅ Clear feature boundaries established (phased or single-release, per user preference)
|
||||
✅ All user-specified requirements accounted for — none silently removed or deferred
|
||||
✅ Any scope reduction recommendations presented to user with rationale and explicit confirmation obtained
|
||||
✅ Clear MVP feature boundaries established
|
||||
✅ Phased development roadmap created
|
||||
✅ Key risks identified and mitigation strategies defined
|
||||
✅ User explicitly agrees to scope decisions
|
||||
✅ A/P/C menu presented and handled correctly
|
||||
|
|
@ -246,11 +202,8 @@ When user selects 'C', append the content directly to the document using the str
|
|||
❌ Making scope decisions without strategic rationale
|
||||
❌ Not getting explicit user agreement on MVP boundaries
|
||||
❌ Missing critical risk analysis
|
||||
❌ Not creating clear phased development approach
|
||||
❌ Not presenting A/P/C menu after content generation
|
||||
❌ **CRITICAL**: Silently de-scoping or deferring requirements that the user explicitly included in their input documents
|
||||
❌ **CRITICAL**: Inventing phasing (MVP/Growth/Vision) when the user did not request phased delivery
|
||||
❌ **CRITICAL**: Making consequential scoping decisions (what is in/out of scope) without explicit user confirmation
|
||||
❌ **CRITICAL**: Creating phase-based artifacts (tags, labels, follow-on prompts) without explicit user approval
|
||||
|
||||
❌ **CRITICAL**: Reading only partial step file - leads to incomplete understanding and poor decisions
|
||||
❌ **CRITICAL**: Proceeding with 'C' without fully reading and understanding the next step file
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ Make targeted improvements:
|
|||
- All user success criteria
|
||||
- All functional requirements (capability contract)
|
||||
- All user journey narratives
|
||||
- All scope decisions (whether phased or single-release), including consent-critical evidence (explicit user confirmations and rationales for any scope changes from step 8)
|
||||
- All scope decisions (MVP, Growth, Vision)
|
||||
- All non-functional requirements
|
||||
- Product differentiator and vision
|
||||
- Domain-specific requirements
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
const path = require('node:path');
|
||||
const os = require('node:os');
|
||||
const fs = require('../tools/installer/fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const { Installer } = require('../tools/installer/core/installer');
|
||||
const { ManifestGenerator } = require('../tools/installer/core/manifest-generator');
|
||||
const { OfficialModules } = require('../tools/installer/modules/official-modules');
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module.exports = {
|
|||
const { bmadDir } = await installer.findBmadDir(projectDir);
|
||||
|
||||
// Check if bmad directory exists
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
if (!(await fs.pathExists(bmadDir))) {
|
||||
await prompts.log.warn('No BMAD installation found in the current directory.');
|
||||
await prompts.log.message(`Expected location: ${bmadDir}`);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const prompts = require('../prompts');
|
||||
const { Installer } = require('../core/installer');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const yaml = require('yaml');
|
||||
const { Manifest } = require('./manifest');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const { getProjectRoot } = require('../project-root');
|
||||
const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const { Manifest } = require('./manifest');
|
||||
const { OfficialModules } = require('../modules/official-modules');
|
||||
const { IdeManager } = require('../ide/manager');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const yaml = require('yaml');
|
||||
const crypto = require('node:crypto');
|
||||
const csv = require('csv-parse/sync');
|
||||
|
|
@ -193,13 +193,11 @@ class ManifestGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
// Recurse into subdirectories — but not inside a discovered skill
|
||||
if (!skillMeta) {
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
if (entry.name.startsWith('.') || entry.name.startsWith('_')) continue;
|
||||
await walk(path.join(dir, entry.name));
|
||||
}
|
||||
// Recurse into subdirectories
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
if (entry.name.startsWith('.') || entry.name.startsWith('_')) continue;
|
||||
await walk(path.join(dir, entry.name));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const crypto = require('node:crypto');
|
||||
const { getProjectRoot } = require('../project-root');
|
||||
const prompts = require('../prompts');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const fs = require('./fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('node:path');
|
||||
const crypto = require('node:crypto');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
// Drop-in replacement for fs-extra using native node:fs APIs.
|
||||
// Eliminates graceful-fs monkey-patching that causes non-deterministic
|
||||
// file loss during multi-module installs on macOS (issue #1779).
|
||||
const fsp = require('node:fs/promises');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
async function pathExists(p) {
|
||||
try {
|
||||
await fsp.access(p);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureDir(dir) {
|
||||
await fsp.mkdir(dir, { recursive: true });
|
||||
}
|
||||
|
||||
async function remove(p) {
|
||||
await fsp.rm(p, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
async function copy(src, dest, options = {}) {
|
||||
const filterFn = options.filter;
|
||||
const overwrite = options.overwrite !== false;
|
||||
const srcStat = await fsp.stat(src);
|
||||
|
||||
if (srcStat.isFile()) {
|
||||
if (filterFn && !(await filterFn(src, dest))) return;
|
||||
await fsp.mkdir(path.dirname(dest), { recursive: true });
|
||||
if (!overwrite) {
|
||||
try {
|
||||
await fsp.access(dest);
|
||||
if (options.errorOnExist) throw new Error(`${dest} already exists`);
|
||||
return;
|
||||
} catch (error) {
|
||||
if (error.message.includes('already exists')) throw error;
|
||||
}
|
||||
}
|
||||
await fsp.copyFile(src, dest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcStat.isDirectory()) {
|
||||
if (filterFn && !(await filterFn(src, dest))) return;
|
||||
await fsp.mkdir(dest, { recursive: true });
|
||||
const entries = await fsp.readdir(src, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
await copy(path.join(src, entry.name), path.join(dest, entry.name), options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function move(src, dest) {
|
||||
try {
|
||||
await fsp.rename(src, dest);
|
||||
} catch (error) {
|
||||
if (error.code === 'EXDEV') {
|
||||
await copy(src, dest);
|
||||
await fsp.rm(src, { recursive: true, force: true });
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readJsonSync(p) {
|
||||
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
||||
}
|
||||
|
||||
async function writeJson(p, data, options = {}) {
|
||||
const spaces = options.spaces ?? 2;
|
||||
await fsp.writeFile(p, JSON.stringify(data, null, spaces) + '\n', 'utf8');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// Native async (node:fs/promises)
|
||||
readFile: fsp.readFile,
|
||||
writeFile: fsp.writeFile,
|
||||
stat: fsp.stat,
|
||||
readdir: fsp.readdir,
|
||||
access: fsp.access,
|
||||
realpath: fsp.realpath,
|
||||
rename: fsp.rename,
|
||||
rmdir: fsp.rmdir,
|
||||
unlink: fsp.unlink,
|
||||
chmod: fsp.chmod,
|
||||
mkdir: fsp.mkdir,
|
||||
mkdtemp: fsp.mkdtemp,
|
||||
copyFile: fsp.copyFile,
|
||||
rm: fsp.rm,
|
||||
|
||||
// fs-extra compatible helpers (native implementations)
|
||||
pathExists,
|
||||
ensureDir,
|
||||
remove,
|
||||
copy,
|
||||
move,
|
||||
readJsonSync,
|
||||
writeJson,
|
||||
|
||||
// Sync methods from core node:fs
|
||||
existsSync: fs.existsSync.bind(fs),
|
||||
readFileSync: fs.readFileSync.bind(fs),
|
||||
writeFileSync: fs.writeFileSync.bind(fs),
|
||||
statSync: fs.statSync.bind(fs),
|
||||
accessSync: fs.accessSync.bind(fs),
|
||||
readdirSync: fs.readdirSync.bind(fs),
|
||||
createReadStream: fs.createReadStream.bind(fs),
|
||||
pathExistsSync: fs.existsSync.bind(fs),
|
||||
|
||||
// Constants
|
||||
constants: fs.constants,
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const yaml = require('yaml');
|
||||
const prompts = require('../prompts');
|
||||
const csv = require('csv-parse/sync');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('node:path');
|
||||
const yaml = require('yaml');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const yaml = require('yaml');
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const fs = require('./fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('node:path');
|
||||
const yaml = require('yaml');
|
||||
const prompts = require('./prompts');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { execSync } = require('node:child_process');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { execSync } = require('node:child_process');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { execSync } = require('node:child_process');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const yaml = require('yaml');
|
||||
const prompts = require('../prompts');
|
||||
const { getProjectRoot, getSourcePath, getModulePath } = require('../project-root');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const fs = require('../fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('node:path');
|
||||
const yaml = require('yaml');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('node:path');
|
||||
const fs = require('./fs-native');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
/**
|
||||
* Find the BMAD project root directory by looking for package.json
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const path = require('node:path');
|
||||
const os = require('node:os');
|
||||
const fs = require('./fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const { CLIUtils } = require('./cli-utils');
|
||||
const { ExternalModuleManager } = require('./modules/external-manager');
|
||||
const { getProjectRoot } = require('./project-root');
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* This should be run once to update existing installations
|
||||
*/
|
||||
|
||||
const fs = require('./installer/fs-native');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('node:path');
|
||||
const yaml = require('yaml');
|
||||
const chalk = require('chalk');
|
||||
|
|
|
|||
Loading…
Reference in New Issue