diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 6f4f0e0c0..53956dcbd 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -19,7 +19,6 @@ }, "skills": [ "./src/core-skills/bmad-help", - "./src/core-skills/bmad-init", "./src/core-skills/bmad-brainstorming", "./src/core-skills/bmad-distillator", "./src/core-skills/bmad-party-mode", @@ -60,9 +59,6 @@ "./src/bmm-skills/3-solutioning/bmad-create-epics-and-stories", "./src/bmm-skills/3-solutioning/bmad-generate-project-context", "./src/bmm-skills/4-implementation/bmad-agent-dev", - "./src/bmm-skills/4-implementation/bmad-agent-sm", - "./src/bmm-skills/4-implementation/bmad-agent-qa", - "./src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev", "./src/bmm-skills/4-implementation/bmad-dev-story", "./src/bmm-skills/4-implementation/bmad-quick-dev", "./src/bmm-skills/4-implementation/bmad-sprint-planning", diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 63c797803..0079a5e81 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -5,7 +5,7 @@ on: branches: [main] paths: - "src/**" - - "tools/cli/**" + - "tools/installer/**" - "package.json" workflow_dispatch: inputs: diff --git a/CHANGELOG.md b/CHANGELOG.md index 391f809c8..b67ee2f62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,56 @@ # Changelog +## v6.3.0 - 2026-04-09 + +### 💥 Breaking Changes + +* Remove custom content installation feature; use marketplace-based plugin installation instead (#2227) +* Remove bmad-init skill; all agents and skills now load config directly from `{project-root}/_bmad/bmm/config.yaml` (#2159) +* Remove spec-wip.md singleton; quick-dev now writes directly to `spec-{slug}.md` with status field, enabling parallel sessions (#2214) +* Consolidate three agent personas into Developer agent (Amelia): remove Barry quick-flow-solo-dev (#2177), Quinn QA agent (#2179), and Bob Scrum Master agent (#2186) + +### 🎁 Features + +* Universal source support for custom module installs with 5-strategy PluginResolver cascade supporting any Git host (GitHub, GitLab, Bitbucket, self-hosted) and local file paths (#2233) +* Community module browser with three-tier selection: official, community (category drill-down from marketplace index), and custom URL with unverified source warning (#2229) +* Switch module source of truth from bundled config to remote marketplace registry with network-failure fallback (#2228) +* Add bmad-prfaq skill implementing Amazon's Working Backwards methodology as alternative Phase 1 analysis path with 5-stage coached workflow and subagent architecture (#2157) +* Add bmad-checkpoint-preview skill for guided, concern-ordered human review of commits, branches, or PRs (#2145) +* Epic context compilation for quick-dev step-01: sub-agent compiles planning docs into cached `epic-{N}-context.md` for story implementation (#2218) +* Previous story continuity in quick-dev: load completed spec from same epic as implementation context (#2201) +* Planning artifact awareness in quick-dev: selectively load PRD, architecture, UX, and epics docs for context-informed specs (#2185) +* One-shot route now generates lightweight spec trace file for consistent artifact tracking (#2121) +* Improve checkpoint-preview UX with clickable spec paths, external edit detection, and missing-file halt (#2217) +* Add Junie (JetBrains AI) platform support (#2142) +* Restore KiloCoder support with native-skills installation (#2151) +* Add bmad-help support for llms.txt general questions (#2230) + +### ♻️ Refactoring + +* Consolidate party-mode into single SKILL.md with real subagent spawning via Agent tool, replacing multi-file workflow architecture (#2160) + +### 🐛 Bug Fixes + +* Fix version display bug where marketplace.json walk-up reported wrong version (#2233) +* Fix checkpoint-preview step-05 advancing without user confirmation by adding explicit HALT (#2184) +* Address adversarial triage findings: clarify review_mode transitions, label walkthrough branches, fix terse commit handling (#2180) +* Preserve local custom module sources during quick update (#2172) +* Support skills/ folder as fallback module source location for bmb compatibility (#2149) + +### 🔧 Maintenance + +* Overhaul installer branding with responsive BMAD METHOD logo, blue color scheme, unified version sourcing from marketplace.json, and surgical manifest-based skill cleanup (#2223) +* Stop copying skill prompts to _bmad by default (#2182) +* Add Python 3.10+ and uv as documented prerequisites (#2221) + +### 📚 Documentation + +* Complete Czech (cs-CZ) documentation translation (#2134) +* Complete Vietnamese (vi-VN) documentation translation (#2110, #2192) +* Rewrite get-answers-about-bmad as 1-2-3 escalation flow, remove deprecated references (#2213) +* Add checkpoint-preview explainer page and workflow diagram (#2183) +* Update docs theme to match bmadcode.com with responsive logo and blue color scheme (#2176) + ## v6.2.2 - 2026-03-25 ### ♻️ Refactoring diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 362d638e3..5f2b59b3d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,12 @@ Thank you for considering contributing! We believe in **Human Amplification, Not --- +> **Before you write code: talk to us on [Discord](https://discord.gg/gk8jAdXWmj).** +> +> If your change adds features, restructures code, or touches more than a couple of files, **confirm with a maintainer that it fits**. A large PR out of the blue has a high chance of being closed — regardless of effort invested. A five-minute conversation can save you hours. + +--- + ## Our Philosophy BMad strengthens human-AI collaboration through specialized agents and guided workflows. Every contribution should answer: **"Does this make humans and AI better together?"** @@ -57,15 +63,10 @@ After searching, use the [feature request template](https://github.com/bmad-code ## Before Starting Work -⚠️ **Required before submitting PRs:** - -| Work Type | Requirement | -| ------------- | ---------------------------------------------- | -| Bug fix | An open issue (create one if it doesn't exist) | -| Feature | An open feature request issue | -| Large changes | Discussion via issue first | - -**Why?** This prevents wasted effort on work that may not align with project direction. +| Work Type | Requirement | +| ----------------------- | -------------------------------------------------------- | +| Typo / small bug fix | Just open the PR | +| Feature or large change | Confirm with a maintainer on Discord **before** you start | --- @@ -83,6 +84,12 @@ Submit PRs to the `main` branch. We use trunk-based development. Every push to ` If your change exceeds 800 lines, break it into smaller PRs that can be reviewed independently. +### AI-Generated Code + +Given the nature of this project, we expect most contributions involve AI assistance — that's fine. What we require is **heavy human curation**. You must understand every line you're submitting, have made deliberate choices about what to include, and be able to explain your reasoning. + +We will reject PRs that read like raw LLM output: bulk refactors nobody asked for, unsolicited "improvements" across many files, or changes where the submitter clearly hasn't read the existing code. Using AI to write code is normal here; using AI as a substitute for thinking is not. + ### New to Pull Requests? 1. **Fork** the repository diff --git a/README.md b/README.md index d76519c97..c9fb503e2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![Version](https://img.shields.io/npm/v/bmad-method?color=blue&label=version)](https://www.npmjs.com/package/bmad-method) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org) +[![Python Version](https://img.shields.io/badge/python-%3E%3D3.10-blue?logo=python&logoColor=white)](https://www.python.org) +[![uv](https://img.shields.io/badge/uv-package%20manager-blueviolet?logo=uv)](https://docs.astral.sh/uv/) [![Discord](https://img.shields.io/badge/Discord-Join%20Community-7289da?logo=discord&logoColor=white)](https://discord.gg/gk8jAdXWmj) **Build More Architect Dreams** — An AI-driven agile development module for the BMad Method Module Ecosystem, the best and most comprehensive Agile AI Driven Development framework that has true scale-adaptive intelligence that adjusts from bug fixes to enterprise systems. @@ -16,7 +18,7 @@ Traditional AI tools do the thinking for you, producing average results. BMad ag - **AI Intelligent Help** — Invoke the `bmad-help` skill anytime for guidance on what's next - **Scale-Domain-Adaptive** — Automatically adjusts planning depth based on project complexity - **Structured Workflows** — Grounded in agile best practices across analysis, planning, architecture, and implementation -- **Specialized Agents** — 12+ domain experts (PM, Architect, Developer, UX, Scrum Master, and more) +- **Specialized Agents** — 12+ domain experts (PM, Architect, Developer, UX, and more) - **Party Mode** — Bring multiple agent personas into one session to collaborate and discuss - **Complete Lifecycle** — From brainstorming to deployment @@ -34,7 +36,7 @@ Traditional AI tools do the thinking for you, producing average results. BMad ag ## Quick Start -**Prerequisites**: [Node.js](https://nodejs.org) v20+ +**Prerequisites**: [Node.js](https://nodejs.org) v20+ · [Python](https://www.python.org) 3.10+ · [uv](https://docs.astral.sh/uv/) ```bash npx bmad-method install @@ -79,18 +81,15 @@ BMad Method extends with official modules for specialized domains. Available dur ## Community - [Discord](https://discord.gg/gk8jAdXWmj) — Get help, share ideas, collaborate -- [Subscribe on YouTube](https://www.youtube.com/@BMadCode) — Tutorials, master class, and podcast (launching Feb 2025) +- [YouTube](https://youtube.com/@BMadCode) — Tutorials, master class, and more +- [X / Twitter](https://x.com/BMadCode) +- [Website](https://bmadcode.com) - [GitHub Issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) — Bug reports and feature requests - [Discussions](https://github.com/bmad-code-org/BMAD-METHOD/discussions) — Community conversations ## Support BMad -BMad is free for everyone — and always will be. If you'd like to support development: - -- ⭐ Please click the star project icon near the top right of this page -- ☕ [Buy Me a Coffee](https://buymeacoffee.com/bmad) — Fuel the development -- 🏢 Corporate sponsorship — DM on Discord -- 🎤 Speaking & Media — Available for conferences, podcasts, interviews (BM on Discord) +BMad is free for everyone and always will be. Star this repo, [buy me a coffee](https://buymeacoffee.com/bmad), or email for corporate sponsorship. ## Contributing diff --git a/README_CN.md b/README_CN.md index a939a0c7b..ec9ba0a01 100644 --- a/README_CN.md +++ b/README_CN.md @@ -16,7 +16,7 @@ - **AI 智能引导** —— 随时调用 `bmad-help` 获取下一步建议 - **规模与领域自适应** —— 按项目复杂度自动调整规划深度 - **结构化工作流** —— 覆盖分析、规划、架构、实施全流程 -- **专业角色智能体** —— 提供 PM、架构师、开发者、UX、Scrum Master 等 12+ 角色 +- **专业角色智能体** —— 提供 PM、架构师、开发者、UX 等 12+ 角色 - **派对模式** —— 多个智能体可在同一会话协作讨论 - **完整生命周期** —— 从头脑风暴一路到交付上线 diff --git a/README_VN.md b/README_VN.md new file mode 100644 index 000000000..14cd5c88e --- /dev/null +++ b/README_VN.md @@ -0,0 +1,109 @@ +![BMad Method](banner-bmad-method.png) + +[![Version](https://img.shields.io/npm/v/bmad-method?color=blue&label=version)](https://www.npmjs.com/package/bmad-method) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) +[![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org) +[![Python Version](https://img.shields.io/badge/python-%3E%3D3.10-blue?logo=python&logoColor=white)](https://www.python.org) +[![uv](https://img.shields.io/badge/uv-package%20manager-blueviolet?logo=uv)](https://docs.astral.sh/uv/) +[![Discord](https://img.shields.io/badge/Discord-Join%20Community-7289da?logo=discord&logoColor=white)](https://discord.gg/gk8jAdXWmj) + +[English](README.md) | [简体中文](README_CN.md) | Tiếng Việt + +**Build More Architect Dreams** - một mô-đun khung phát triển hướng AI trong hệ sinh thái BMad, có khả năng thích ứng theo quy mô từ sửa lỗi nhỏ đến các hệ thống doanh nghiệp. + +**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. + +## Vì sao chọn BMad Method? + +Các công cụ AI truyền thống thường làm thay phần suy nghĩ của bạn và tạo ra kết quả ở mức trung bình. Các agent chuyên biệt và quy trình làm việc có hướng dẫn của BMad hoạt động như những cộng tác viên chuyên gia, dẫn dắt bạn qua một quy trình có cấu trúc để khai mở tư duy tốt nhất của bạn cùng với AI. + +- **Trợ giúp AI thông minh** - Gọi skill `bmad-help` bất kỳ lúc nào để biết bước tiếp theo +- **Thích ứng theo quy mô và miền bài toán** - Tự động điều chỉnh độ sâu lập kế hoạch theo độ phức tạp của dự án +- **Quy trình có cấu trúc** - Dựa trên các thực hành tốt nhất của agile xuyên suốt phân tích, lập kế hoạch, kiến trúc và triển khai +- **Agent chuyên biệt** - Hơn 12 chuyên gia theo vai trò như PM, Architect, Developer, UX, Scrum Master và nhiều vai trò khác +- **Party Mode** - Đưa nhiều persona agent vào cùng một phiên để cộng tác và thảo luận +- **Vòng đời hoàn chỉnh** - Từ động não ý tưởng cho đến triển khai + +[Tìm hiểu thêm tại **docs.bmad-method.org**](https://docs.bmad-method.org/vi-vn/) + +--- + +## 🚀 Điều gì tiếp theo cho BMad? + +**V6 đã có mặt và đây mới chỉ là khởi đầu!** BMad Method đang phát triển rất nhanh với các cải tiến như đội agent đa nền tảng và tích hợp sub-agent, kiến trúc Skills, BMad Builder v1, tự động hóa vòng lặp phát triển và nhiều thứ khác vẫn đang được xây dựng. + +**[📍 Xem lộ trình đầy đủ →](https://docs.bmad-method.org/vi-vn/roadmap/)** + +--- + +## Bắt đầu nhanh + +**Điều kiện tiên quyết**: [Node.js](https://nodejs.org) v20+ · [Python](https://www.python.org) 3.10+ · [uv](https://docs.astral.sh/uv/) + +```bash +npx bmad-method install +``` + +> Muốn dùng bản prerelease mới nhất? Hãy dùng `npx bmad-method@next install`. Hãy kỳ vọng mức độ biến động cao hơn bản cài đặt mặc định. + +Làm theo các lời nhắc của trình cài đặt, sau đó mở AI IDE của bạn như Claude Code hoặc Cursor trong thư mục dự án. + +**Cài đặt không tương tác** (cho CI/CD): + +```bash +npx bmad-method install --directory /path/to/project --modules bmm --tools claude-code --yes +``` + +[Xem toàn bộ tùy chọn cài đặt](https://docs.bmad-method.org/vi-vn/how-to/non-interactive-installation/) + +> **Chưa chắc nên làm gì?** Hãy hỏi `bmad-help` - nó sẽ cho bạn biết chính xác bước nào tiếp theo và bước nào là tùy chọn. Bạn cũng có thể hỏi kiểu như `bmad-help Tôi vừa hoàn thành phần kiến trúc, tiếp theo tôi cần làm gì?` + +## Mô-đun + +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 đó. + +| Module | Mục đích | +| ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | +| **[BMad Method (BMM)](https://github.com/bmad-code-org/BMAD-METHOD)** | Khung lõi với hơn 34 quy trình | +| **[BMad Builder (BMB)](https://github.com/bmad-code-org/bmad-builder)** | Tạo agent và quy trình BMad tùy chỉnh | +| **[Test Architect (TEA)](https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise)** | Chiến lược kiểm thử và tự động hóa dựa trên rủi ro | +| **[Game Dev Studio (BMGD)](https://github.com/bmad-code-org/bmad-module-game-dev-studio)** | Quy trình phát triển game (Unity, Unreal, Godot) | +| **[Creative Intelligence Suite (CIS)](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite)** | Đổi mới, động não ý tưởng, tư duy thiết kế | + +## Tài liệu + +[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 + +**Liên kết nhanh:** +- [Hướng dẫn bắt đầu](https://docs.bmad-method.org/vi-vn/tutorials/getting-started/) +- [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/) +- [Tài liệu Test Architect](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/) + +## Cộng đồng + +- [Discord](https://discord.gg/gk8jAdXWmj) - Nhận trợ giúp, chia sẻ ý tưởng, cộng tác +- [YouTube](https://youtube.com/@BMadCode) - Video hướng dẫn, master class và nhiều nội dung khác +- [X / Twitter](https://x.com/BMadCode) +- [Website](https://bmadcode.com) +- [GitHub Issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) - Báo lỗi và yêu cầu tính năng +- [Discussions](https://github.com/bmad-code-org/BMAD-METHOD/discussions) - Trao đổi cộng đồng + +## Hỗ trợ BMad + +BMad miễn phí cho tất cả mọi người và sẽ luôn như vậy. Hãy nhấn sao cho repo này, [mời tôi một ly cà phê](https://buymeacoffee.com/bmad), hoặc gửi email tới nếu bạn muốn tài trợ doanh nghiệp. + +## Đóng góp + +Chúng tôi luôn chào đón đóng góp. Xem [CONTRIBUTING.md](CONTRIBUTING.md) để biết hướng dẫn. + +## Giấy phép + +Giấy phép MIT - xem [LICENSE](LICENSE) để biết chi tiết. + +--- + +**BMad** và **BMAD-METHOD** là các nhãn hiệu của BMad Code, LLC. Xem [TRADEMARK.md](TRADEMARK.md) để biết chi tiết. + +[![Contributors](https://contrib.rocks/image?repo=bmad-code-org/BMAD-METHOD)](https://github.com/bmad-code-org/BMAD-METHOD/graphs/contributors) + +Xem [CONTRIBUTORS.md](CONTRIBUTORS.md) để biết thông tin về những người đóng góp. \ No newline at end of file diff --git a/docs/_STYLE_GUIDE.md b/docs/_STYLE_GUIDE.md index d23e93114..ea2335ed4 100644 --- a/docs/_STYLE_GUIDE.md +++ b/docs/_STYLE_GUIDE.md @@ -353,7 +353,7 @@ Only for BMad Method and Enterprise tracks. Quick Flow skips to implementation. ### Can I change my plan later? -Yes. The SM agent has a `bmad-correct-course` workflow for handling scope changes. +Yes. The `bmad-correct-course` workflow handles scope changes mid-implementation. **Have a question not answered here?** [Open an issue](...) or ask in [Discord](...). ``` diff --git a/docs/cs/404.md b/docs/cs/404.md new file mode 100644 index 000000000..74ba6c89b --- /dev/null +++ b/docs/cs/404.md @@ -0,0 +1,8 @@ +--- +title: Stránka nenalezena +template: splash +--- + +Stránka, kterou hledáte, neexistuje nebo byla přesunuta. + +[Zpět na úvodní stránku](/cs/index.md) diff --git a/docs/cs/_STYLE_GUIDE.md b/docs/cs/_STYLE_GUIDE.md new file mode 100644 index 000000000..3cdd71871 --- /dev/null +++ b/docs/cs/_STYLE_GUIDE.md @@ -0,0 +1,370 @@ +--- +title: "Průvodce stylem dokumentace" +description: Projektově specifické konvence dokumentace založené na stylu Google a struktuře Diataxis +--- + +Tento projekt se řídí [Google Developer Documentation Style Guide](https://developers.google.com/style) a používá [Diataxis](https://diataxis.fr/) pro strukturování obsahu. Následují pouze projektově specifické konvence. + +## Projektově specifická pravidla + +| Pravidlo | Specifikace | +| -------------------------------------- | ---------------------------------------- | +| Žádné horizontální čáry (`---`) | Narušují plynulost čtení | +| Žádné nadpisy `####` | Místo toho použijte tučný text nebo admonitions | +| Žádné sekce „Souvisejí“ nebo „Další:“ | Navigaci zajišťuje postranní panel | +| Žádné hluboce vnořené seznamy | Místo toho rozdělejte do sekcí | +| Žádné bloky kódu pro nekód | Pro příklady dialogů použijte admonitions | +| Žádné tučné odstavce pro upozornění | Místo toho použijte admonitions | +| Max 1–2 admonitions na sekci | Tutoriály povolují 3–4 na hlavní sekci | +| Buňky tabulek / položky seznamů | Max 1–2 věty | +| Rozpočet nadpisů | 8–12 `##` na dokument; 2–3 `###` na sekci | + +## Admonitions (syntaxe Starlight) + +```md +:::tip[Název] +Zkratky, osvědčené postupy +::: + +:::note[Název] +Kontext, definice, příklady, předpoklady +::: + +:::caution[Název] +Upozornění, potenciální problémy +::: + +:::danger[Název] +Pouze kritická varování — ztráta dat, bezpečnostní problémy +::: +``` + +### Standardní použití + +| Admonition | Použití pro | +| ------------------------ | ----------------------------- | +| `:::note[Předpoklady]` | Závislosti před začátkem | +| `:::tip[Rychlá cesta]` | TL;DR shrnutí na začátku dokumentu | +| `:::caution[Důležité]` | Kritická upozornění | +| `:::note[Příklad]` | Příklady příkazů/odpovědí | + +## Standardní formáty tabulek + +**Fáze:** + +```md +| Fáze | Název | Co se děje | +| ---- | -------- | -------------------------------------------- | +| 1 | Analýza | Brainstorming, průzkum *(volitelné)* | +| 2 | Plánování | Požadavky — PRD nebo specifikace *(povinné)* | +``` + +**Skills:** + +```md +| Skill | Agent | Účel | +| -------------------- | ------- | ------------------------------------ | +| `bmad-brainstorming` | Analytik | Brainstorming nového projektu | +| `bmad-create-prd` | PM | Vytvoření dokumentu požadavků (PRD) | +``` + +## Bloky struktury složek + +Zobrazujte v sekcích „Co jste dosáhli“: + +````md +``` +váš-projekt/ +├── _bmad/ # Konfigurace BMad +├── _bmad-output/ +│ ├── planning-artifacts/ +│ │ └── PRD.md # Váš dokument požadavků +│ ├── implementation-artifacts/ +│ └── project-context.md # Pravidla implementace (volitelné) +└── ... +``` +```` + +## Struktura tutoriálu + +```text +1. Název + Háček (1–2 věty popisující výsledek) +2. Upozornění na verzi/modul (info nebo warning admonition) (volitelné) +3. Co se naučíte (odrážkový seznam výsledků) +4. Předpoklady (info admonition) +5. Rychlá cesta (tip admonition – TL;DR shrnutí) +6. Pochopení [Tématu] (kontext před kroky – tabulky pro fáze/agenty) +7. Instalace (volitelné) +8. Krok 1: [První hlavní úkol] +9. Krok 2: [Druhý hlavní úkol] +10. Krok 3: [Třetí hlavní úkol] +11. Co jste dosáhli (shrnutí + struktura složek) +12. Rychlý přehled (tabulka skills) +13. Časté otázky (formát FAQ) +14. Získání pomoci (komunitní odkazy) +15. Klíčové poznatky (tip admonition) +``` + +### Kontrolní seznam tutoriálu + +- [ ] Háček popisuje výsledek v 1–2 větách +- [ ] Sekce „Co se naučíte“ je přítomna +- [ ] Předpoklady v admonition +- [ ] Rychlá cesta TL;DR admonition nahoře +- [ ] Tabulky pro fáze, skills, agenty +- [ ] Sekce „Co jste dosáhli“ je přítomna +- [ ] Tabulka rychlého přehledu je přítomna +- [ ] Sekce častých otázek je přítomna +- [ ] Sekce získání pomoci je přítomna +- [ ] Klíčové poznatky admonition na konci + +## Struktura praktického návodu + +```text +1. Název + Háček (jedna věta: „Použijte workflow `X` k...“) +2. Kdy to použít (odrážkový seznam scénářů) +3. Kdy to přeskočit (volitelné) +4. Předpoklady (note admonition) +5. Kroky (číslované ### podsekce) +6. Co získáte (výstup/vytvořené artefakty) +7. Příklad (volitelné) +8. Tipy (volitelné) +9. Další kroky (volitelné) +``` + +### Kontrolní seznam praktického návodu + +- [ ] Háček začíná „Použijte workflow `X` k...“ +- [ ] „Kdy to použít“ má 3–5 odrážek +- [ ] Předpoklady jsou uvedeny +- [ ] Kroky jsou číslované `###` podsekce s akčními slovesy +- [ ] „Co získáte“ popisuje výstupní artefakty + +## Struktura vysvětlení + +### Typy + +| Typ | Příklad | +| ----------------- | ----------------------------- | +| **Úvodní stránka** | `core-concepts/index.md` | +| **Koncept** | `what-are-agents.md` | +| **Funkce** | `quick-dev.md` | +| **Filosofie** | `why-solutioning-matters.md` | +| **FAQ** | `established-projects-faq.md` | + +### Obecná šablona + +```text +1. Název + Háček (1–2 věty) +2. Přehled/Definice (co to je, proč je to důležité) +3. Klíčové koncepty (### podsekce) +4. Srovnávací tabulka (volitelné) +5. Kdy použít / Kdy nepoužít (volitelné) +6. Diagram (volitelné – mermaid, max 1 na dokument) +7. Další kroky (volitelné) +``` + +### Úvodní/Vstupní stránky + +```text +1. Název + Háček (jedna věta) +2. Tabulka obsahu (odkazy s popisy) +3. Jak začít (číslovaný seznam) +4. Vyberte si svou cestu (volitelné – rozhodovací strom) +``` + +### Vysvětlení konceptů + +```text +1. Název + Háček (co to je) +2. Typy/Kategorie (### podsekce) (volitelné) +3. Tabulka klíčových rozdílů +4. Komponenty/Části +5. Co byste měli použít? +6. Vytváření/Přizpůsobení (odkaz na praktické návody) +``` + +### Vysvětlení funkcí + +```text +1. Název + Háček (co to dělá) +2. Rychlá fakta (volitelné – „Ideální pro:“, „Čas:“) +3. Kdy použít / Kdy nepoužít +4. Jak to funguje (mermaid diagram volitelné) +5. Klíčové výhody +6. Srovnávací tabulka (volitelné) +7. Kdy přejít na vyšší úroveň (volitelné) +``` + +### Dokumenty filosofie/zdůvodnění + +```text +1. Název + Háček (princip) +2. Problém +3. Řešení +4. Klíčové principy (### podsekce) +5. Výhody +6. Kdy to platí +``` + +### Kontrolní seznam vysvětlení + +- [ ] Háček uvádí, co dokument vysvětluje +- [ ] Obsah v přehledných `##` sekcích +- [ ] Srovnávací tabulky pro 3+ možností +- [ ] Diagramy mají jasné popisky +- [ ] Odkazy na praktické návody pro procedurální otázky +- [ ] Max 2–3 admonitions na dokument + +## Struktura reference + +### Typy + +| Typ | Příklad | +| ----------------- | --------------------- | +| **Úvodní stránka** | `workflows/index.md` | +| **Katalog** | `agents/index.md` | +| **Hloubkový pohled** | `document-project.md` | +| **Konfigurace** | `core-tasks.md` | +| **Slovníček** | `glossary/index.md` | +| **Komplexní** | `bmgd-workflows.md` | + +### Úvodní stránky reference + +```text +1. Název + Háček (jedna věta) +2. Sekce obsahu (## pro každou kategorii) + - Odrážkový seznam s odkazy a popisy +``` + +### Katalogová reference + +```text +1. Název + Háček +2. Položky (## pro každou položku) + - Stručný popis (jedna věta) + - **Skills:** nebo **Klíčové info:** jako plochý seznam +3. Univerzální/Sdílené (## sekce) (volitelné) +``` + +### Hloubková reference položky + +```text +1. Název + Háček (jedna věta účel) +2. Rychlá fakta (volitelné note admonition) + - Modul, Skill, Vstup, Výstup jako seznam +3. Účel/Přehled (## sekce) +4. Jak vyvolat (blok kódu) +5. Klíčové sekce (## pro každý aspekt) + - Použijte ### pro pod-možnosti +6. Poznámky/Upozornění (tip nebo caution admonition) +``` + +### Konfigurační reference + +```text +1. Název + Háček +2. Obsah (odkazy pro skok, pokud 4+ položek) +3. Položky (## pro každou konfiguraci/úkol) + - **Tučné shrnutí** — jedna věta + - **Použijte když:** odrážkový seznam + - **Jak to funguje:** číslované kroky (max 3–5) + - **Výstup:** očekávaný výsledek (volitelné) +``` + +### Komplexní referenční průvodce + +```text +1. Název + Háček +2. Přehled (## sekce) + - Diagram nebo tabulka zobrazující organizaci +3. Hlavní sekce (## pro každou fázi/kategorii) + - Položky (### pro každou položku) + - Standardizovaná pole: Skill, Agent, Vstup, Výstup, Popis +4. Další kroky (volitelné) +``` + +### Kontrolní seznam reference + +- [ ] Háček uvádí, co dokument referuje +- [ ] Struktura odpovídá typu reference +- [ ] Položky používají konzistentní strukturu +- [ ] Tabulky pro strukturovaná/srovnávací data +- [ ] Odkazy na dokumenty vysvětlení pro koncepční hloubku +- [ ] Max 1–2 admonitions + +## Struktura slovníčku + +Starlight generuje navigaci „Na této stránce“ z nadpisů na pravé straně: + +- Kategorie jako `##` nadpisy — zobrazují se v pravé navigaci +- Termíny v tabulkách — kompaktní řádky, ne jednotlivé nadpisy +- Žádný inline TOC — pravý panel zajišťuje navigaci + +### Formát tabulky + +```md +## Název kategorie + +| Termín | Definice | +| ------------ | ------------------------------------------------------------------------------------------- | +| **Agent** | Specializovaná AI persona s konkrétní odborností, která provází uživatele pracovními postupy. | +| **Workflow** | Vícekrokový řízený proces, který orchestruje aktivity AI agentů k vytvoření výstupů. | +``` + +### Pravidla definic + +| Správně | Špatně | +| ------------------------------ | -------------------------------------------- | +| Začněte tím, co to JE nebo DĚLÁ | Nezačínejte „Toto je...“ nebo „[Termín] je...“ | +| Držte se 1–2 vět | Nepište víceodstavcová vysvětlení | +| Tučný název termínu v buňce | Nepoužívejte prostý text pro termíny | + +### Kontextové značky + +Přidejte kurzívní kontext na začátek definice pro termíny s omezeným rozsahem: + +- `*Pouze Quick Flow.*` +- `*BMad Method/Enterprise.*` +- `*Fáze N.*` +- `*BMGD.*` +- `*Existující projekty.*` + +### Kontrolní seznam slovníčku + +- [ ] Termíny v tabulkách, ne jako jednotlivé nadpisy +- [ ] Termíny abecedně seřazeny v kategoriích +- [ ] Definice 1–2 věty +- [ ] Kontextové značky kurzívou +- [ ] Názvy termínů tučně v buňkách +- [ ] Žádné definice „[Termín] je...“ + +## Sekce FAQ + +```md +## Otázky + +- [Potřebuji vždy architekturu?](#potřebuji-vždy-architekturu) +- [Mohu později změnit svůj plán?](#mohu-později-změnit-svůj-plán) + +### Potřebuji vždy architekturu? + +Pouze pro BMad Method a Enterprise. Quick Flow přeskakuje rovnou k implementaci. + +### Mohu později změnit svůj plán? + +Ano. SM agent má workflow `bmad-correct-course` pro řešení změn rozsahu. + +**Máte otázku, na kterou jste zde nenašli odpověď?** [Vytvořte issue](...) nebo se zeptejte na [Discordu](...). +``` + +## Validační příkazy + +Před odesláním změn dokumentace: + +```bash +npm run docs:fix-links # Náhled oprav formátu odkazů +npm run docs:fix-links -- --write # Aplikovat opravy +npm run docs:validate-links # Kontrola existence odkazů +npm run docs:build # Ověření bez chyb při sestavení +``` diff --git a/docs/cs/explanation/advanced-elicitation.md b/docs/cs/explanation/advanced-elicitation.md new file mode 100644 index 000000000..a2eaac16a --- /dev/null +++ b/docs/cs/explanation/advanced-elicitation.md @@ -0,0 +1,49 @@ +--- +title: "Pokročilá elicitace" +description: Přimějte LLM přehodnotit svou práci pomocí strukturovaných metod uvažování +sidebar: + order: 6 +--- + +Přimějte LLM přehodnotit, co právě vygeneroval. Vyberete metodu uvažování, LLM ji aplikuje na svůj vlastní výstup, a vy rozhodnete, zda si vylepšení ponecháte. + +## Co je pokročilá elicitace? + +Strukturovaný druhý průchod. Místo žádání AI, aby „to zkusila znovu“ nebo „to zlepšila“, vyberete specifickou metodu uvažování a AI přezkoumá svůj vlastní výstup přes tento objektiv. + +Rozdíl je podstatný. Vágní požadavky produkují vágní revize. Pojmenovaná metoda vynucuje konkrétní úhel útoku, odhaluje postřehy, které by generický pokus přehlédl. + +## Kdy ji použít + +- Poté, co workflow vygeneruje obsah a chcete alternativy +- Když výstup vypadá v pořádku, ale tušíte, že je v něm víc hloubky +- K zátěžovému testování předpokladů nebo nalezení slabých míst +- Pro důležitý obsah, kde přehodnocení pomáhá + +Workflow nabízejí pokročilou elicitaci v rozhodovacích bodech — poté, co LLM něco vygeneruje, budete dotázáni, zda ji chcete spustit. + +## Jak to funguje + +1. LLM navrhne 5 relevantních metod pro váš obsah +2. Vyberete jednu (nebo zamícháte pro jiné možnosti) +3. Metoda je aplikována, vylepšení zobrazena +4. Přijměte nebo zahoďte, opakujte nebo pokračujte + +## Vestavěné metody + +K dispozici jsou desítky metod uvažování. Několik příkladů: + +- **Pre-mortem analýza** — Předpokládejte, že projekt už selhal, a zpětně hledejte proč +- **Myšlení z prvních principů** — Odstraňte předpoklady, znovu postavte od základní pravdy +- **Inverze** — Zeptejte se, jak zaručit selhání, a poté se tomu vyhněte +- **Red Team vs Blue Team** — Napadněte vlastní práci, pak ji braňte +- **Sokratovské dotazování** — Zpochybněte každé tvrzení otázkou „proč?“ a „jak víte?“ +- **Odstranění omezení** — Odstraňte všechna omezení, podívejte se, co se změní, selektivně je přidejte zpět +- **Mapování zainteresovaných stran** — Přehodnoťte z perspektivy každé zainteresované strany +- **Analogické uvažování** — Najděte paralely v jiných oblastech a aplikujte jejich lekce + +A mnoho dalších. AI vybírá nejrelevantnější možnosti pro váš obsah — vy si vyberete, kterou spustit. + +:::tip[Začněte zde] +Pre-mortem analýza je dobrá první volba pro jakoukoli specifikaci nebo plán. Konzistentně nachází mezery, které standardní revize přehlédne. +::: diff --git a/docs/cs/explanation/adversarial-review.md b/docs/cs/explanation/adversarial-review.md new file mode 100644 index 000000000..5ccfed100 --- /dev/null +++ b/docs/cs/explanation/adversarial-review.md @@ -0,0 +1,59 @@ +--- +title: "Adversariální revize" +description: Technika vynuceného uvažování, která zabraňuje líným „vypadá dobře“ revizím +sidebar: + order: 5 +--- + +Vynuťte hlubší analýzu tím, že budete vyžadovat nalezení problémů. + +## Co je adversariální revize? + +Technika revize, kde recenzent *musí* najít problémy. Žádné „vypadá dobře“ není povoleno. Recenzent zaujme cynický postoj — předpokládá, že problémy existují, a hledá je. + +Nejde o negativismus. Jde o vynucení skutečné analýzy místo povrchního pohledu, který automaticky schválí cokoli, co bylo předloženo. + +**Základní pravidlo:** Musíte najít problémy. Nulové nálezy spouštějí zastavení — analyzujte znovu nebo vysvětlete proč. + +## Proč to funguje + +Běžné revize trpí konfirmačním zkreslením. Proletíte práci, nic nevyskočí, schválíte to. Mandát „najít problémy“ tento vzor rozbíjí: + +- **Vynucuje důkladnost** — Nemůžete schválit, dokud jste nehledali dostatečně pečlivě +- **Zachytí chybějící věci** — „Co zde není?“ se stává přirozenou otázkou +- **Zlepšuje kvalitu signálu** — Nálezy jsou konkrétní a akční, ne vágní obavy +- **Informační asymetrie** — Provádějte revize s čerstvým kontextem (bez přístupu k původnímu uvažování), abyste hodnotili artefakt, ne záměr + +## Kde se používá + +Adversariální revize se objevuje v celém BMad workflow — revize kódu, kontroly připravenosti implementace, validace specifikací a další. Někdy je to povinný krok, někdy volitelný (jako pokročilá elicitace nebo party mode). Vzor se přizpůsobí jakémukoli artefaktu, který potřebuje kontrolu. + +## Vyžadováno lidské filtrování + +Protože AI je *instruována* najít problémy, najde problémy — i když neexistují. Očekávejte falešné pozitivy: malichernosti převlečené za problémy, nepochopení záměru nebo přímo vymyšlené obavy. + +**Vy rozhodujete, co je skutečné.** Zkontrolujte každý nález, odmítněte šum, opravte to, na čem záleží. + +## Příklad + +Místo: + +> „Implementace autentizace vypadá rozumně. Schváleno.“ + +Adversariální revize produkuje: + +> 1. **VYSOKÁ** — `login.ts:47` — Žádné omezení rychlosti neúspěšných pokusů +> 2. **VYSOKÁ** — Session token uložen v localStorage (zranitelný vůči XSS) +> 3. **STŘEDNÍ** — Validace hesla probíhá pouze na straně klienta +> 4. **STŘEDNÍ** — Žádné auditní logování neúspěšných pokusů o přihlášení +> 5. **NÍZKÁ** — Magické číslo `3600` by mělo být `SESSION_TIMEOUT_SECONDS` + +První revize mohla přehlédnout bezpečnostní zranitelnost. Druhá zachytila čtyři. + +## Iterace a klesající výnosy + +Po řešení nálezů zvažte opětovné spuštění. Druhý průchod obvykle zachytí více. Třetí také není vždy zbytečný. Ale každý průchod zabere čas a nakonec dosáhnete klesajících výnosů — jen malichernosti a falešné nálezy. + +:::tip[Lepší revize] +Předpokládejte, že problémy existují. Hledejte, co chybí, ne jen co je špatně. +::: diff --git a/docs/cs/explanation/analysis-phase.md b/docs/cs/explanation/analysis-phase.md new file mode 100644 index 000000000..71b6dd650 --- /dev/null +++ b/docs/cs/explanation/analysis-phase.md @@ -0,0 +1,70 @@ +--- +title: "Fáze analýzy: od nápadu k základům" +description: Co je brainstorming, výzkum, product brief a PRFAQ — a kdy který nástroj použít +sidebar: + order: 1 +--- + +Fáze analýzy (fáze 1) vám pomůže jasně si promyslet váš produkt, než se pustíte do jeho tvorby. Každý nástroj v této fázi je volitelný, ale úplné vynechání analýzy znamená, že váš PRD je postaven na předpokladech namísto vhledu. + +## Proč analýza před plánováním? + +PRD odpovídá na otázku „Co bychom měli postavit a proč?“. Pokud jej nakrmíte vágním myšlením, získáte vágní PRD — a každý navazující dokument tuto vágnost zdědí. Architektura postavená na slabém PRD sází na špatnou techniku. Příběhy odvozené ze slabé architektury opomíjejí okrajové případy. Náklady se zvyšují. + +Existují analytické nástroje, které vám PRD zostří. Napadají problém z různých úhlů — kreativní průzkum, realita trhu, jasnost zákazníka, proveditelnost — takže v době, kdy sedíte s agentem PM, víte, co a pro koho stavíte. + +## Nástroje + +### Brainstorming + +**Co to je.** Zprostředkované tvůrčí sezení s využitím osvědčených technik generování nápadů. AI funguje jako kouč, který z vás tahá nápady prostřednictvím strukturovaných cvičení — negeneruje nápady za vás. + +**Proč je to tady.** Neotřelé nápady potřebují prostor pro rozvoj, než se zakotví v požadavcích. Brainstorming tento prostor vytváří. Je cenný zejména tehdy, když máte problémovou oblast, ale nemáte jasné řešení, nebo když chcete prozkoumat více směrů, než se k něčemu zavážete. + +**Kdy jej použít.** Máte nejasnou představu o tom, co chcete vytvořit, ale nemáte vykrystalizovaný koncept. Nebo máte koncept, ale chcete ho otestovat pod tlakem oproti alternativám. + +Viz [Brainstorming](./brainstorming.md), kde se dozvíte, jak relace fungují. + +### Výzkum (trhu, domény, technický) + +**Co to je.** Tři cílené pracovní postupy výzkumu, které zkoumají různé rozměry vašeho nápadu. Výzkum trhu zkoumá konkurenci, trendy a nálady uživatelů. Doménový výzkum vytváří odborné znalosti v daném oboru a terminologii. Technický výzkum hodnotí proveditelnost, možnosti architektury a přístupy k implementaci. + +**Proč je to tady.** Stavět na předpokladech je nejrychlejší způsob, jak vytvořit něco, co nikdo nepotřebuje. Výzkum zakládá váš koncept na realitě — co již existuje u konkurence, s čím uživatelé skutečně bojují, co je technicky proveditelné a jakým omezením specifickým pro dané odvětví budete čelit. + +**Kdy ho použít.** Vstupujete do neznámé oblasti, tušíte, že konkurence existuje, ale nemáte ji zmapovanou, nebo váš koncept závisí na technických možnostech, které nemáte ověřené. Proveďte jeden, dva nebo všechny tři — každý z nich je samostatný. + +### Product Brief + +**Co to je.** Řízené zjišťovací sezení, jehož výsledkem je 1–2stránkové shrnutí vašeho konceptu produktu. AI funguje jako spolupracující obchodní analytik, který vám pomůže formulovat vizi, cílovou skupinu, nabídku hodnoty a rozsah. + +**Proč tu je.** Produktový brief je jemnější cestou k plánování. Zachycuje vaši strategickou vizi ve strukturovaném formátu, který se přímo promítá do tvorby PRD. Nejlépe funguje, když jste již o svém konceptu přesvědčeni — znáte zákazníka, problém a zhruba víte, co chcete vytvořit. Brief tyto úvahy uspořádá a vyostří. + +**Kdy jej použít.** Váš koncept je relativně jasný a chcete jej efektivně zdokumentovat ještě před vytvořením PRD. Jste si jisti svým směřováním a nepotřebujete své předpoklady agresivně zpochybňovat. + +### PRFAQ (Working Backwards) + +**Co to je.** Metodika Working Backwards společnosti Amazon upravená jako interaktivní výzva. Napíšete tiskovou zprávu oznamující váš hotový produkt dříve, než existuje jediný řádek kódu, a pak odpovíte na nejtěžší otázky, které by vám zákazníci a zainteresované strany položili. Umělá inteligence funguje jako neúprosný, ale konstruktivní produktový kouč. + +**Proč je to tady.** PRFAQ je přísná cesta k plánování. Vynucuje si jasnost v zájmu zákazníka tím, že vás nutí obhájit každé tvrzení. Pokud nedokážete napsat přesvědčivou tiskovou zprávu, produkt není připraven. Pokud odpovědi na časté dotazy zákazníků odhalí nedostatky, jsou to nedostatky, které byste objevili mnohem později — a nákladněji — při implementaci. Hozená rukavice odhalí slabé myšlení v rané fázi, kdy je nejlevnější ho opravit. + +**Kdy ji použít.** Před vyčleněním zdrojů chcete, aby váš koncept prošel zátěžovým testem. Nejste si jisti, zda to uživatele bude skutečně zajímat. Chcete si ověřit, že dokážete formulovat jasnou a obhajitelnou nabídku hodnoty. Nebo si prostě chcete disciplínou Working Backwards zpřesnit své myšlení. + +## Který nástroj bych měl použít? + +| Situace | Doporučený nástroj | +| --------- | ---------------- | +| „Mám nejasný nápad, ale nevím, kde začít“ | Brainstorming | +| „Než se rozhodnu, potřebuji pochopit trh“ | Výzkum | +| „Vím, co chci vytvořit, jen to potřebuji zdokumentovat“ | Product Brief | +| „Chci se ujistit, že tento nápad skutečně stojí za vybudování“ | PRFAQ | +| „Chci prozkoumat, pak ověřit a pak zdokumentovat“ | Brainstorming → Výzkum → PRFAQ nebo Brief | + +Product Brief i PRFAQ jsou vstupem pro PRD — vyberte si jeden z nich podle toho, jak moc chcete být nároční. Brief je společným objevováním. PRFAQ je hozená rukavice. Obojí vás dovede ke stejnému cíli; PRFAQ testuje, zda si váš koncept zaslouží se tam dostat. + +:::tip[Nejste si jisti?] +Spusťte `bmad-help` a popište svou situaci. Doporučí vám správný výchozí bod na základě toho, co jste již udělali a čeho se snažíte dosáhnout. +::: + +## Co se stane po analýze? + +Výstupy analýzy se přímo promítají do fáze 2 (plánování). Pracovní postup PRD přijímá jako vstupy produktové briefy, dokumenty PRFAQ, výsledky výzkumu a zprávy z brainstormingu — syntetizuje vše, co jste vytvořili, do strukturovaných požadavků. Čím více analýz provedete, tím ostřejší bude vaše PRD. diff --git a/docs/cs/explanation/brainstorming.md b/docs/cs/explanation/brainstorming.md new file mode 100644 index 000000000..685312098 --- /dev/null +++ b/docs/cs/explanation/brainstorming.md @@ -0,0 +1,33 @@ +--- +title: "Brainstorming" +description: Interaktivní kreativní sezení s využitím 60+ osvědčených technik ideace +sidebar: + order: 2 +--- + +Uvolněte svou kreativitu prostřednictvím řízeného průzkumu. + +## Co je brainstorming? + +Spusťte `bmad-brainstorming` a máte kreativního facilitátora, který z vás táhne nápady — ne který je generuje za vás. AI působí jako kouč a průvodce, používá osvědčené techniky k vytvoření podmínek, ve kterých se projeví vaše nejlepší myšlení. + +**Ideální pro:** + +- Překonání kreativních bloků +- Generování nápadů na produkty nebo funkce +- Zkoumání problémů z nových úhlů +- Rozvíjení surových konceptů do akčních plánů + +## Jak to funguje + +1. **Příprava** — Definujte téma, cíle, omezení +2. **Volba přístupu** — Vyberte techniky sami, nechte si doporučit od AI, zvolte náhodně, nebo postupujte progresivním tokem +3. **Facilitace** — Projděte techniky s podněcujícími otázkami a kolaborativním koučováním +4. **Organizace** — Nápady seskupeny do témat a prioritizovány +5. **Akce** — Nejlepší nápady dostanou další kroky a metriky úspěchu + +Vše je zachyceno v dokumentu sezení, na který se můžete později odkazovat nebo ho sdílet se zúčastněnými stranami. + +:::note[Vaše nápady] +Každý nápad pochází od vás. Workflow vytváří podmínky pro vhled — vy jste zdrojem. +::: diff --git a/docs/cs/explanation/established-projects-faq.md b/docs/cs/explanation/established-projects-faq.md new file mode 100644 index 000000000..7c2a1e35a --- /dev/null +++ b/docs/cs/explanation/established-projects-faq.md @@ -0,0 +1,50 @@ +--- +title: "FAQ pro existující projekty" +description: Časté otázky o používání BMad Method na existujících projektech +sidebar: + order: 8 +--- +Rychlé odpovědi na časté otázky o práci na existujících projektech s BMad Method (BMM). + +## Otázky + +- [Musím nejdřív spustit document-project?](#musím-nejdřív-spustit-document-project) +- [Co když zapomenu spustit document-project?](#co-když-zapomenu-spustit-document-project) +- [Mohu použít Quick Flow pro existující projekty?](#mohu-použít-quick-flow-pro-existující-projekty) +- [Co když můj existující kód nedodržuje osvědčené postupy?](#co-když-můj-existující-kód-nedodržuje-osvědčené-postupy) + +### Musím nejdřív spustit document-project? + +Vysoce doporučeno, zejména pokud: + +- Neexistuje žádná dokumentace +- Dokumentace je zastaralá +- AI agenti potřebují kontext o existujícím kódu + +Můžete to přeskočit, pokud máte komplexní, aktuální dokumentaci včetně `docs/index.md` nebo budete používat jiné nástroje nebo techniky k usnadnění discovery pro agenta stavějícího na existujícím systému. + +### Co když zapomenu spustit document-project? + +Nedělejte si starosti — můžete to udělat kdykoli. Můžete to udělat i během nebo po projektu, aby pomohl udržet dokumentaci aktuální. + +### Mohu použít Quick Flow pro existující projekty? + +Ano! Quick Flow funguje skvěle pro existující projekty. Umí: + +- Automaticky detekovat váš existující stack +- Analyzovat existující vzory kódu +- Detekovat konvence a požádat o potvrzení +- Generovat kontextově bohatou specifikaci, která respektuje existující kód + +Ideální pro opravy chyb a malé funkce v existujících kódových bázích. + +### Co když můj existující kód nedodržuje osvědčené postupy? + +Quick Flow detekuje vaše konvence a zeptá se: „Mám dodržovat tyto existující konvence?“ Rozhodujete vy: + +- **Ano** → Zachovat konzistenci se současnou kódovou bází +- **Ne** → Zavést nové standardy (zdokumentujte proč ve specifikaci) + +BMM respektuje vaši volbu — nevynucuje modernizaci, ale nabídne ji. + +**Máte otázku, na kterou jste zde nenašli odpověď?** Prosím [vytvořte issue](https://github.com/bmad-code-org/BMAD-METHOD/issues) nebo se zeptejte na [Discordu](https://discord.gg/gk8jAdXWmj), abychom ji mohli přidat! diff --git a/docs/cs/explanation/party-mode.md b/docs/cs/explanation/party-mode.md new file mode 100644 index 000000000..03b6950cb --- /dev/null +++ b/docs/cs/explanation/party-mode.md @@ -0,0 +1,59 @@ +--- +title: "Party Mode" +description: Spolupráce více agentů — všichni vaši AI agenti v jedné konverzaci +sidebar: + order: 7 +--- + +Všichni vaši AI agenti v jedné konverzaci. + +## Co je Party Mode? + +Spusťte `bmad-party-mode` a máte celý svůj AI tým v jedné místnosti — PM, Architect, Dev, UX Designer, kohokoli potřebujete. BMad Master orchestruje, vybírá relevantní agenty pro každou zprávu. Agenti odpovídají v charakteru, souhlasí, nesouhlasí a staví na nápadech ostatních. + +Konverzace pokračuje tak dlouho, jak chcete. Ptejte se na doplňující otázky, oponujte odpovědím, přesměrujte diskuzi — je to skutečná výměna s vašimi agenty, dokud neskončíte. + +**Ideální pro:** + +- Velká rozhodnutí s kompromisy +- Brainstormingová sezení +- Post-mortemy, když se něco pokazí +- Retrospektivy a plánování sprintů + +## Příklady + +### Kritika špatné architektury + +**Vy:** „Dobře, týme, náš poslední sprint byl katastrofa. Autentizační služba spadla třikrát. Kdo to pokazil?“ + +**Architect:** „Design byl v pořádku — distribuovaná autentizace se správnými záložními řešeními. Pokud se implementace odchýlila od specifikace...“ + +**Dev:** „Následoval jsem architektonický dokument přesně. Specifikace nepočítala s race conditions při souběžné invalidaci relací.“ + +**PM:** „Oba jste přehlédli větší problém — nevalidovali jsme požadavky na správu relací v PRD. Tohle je na mně, že jsem to nezachytil.“ + +**TEA:** „A já to měl zachytit v integračních testech. Testovací scénáře nepokrývaly souběžnou invalidaci.“ + +### Kreativní brainstorming + +**Vy:** „Jak udělat onboarding magický místo nudného?“ + +**UX Designer:** „Začněte s progresivním odhalováním — odhalujte funkce, jak je uživatelé potřebují, ne všechny najednou v tutoriálu.“ + +**Storyteller:** „Co kdyby onboarding byl příběh? Každý krok odhaluje cestu postavy — uživatel JE hrdina.“ + +**Game Designer:** „Navazuji na to — co kdyby první ‚quest' vlastně řešil skutečný problém uživatele? Učí se tím, že dělají něco hodnotného.“ + +### Technické rozhodnutí + +**Vy:** „Monolit nebo mikroslužby pro MVP?“ + +**Architect:** „Začněte monolitem. Mikroslužby přidávají složitost, kterou při 1000 uživatelích nepotřebujete.“ + +**PM:** „Souhlasím. Čas na trh je důležitější než teoretická škálovatelnost.“ + +**Dev:** „Monolit s jasnými hranicemi modulů. Služby můžeme extrahovat později, pokud bude potřeba.“ + +:::tip[Lepší rozhodnutí] +Lepší rozhodnutí prostřednictvím různorodých perspektiv. Vítejte v party mode. +::: diff --git a/docs/cs/explanation/preventing-agent-conflicts.md b/docs/cs/explanation/preventing-agent-conflicts.md new file mode 100644 index 000000000..d0dd2d01e --- /dev/null +++ b/docs/cs/explanation/preventing-agent-conflicts.md @@ -0,0 +1,112 @@ +--- +title: "Předcházení konfliktům agentů" +description: Jak architektura zabraňuje konfliktům, když více agentů implementuje systém +sidebar: + order: 4 +--- + +Když více AI agentů implementuje různé části systému, mohou dělat protichůdná technická rozhodnutí. Dokumentace architektury tomu zabraňuje stanovením sdílených standardů. + +## Běžné typy konfliktů + +### Konflikty stylu API + +Bez architektury: +- Agent A používá REST s `/users/{id}` +- Agent B používá GraphQL mutations +- Výsledek: Nekonzistentní vzory API, zmatení konzumenti + +S architekturou: +- ADR specifikuje: „Použít GraphQL pro veškerou komunikaci klient-server“ +- Všichni agenti dodržují stejný vzor + +### Konflikty návrhu databáze + +Bez architektury: +- Agent A používá snake_case pro názvy sloupců +- Agent B používá camelCase pro názvy sloupců +- Výsledek: Nekonzistentní schéma, matoucí dotazy + +S architekturou: +- Dokument standardů specifikuje konvence pojmenování +- Všichni agenti dodržují stejné vzory + +### Konflikty řízení stavu + +Bez architektury: +- Agent A používá Redux pro globální stav +- Agent B používá React Context +- Výsledek: Více přístupů k řízení stavu, složitost + +S architekturou: +- ADR specifikuje přístup k řízení stavu +- Všichni agenti implementují konzistentně + +## Jak architektura zabraňuje konfliktům + +### 1. Explicitní rozhodnutí skrze ADR + +Každé významné technologické rozhodnutí je zdokumentováno s: +- Kontext (proč toto rozhodnutí záleží) +- Zvažované možnosti (jaké alternativy existují) +- Rozhodnutí (co jsme zvolili) +- Zdůvodnění (proč jsme to zvolili) +- Důsledky (přijaté kompromisy) + +### 2. Specifické pokyny pro FR/NFR + +Architektura mapuje každý funkční požadavek na technický přístup: +- FR-001: Správa uživatelů → GraphQL mutations +- FR-002: Mobilní aplikace → Optimalizované dotazy + +### 3. Standardy a konvence + +Explicitní dokumentace: +- Struktura adresářů +- Konvence pojmenování +- Organizace kódu +- Vzory testování + +## Architektura jako sdílený kontext + +Představte si architekturu jako sdílený kontext, který všichni agenti čtou před implementací: + +```text +PRD: "Co budovat" + ↓ +Architektura: "Jak to budovat" + ↓ +Agent A čte architekturu → implementuje Epic 1 +Agent B čte architekturu → implementuje Epic 2 +Agent C čte architekturu → implementuje Epic 3 + ↓ +Výsledek: Konzistentní implementace +``` + +## Klíčová témata ADR + +Běžná rozhodnutí, která zabraňují konfliktům: + +| Téma | Příklad rozhodnutí | +| ---------------- | -------------------------------------------- | +| Styl API | GraphQL vs REST vs gRPC | +| Databáze | PostgreSQL vs MongoDB | +| Autentizace | JWT vs Sessions | +| Řízení stavu | Redux vs Context vs Zustand | +| Stylování | CSS Modules vs Tailwind vs Styled Components | +| Testování | Jest + Playwright vs Vitest + Cypress | + +## Anti-vzory, kterým se vyhnout + +:::caution[Běžné chyby] +- **Implicitní rozhodnutí** — „Styl API vyřešíme průběžně“ vede k nekonzistenci +- **Nadměrná dokumentace** — Dokumentování každého drobného rozhodnutí způsobuje paralýzu analýzou +- **Zastaralá architektura** — Dokumenty napsané jednou a nikdy neaktualizované způsobují, že agenti následují zastaralé vzory +::: + +:::tip[Správný přístup] +- Dokumentujte rozhodnutí, která přesahují hranice epiců +- Zaměřte se na oblasti náchylné ke konfliktům +- Aktualizujte architekturu, jak se učíte +- Použijte `bmad-correct-course` pro významné změny +::: diff --git a/docs/cs/explanation/project-context.md b/docs/cs/explanation/project-context.md new file mode 100644 index 000000000..795b4b7b5 --- /dev/null +++ b/docs/cs/explanation/project-context.md @@ -0,0 +1,157 @@ +--- +title: "Kontext projektu" +description: Jak project-context.md vede AI agenty s pravidly a preferencemi vašeho projektu +sidebar: + order: 7 +--- + +Soubor `project-context.md` je implementační průvodce vašeho projektu pro AI agenty. Podobně jako „ústava“ v jiných vývojových systémech zachycuje pravidla, vzory a preference, které zajišťují konzistentní generování kódu napříč všemi workflow. + +## Co dělá + +AI agenti neustále dělají implementační rozhodnutí — jaké vzory následovat, jak strukturovat kód, jaké konvence používat. Bez jasného vedení mohou: +- Následovat generické osvědčené postupy, které neodpovídají vaší kódové bázi +- Dělat nekonzistentní rozhodnutí napříč různými stories +- Přehlédnout požadavky nebo omezení specifická pro projekt + +Soubor `project-context.md` toto řeší dokumentací toho, co agenti potřebují vědět, ve stručném formátu optimalizovaném pro LLM. + +## Jak to funguje + +Každý implementační workflow automaticky načítá `project-context.md`, pokud existuje. Architektonický workflow ho také načítá, aby respektoval vaše technické preference při navrhování architektury. + +**Načítán těmito workflow:** +- `bmad-create-architecture` — respektuje technické preference během solutioningu +- `bmad-create-story` — informuje tvorbu stories vzory projektu +- `bmad-dev-story` — vede implementační rozhodnutí +- `bmad-code-review` — validuje proti standardům projektu +- `bmad-quick-dev` — aplikuje vzory při implementaci specifikací +- `bmad-sprint-planning`, `bmad-retrospective`, `bmad-correct-course` — poskytuje celkový kontext projektu + +## Kdy ho vytvořit + +Soubor `project-context.md` je užitečný v jakékoli fázi projektu: + +| Scénář | Kdy vytvořit | Účel | +| ------------------------------------ | ----------------------------------------------- | -------------------------------------------------------------------- | +| **Nový projekt, před architekturou** | Ručně, před `bmad-create-architecture` | Dokumentujte vaše technické preference, aby je architekt respektoval | +| **Nový projekt, po architektuře** | Přes `bmad-generate-project-context` nebo ručně | Zachyťte architektonická rozhodnutí pro implementační agenty | +| **Existující projekt** | Přes `bmad-generate-project-context` | Objevte existující vzory, aby agenti dodržovali zavedené konvence | +| **Quick Flow projekt** | Před nebo během `bmad-quick-dev` | Zajistěte, aby rychlá implementace respektovala vaše vzory | + +:::tip[Doporučeno] +Pro nové projekty ho vytvořte ručně před architekturou, pokud máte silné technické preference. Jinak ho vygenerujte po architektuře pro zachycení těchto rozhodnutí. +::: + +## Co do něj patří + +Soubor má dvě hlavní sekce: + +### Technologický stack a verze + +Dokumentuje frameworky, jazyky a nástroje, které váš projekt používá se specifickými verzemi: + +```markdown +## Technology Stack & Versions + +- Node.js 20.x, TypeScript 5.3, React 18.2 +- State: Zustand (not Redux) +- Testing: Vitest, Playwright, MSW +- Styling: Tailwind CSS with custom design tokens +``` + +### Kritická pravidla implementace + +Dokumentuje vzory a konvence, které by agenti jinak mohli přehlédnout: + +```markdown +## Critical Implementation Rules + +**TypeScript Configuration:** +- Strict mode enabled — no `any` types without explicit approval +- Use `interface` for public APIs, `type` for unions/intersections + +**Code Organization:** +- Components in `/src/components/` with co-located `.test.tsx` +- Utilities in `/src/lib/` for reusable pure functions +- API calls use the `apiClient` singleton — never fetch directly + +**Testing Patterns:** +- Unit tests focus on business logic, not implementation details +- Integration tests use MSW to mock API responses +- E2E tests cover critical user journeys only + +**Framework-Specific:** +- All async operations use the `handleError` wrapper for consistent error handling +- Feature flags accessed via `featureFlag()` from `@/lib/flags` +- New routes follow the file-based routing pattern in `/src/app/` +``` + +Zaměřte se na to, co je **neočividné** — věci, které agenti nemusí odvodit z čtení úryvků kódu. Nedokumentujte standardní postupy, které platí univerzálně. + +## Vytvoření souboru + +Máte tři možnosti: + +### Ruční vytvoření + +Vytvořte soubor na `_bmad-output/project-context.md` a přidejte svá pravidla: + +```bash +# V kořeni projektu +mkdir -p _bmad-output +touch _bmad-output/project-context.md +``` + +Upravte ho s vaším technologickým stackem a pravidly implementace. Architektonický a implementační workflow ho automaticky najdou a načtou. + +### Generování po architektuře + +Spusťte workflow `bmad-generate-project-context` po dokončení architektury: + +```bash +bmad-generate-project-context +``` + +Toto skenuje váš dokument architektury a soubory projektu a generuje kontextový soubor zachycující učiněná rozhodnutí. + +### Generování pro existující projekty + +Pro existující projekty spusťte `bmad-generate-project-context` pro objevení existujících vzorů: + +```bash +bmad-generate-project-context +``` + +Workflow analyzuje vaši kódovou bázi, identifikuje konvence a vygeneruje kontextový soubor, který můžete zkontrolovat a upřesnit. + +## Proč na tom záleží + +Bez `project-context.md` agenti dělají předpoklady, které nemusí odpovídat vašemu projektu: + +| Bez kontextu | S kontextem | +| ----------------------------------------------- | ---------------------------------------- | +| Používá generické vzory | Dodržuje vaše zavedené konvence | +| Nekonzistentní styl napříč stories | Konzistentní implementace | +| Může přehlédnout omezení specifická pro projekt | Respektuje všechny technické požadavky | +| Každý agent rozhoduje nezávisle | Všichni agenti se řídí stejnými pravidly | + +To je zvláště důležité pro: +- **Quick Flow** — přeskakuje PRD a architekturu, takže kontextový soubor vyplní mezeru +- **Týmové projekty** — zajistí, že všichni agenti dodržují stejné standardy +- **Existující projekty** — zabrání porušení zavedených vzorů + +## Editace a aktualizace + +Soubor `project-context.md` je živý dokument. Aktualizujte ho, když: + +- Se změní architektonická rozhodnutí +- Jsou zavedeny nové konvence +- Vzory se vyvíjejí během implementace +- Identifikujete mezery z chování agentů + +Můžete ho kdykoli ručně upravit, nebo přegenerovat `bmad-generate-project-context` po významných změnách. + +:::note[Umístění souboru] +Výchozí umístění je `_bmad-output/project-context.md`. Workflow ho tam hledají a také kontrolují `**/project-context.md` kdekoli ve vašem projektu. +::: diff --git a/docs/cs/explanation/quick-dev.md b/docs/cs/explanation/quick-dev.md new file mode 100644 index 000000000..aa7305df9 --- /dev/null +++ b/docs/cs/explanation/quick-dev.md @@ -0,0 +1,73 @@ +--- +title: "Quick Dev" +description: Snižte tření human-in-the-loop bez ztráty kontrolních bodů chránících kvalitu výstupu +sidebar: + order: 2 +--- + +Záměr na vstupu, změny kódu na výstupu, s co nejmenším počtem human-in-the-loop kroků — bez obětování kvality. + +Umožňuje modelu běžet déle mezi kontrolními body a poté přivede člověka zpět pouze tehdy, když úkol nemůže bezpečně pokračovat bez lidského úsudku nebo když je čas zkontrolovat konečný výsledek. + +![Diagram workflow Quick Dev](/diagrams/quick-dev-diagram.png) + +## Proč to existuje + +Human-in-the-loop kroky jsou nutné a nákladné. + +Současné LLM stále selhávají předvídatelnými způsoby: chybně čtou záměr, vyplňují mezery sebevědomými odhady, odchylují se k nesouvisející práci a generují šumový výstup revize. Současně neustálá lidská intervence limituje rychlost vývoje. Lidská pozornost je úzké hrdlo. + +`bmad-quick-dev` přenastavuje tento kompromis. Důvěřuje modelu, aby běžel bez dozoru delší úseky, ale pouze poté, co workflow vytvořil dostatečně silnou hranici, aby to bylo bezpečné. + +## Základní design + +### 1. Nejprve komprimujte záměr + +Workflow začíná tím, že člověk a model zkomprimují požadavek do jednoho koherentního cíle. Vstup může začínat jako hrubé vyjádření záměru, ale předtím, než workflow poběží autonomně, musí být dostatečně malý, jasný a bez protimluvů pro provedení. + +Záměr může přijít v mnoha formách: pár frází, odkaz na bug tracker, výstup z plan mode, text zkopírovaný z chatové relace, nebo dokonce číslo story z BMAD vlastního `epics.md`. V posledním případě workflow nepochopí sémantiku sledování stories BMAD, ale stále může vzít samotnou story a pracovat s ní. + +Tento workflow neodstraňuje lidskou kontrolu. Přemisťuje ji na malý počet vysoce hodnotných momentů: + +- **Vyjasnění záměru** — přeměna nepřehledného požadavku na jeden koherentní cíl bez skrytých protimluvů +- **Schválení specifikace** — potvrzení, že zmrazené porozumění je správná věc k budování +- **Revize konečného produktu** — primární kontrolní bod, kde člověk rozhoduje, zda je výsledek přijatelný + +### 2. Nasměrujte na nejmenší bezpečnou cestu + +Jakmile je cíl jasný, workflow rozhodne, zda jde o skutečnou jednorázovou změnu nebo zda potřebuje plnější cestu. Malé změny s nulovým blast-radius mohou jít přímo k implementaci. Vše ostatní prochází plánováním, aby model měl silnější hranici před tím, než poběží déle samostatně. + +### 3. Běžte déle s menším dozorem + +Po tomto rozhodnutí o směrování může model nést více práce samostatně. Na plnější cestě se schválená specifikace stává hranicí, proti které model provádí s menším dozorem, což je celý smysl designu. + +### 4. Diagnostikujte selhání na správné vrstvě + +Pokud je implementace špatná, protože byl špatný záměr, oprava kódu je špatná oprava. Pokud je kód špatný, protože specifikace byla slabá, oprava diffu je také špatná oprava. Workflow je navržen tak, aby diagnostikoval, kde selhání vstoupilo do systému, vrátil se na tu vrstvu a přegeneroval odtamtud. + +Nálezy revize se používají k rozhodnutí, zda problém pochází ze záměru, generování specifikace nebo lokální implementace. Pouze skutečně lokální problémy se opravují lokálně. + +### 5. Přiveďte člověka zpět pouze když je potřeba + +Interview o záměru je human-in-the-loop, ale není to stejný druh přerušení jako opakující se kontrolní bod. Workflow se snaží udržet tyto opakující se kontrolní body na minimu. Po úvodním formování záměru se člověk vrací hlavně tehdy, když workflow nemůže bezpečně pokračovat bez úsudku a na konci, když je čas zkontrolovat výsledek. + +- **Řešení mezer v záměru** — vstoupení zpět, když revize prokáže, že workflow nemohl bezpečně odvodit, co bylo myšleno + +Vše ostatní je kandidátem na delší autonomní provádění. Tento kompromis je záměrný. Starší vzory věnují více lidské pozornosti nepřetržitému dozoru. Quick Dev věnuje více důvěry modelu, ale šetří lidskou pozornost pro momenty, kde má lidské uvažování nejvyšší páku. + +## Proč systém revize záleží + +Fáze revize není jen pro hledání chyb. Je tu pro směrování korekce bez ničení momentum. + +Tento workflow funguje nejlépe na platformě, která může spouštět sub-agenty, nebo alespoň vyvolat jiné LLM přes příkazovou řádku a čekat na výsledek. Pokud to vaše platforma nativně nepodporuje, můžete přidat skill, který to udělá. Bezcontextové sub-agenty jsou základním kamenem designu revize. + +Agentní revize často selhávají dvěma způsoby: + +- Generují příliš mnoho nálezů, čímž nutí člověka prosévat šum. +- Vychýlí aktuální změnu odhalením nesouvisejících problémů a přemění každý běh na ad-hoc úklidový projekt. + +Quick Dev řeší obojí tím, že s revizí zachází jako s triáží. + +Některé nálezy patří k aktuální změně. Některé ne. Pokud je nález náhodný spíše než kauzálně vázaný na aktuální práci, workflow ho může odložit místo nucení člověka ho okamžitě řešit. To udržuje běh zaměřený a zabraňuje náhodným tangentám ve spotřebování rozpočtu pozornosti. + +Ta triáž bude někdy nedokonalá. To je přijatelné. Obvykle je lepší špatně posoudit některé nálezy než zaplavit člověka tisíci nízkohodnotných revizních komentářů. Systém optimalizuje pro kvalitu signálu, ne vyčerpávající recall. diff --git a/docs/cs/explanation/why-solutioning-matters.md b/docs/cs/explanation/why-solutioning-matters.md new file mode 100644 index 000000000..1e9848bfd --- /dev/null +++ b/docs/cs/explanation/why-solutioning-matters.md @@ -0,0 +1,76 @@ +--- +title: "Proč je solutioning důležitý" +description: Pochopení toho, proč je fáze solutioningu klíčová pro projekty s více epicy +sidebar: + order: 3 +--- + +Fáze 3 (Solutioning) překládá **co** budovat (z plánování) na **jak** to budovat (technický návrh). Tato fáze zabraňuje konfliktům agentů v projektech s více epicy tím, že dokumentuje architektonická rozhodnutí před zahájením implementace. + +## Problém bez solutioningu + +```text +Agent 1 implementuje Epic 1 pomocí REST API +Agent 2 implementuje Epic 2 pomocí GraphQL +Výsledek: Nekonzistentní design API, integrační noční můra +``` + +Když více agentů implementuje různé části systému bez sdíleného architektonického vedení, dělají nezávislá technická rozhodnutí, která si mohou odporovat. + +## Řešení se solutioningem + +```text +Architektonický workflow rozhodne: "Použít GraphQL pro všechna API" +Všichni agenti dodržují architektonická rozhodnutí +Výsledek: Konzistentní implementace, žádné konflikty +``` + +Explicitní dokumentací technických rozhodnutí všichni agenti implementují konzistentně a integrace se stává přímočarou. + +## Solutioning vs. plánování + +| Aspekt | Plánování (Fáze 2) | Solutioning (Fáze 3) | +| -------- | ----------------------- | --------------------------------- | +| Otázka | Co a proč? | Jak? Pak jaké jednotky práce? | +| Výstup | FR/NFR (požadavky) | Architektura + epicy/stories | +| Agent | PM | Architect → PM | +| Publikum | Zainteresované strany | Vývojáři | +| Dokument | PRD (FR/NFR) | Architektura + soubory epiců | +| Úroveň | Obchodní logika | Technický design + rozklad práce | + +## Klíčový princip + +**Učiňte technická rozhodnutí explicitní a zdokumentovaná**, aby všichni agenti implementovali konzistentně. + +Toto zabraňuje: +- Konfliktům stylu API (REST vs GraphQL) +- Nekonzistencím v návrhu databáze +- Neshodám v řízení stavu +- Nesouladu konvencí pojmenování +- Variacím v bezpečnostním přístupu + +## Kdy je solutioning vyžadován + +| Cesta | Solutioning vyžadován? | +|-------|----------------------| +| Quick Flow | Ne — přeskočte úplně | +| BMad Method Simple | Volitelný | +| BMad Method Complex | Ano | +| Enterprise | Ano | + +:::tip[Pravidlo palce] +Pokud máte více epiců, které by mohly být implementovány různými agenty, potřebujete solutioning. +::: + +## Cena přeskočení + +Přeskočení solutioningu u složitých projektů vede k: + +- **Integračním problémům** objeveným uprostřed sprintu +- **Přepracování** kvůli konfliktním implementacím +- **Delšímu celkovému času vývoje** +- **Technickému dluhu** z nekonzistentních vzorů + +:::caution[Multiplikátor nákladů] +Zachycení problémů se zarovnáním v solutioningu je 10× rychlejší než jejich objevení během implementace. +::: diff --git a/docs/cs/how-to/customize-bmad.md b/docs/cs/how-to/customize-bmad.md new file mode 100644 index 000000000..4669030a0 --- /dev/null +++ b/docs/cs/how-to/customize-bmad.md @@ -0,0 +1,171 @@ +--- +title: "Jak přizpůsobit BMad" +description: Přizpůsobení agentů, workflow a modulů se zachováním kompatibility s aktualizacemi +sidebar: + order: 7 +--- + +Použijte soubory `.customize.yaml` k přizpůsobení chování agentů, person a nabídek při zachování vašich změn napříč aktualizacemi. + +## Kdy to použít + +- Chcete změnit jméno, osobnost nebo komunikační styl agenta +- Potřebujete, aby si agenti pamatovali kontextově specifické informace projektu +- Chcete přidat vlastní položky nabídky, které spouštějí vaše vlastní workflow nebo prompty +- Chcete, aby agenti prováděli specifické akce při každém spuštění + +:::note[Předpoklady] +- BMad nainstalován ve vašem projektu (viz [Jak nainstalovat BMad](./install-bmad.md)) +- Textový editor pro YAML soubory +::: + +:::caution[Chraňte svá přizpůsobení] +Vždy používejte soubory `.customize.yaml` popsané zde místo přímé editace souborů agentů. Instalátor přepíše soubory agentů během aktualizací, ale zachová vaše změny v `.customize.yaml`. +::: + +## Kroky + +### 1. Najděte soubory přizpůsobení + +Po instalaci najdete jeden soubor `.customize.yaml` na agenta v: + +```text +_bmad/_config/agents/ +├── core-bmad-master.customize.yaml +├── bmm-dev.customize.yaml +├── bmm-pm.customize.yaml +└── ... (jeden soubor na instalovaného agenta) +``` + +### 2. Upravte soubor přizpůsobení + +Otevřete soubor `.customize.yaml` pro agenta, kterého chcete upravit. Každá sekce je volitelná — přizpůsobte pouze to, co potřebujete. + +| Sekce | Chování | Účel | +| ------------------ | --------- | -------------------------------------------------------- | +| `agent.metadata` | Nahrazuje | Přepsat zobrazované jméno agenta | +| `persona` | Nahrazuje | Nastavit roli, identitu, styl a principy | +| `memories` | Přidává | Přidat trvalý kontext, který si agent vždy pamatuje | +| `menu` | Přidává | Přidat vlastní položky nabídky pro workflow nebo prompty | +| `critical_actions` | Přidává | Definovat instrukce při spuštění agenta | +| `prompts` | Přidává | Vytvořit znovupoužitelné prompty pro akce nabídky | + +Sekce označené **Nahrazuje** zcela přepíší výchozí hodnoty agenta. Sekce označené **Přidává** doplní existující konfiguraci. + +**Jméno agenta** + +Změňte, jak se agent představí: + +```yaml +agent: + metadata: + name: 'Spongebob' # Výchozí: "Amelia" +``` + +**Persona** + +Nahraďte osobnost, roli a komunikační styl agenta: + +```yaml +persona: + role: 'Senior Full-Stack Engineer' + identity: 'Lives in a pineapple (under the sea)' + communication_style: 'Spongebob annoying' + principles: + - 'Never Nester, Spongebob Devs hate nesting more than 2 levels deep' + - 'Favor composition over inheritance' +``` + +Sekce `persona` nahrazuje celou výchozí personu, takže nastavte všechna čtyři pole. + +**Memories** + +Přidejte trvalý kontext, který si agent bude vždy pamatovat: + +```yaml +memories: + - 'Works at Krusty Krab' + - 'Favorite Celebrity: David Hasselhoff' + - 'Learned in Epic 1 that it is not cool to just pretend that tests have passed' +``` + +**Položky nabídky** + +Přidejte vlastní záznamy do nabídky agenta. Každá položka potřebuje `trigger`, cíl (`workflow` cestu nebo `action` referenci) a `description`: + +```yaml +menu: + - trigger: my-workflow + workflow: 'my-custom/workflows/my-workflow.yaml' + description: My custom workflow + - trigger: deploy + action: '#deploy-prompt' + description: Deploy to production +``` + +**Kritické akce** + +Definujte instrukce, které se spustí při startu agenta: + +```yaml +critical_actions: + - 'Check the CI Pipelines with the XYZ Skill and alert user on wake if anything is urgently needing attention' +``` + +**Vlastní prompty** + +Vytvořte znovupoužitelné prompty, na které mohou položky nabídky odkazovat s `action="#id"`: + +```yaml +prompts: + - id: deploy-prompt + content: | + Deploy the current branch to production: + 1. Run all tests + 2. Build the project + 3. Execute deployment script +``` + +### 3. Aplikujte změny + +Po editaci přeinstalujte pro aplikaci změn: + +```bash +npx bmad-method install +``` + +Instalátor detekuje existující instalaci a nabídne tyto možnosti: + +| Možnost | Co udělá | +| ---------------------------- | ---------------------------------------------------------------------- | +| **Quick Update** | Aktualizuje všechny moduly na nejnovější verzi a aplikuje přizpůsobení | +| **Modify BMad Installation** | Plný instalační postup pro přidání nebo odebrání modulů | + +Pro změny pouze přizpůsobení je **Quick Update** nejrychlejší možnost. + +## Řešení problémů + +**Změny se nezobrazují?** + +- Spusťte `npx bmad-method install` a vyberte **Quick Update** pro aplikaci změn +- Zkontrolujte, že vaše YAML syntaxe je platná (na odsazení záleží) +- Ověřte, že jste upravili správný soubor `.customize.yaml` pro daného agenta + +**Agent se nenačítá?** + +- Zkontrolujte YAML syntaxi pomocí online YAML validátoru +- Ujistěte se, že jste nenechali pole prázdná po odkomentování +- Zkuste se vrátit k původní šabloně a znovu sestavit + +**Potřebujete resetovat agenta?** + +- Vymažte nebo smažte soubor `.customize.yaml` agenta +- Spusťte `npx bmad-method install` a vyberte **Quick Update** pro obnovení výchozích hodnot + +## Přizpůsobení workflow + +Přizpůsobení existujících BMad Method workflow a skills přijde brzy. + +## Přizpůsobení modulů + +Návod na tvorbu rozšiřujících modulů a přizpůsobení existujících modulů přijde brzy. diff --git a/docs/cs/how-to/established-projects.md b/docs/cs/how-to/established-projects.md new file mode 100644 index 000000000..4be87509a --- /dev/null +++ b/docs/cs/how-to/established-projects.md @@ -0,0 +1,117 @@ +--- +title: "Existující projekty" +description: Jak používat BMad Method na existujících kódových bázích +sidebar: + order: 6 +--- + +Používejte BMad Method efektivně při práci na existujících projektech a starších kódových bázích. + +Tento návod pokrývá základní workflow pro zapojení se do existujících projektů s BMad Method. + +:::note[Předpoklady] +- BMad Method nainstalován (`npx bmad-method install`) +- Existující kódová báze, na které chcete pracovat +- Přístup k AI-powered IDE (Claude Code nebo Cursor) +::: + +## Krok 1: Vyčistěte dokončené plánovací artefakty + +Pokud jste dokončili všechny PRD epicy a stories procesem BMad, vyčistěte tyto soubory. Archivujte je, smažte nebo se spoléhejte na historii verzí. Nenechávejte tyto soubory v: + +- `docs/` +- `_bmad-output/planning-artifacts/` +- `_bmad-output/implementation-artifacts/` + +## Krok 2: Vytvořte kontext projektu + +:::tip[Doporučeno pro existující projekty] +Vygenerujte `project-context.md` pro zachycení vzorů a konvencí vaší existující kódové báze. Tím zajistíte, že AI agenti budou při implementaci změn dodržovat vaše zavedené postupy. +::: + +Spusťte workflow pro generování kontextu projektu: + +```bash +bmad-generate-project-context +``` + +Toto skenuje vaši kódovou bázi a identifikuje: +- Technologický stack a verze +- Vzory organizace kódu +- Konvence pojmenování +- Přístupy k testování +- Vzory specifické pro framework + +Vygenerovaný soubor můžete zkontrolovat a upravit, nebo ho vytvořit ručně na `_bmad-output/project-context.md`. + +[Zjistit více o kontextu projektu](../explanation/project-context.md) + +## Krok 3: Udržujte kvalitní projektovou dokumentaci + +Vaše složka `docs/` by měla obsahovat stručnou, dobře organizovanou dokumentaci, která přesně reprezentuje váš projekt: + +- Záměr a obchodní zdůvodnění +- Obchodní pravidla +- Architektura +- Jakékoli další relevantní informace o projektu + +Pro složité projekty zvažte použití workflow `bmad-document-project`. Nabízí varianty, které proskenují celý váš projekt a zdokumentují jeho aktuální stav. + +## Krok 3: Získejte pomoc + +### BMad-Help: Váš výchozí bod + +**Spusťte `bmad-help` kdykoli si nejste jisti, co dělat dál.** Tento inteligentní průvodce: + +- Prozkoumá váš projekt a zjistí, co už bylo uděláno +- Ukáže možnosti na základě nainstalovaných modulů +- Rozumí dotazům v přirozeném jazyce + +``` +bmad-help I have an existing Rails app, where should I start? +bmad-help What's the difference between quick-flow and full method? +bmad-help Show me what workflows are available +``` + +BMad-Help se také **automaticky spouští na konci každého workflow** a poskytuje jasné pokyny, co přesně dělat dál. + +### Volba přístupu + +Máte dvě hlavní možnosti v závislosti na rozsahu změn: + +| Rozsah | Doporučený přístup | +| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| **Malé aktualizace či doplnění** | Spusťte `bmad-quick-dev` pro vyjasnění záměru, plánování, implementaci a revizi v jednom workflow. Plná čtyřfázová metoda BMad je pravděpodobně přehnaná. | +| **Velké změny či doplnění** | Začněte s metodou BMad a aplikujte tolik nebo tak málo důkladnosti, kolik potřebujete. | + +### Během tvorby PRD + +Při vytváření briefu nebo přímém přechodu na PRD zajistěte, aby agent: + +- Našel a analyzoval vaši existující projektovou dokumentaci +- Přečetl si správný kontext o vašem aktuálním systému + +Agenta můžete navést explicitně, ale cílem je zajistit, aby se nová funkce dobře integrovala s vaším existujícím systémem. + +### Úvahy o UX + +Práce na UX je volitelná. Rozhodnutí nezávisí na tom, zda váš projekt má UX, ale na: + +- Zda budete pracovat na změnách UX +- Zda jsou potřeba významné nové UX návrhy nebo vzory + +Pokud vaše změny představují jednoduché aktualizace existujících obrazovek, se kterými jste spokojeni, plný UX proces je zbytečný. + +### Úvahy o architektuře + +Při práci na architektuře zajistěte, aby architekt: + +- Používal správné zdokumentované soubory +- Skenoval existující kódovou bázi + +Věnujte zde zvláštní pozornost, abyste předešli znovuvynalézání kola nebo rozhodnutím, která neodpovídají vaší existující architektuře. + +## Další informace + +- **[Rychlé opravy](./quick-fixes.md)** — Opravy chyb a ad-hoc změny +- **[FAQ pro existující projekty](../explanation/established-projects-faq.md)** — Časté otázky o práci na existujících projektech diff --git a/docs/cs/how-to/get-answers-about-bmad.md b/docs/cs/how-to/get-answers-about-bmad.md new file mode 100644 index 000000000..19865ae3f --- /dev/null +++ b/docs/cs/how-to/get-answers-about-bmad.md @@ -0,0 +1,110 @@ +--- +title: "Jak získat odpovědi o BMad" +description: Použijte LLM k rychlému zodpovězení vašich otázek o BMad +sidebar: + order: 4 +--- + +## Začněte zde: BMad-Help + +**Nejrychlejší způsob, jak získat odpovědi o BMad, je skill `bmad-help`.** Tento inteligentní průvodce zodpoví více než 80 % všech otázek a je vám k dispozici přímo ve vašem IDE při práci. + +BMad-Help je víc než vyhledávací nástroj — umí: +- **Prozkoumat váš projekt** a zjistit, co už bylo dokončeno +- **Rozumět přirozenému jazyku** — ptejte se běžnou řečí +- **Přizpůsobit se nainstalovaným modulům** — zobrazí relevantní možnosti +- **Automaticky se spouštět po workflow** — řekne vám přesně, co dělat dál +- **Doporučit první povinný úkol** — žádné hádání, kde začít + +### Jak používat BMad-Help + +Zavolejte ho jménem ve vaší AI relaci: + +``` +bmad-help +``` + +:::tip +V závislosti na vaší platformě můžete také použít `/bmad-help` nebo `$bmad-help`, ale samotné `bmad-help` by mělo fungovat všude. +::: + +Spojte ho s dotazem v přirozeném jazyce: + +``` +bmad-help I have a SaaS idea and know all the features. Where do I start? +bmad-help What are my options for UX design? +bmad-help I'm stuck on the PRD workflow +bmad-help Show me what's been done so far +``` + +BMad-Help odpoví: +- Co je doporučeno pro vaši situaci +- Jaký je první povinný úkol +- Jak vypadá zbytek procesu + +## Kdy použít tohoto průvodce + +Použijte tuto sekci, když: +- Chcete pochopit architekturu nebo interní fungování BMad +- Potřebujete odpovědi mimo to, co BMad-Help nabízí +- Zkoumáte BMad před instalací +- Chcete prozkoumat zdrojový kód přímo + +## Kroky + +### 1. Vyberte si zdroj + +| Zdroj | Nejlepší pro | Příklady | +| -------------------- | ----------------------------------------- | ---------------------------- | +| **Složka `_bmad`** | Jak BMad funguje — agenti, workflow, prompty | „Co dělá PM agent?“ | +| **Celý GitHub repo** | Historie, instalátor, architektura | „Co se změnilo ve v6?“ | +| **`llms-full.txt`** | Rychlý přehled z dokumentace | „Vysvětli čtyři fáze BMad“ | + +Složka `_bmad` se vytvoří při instalaci BMad. Pokud ji ještě nemáte, naklonujte si repo. + +### 2. Nasměrujte AI na zdroj + +**Pokud vaše AI umí číst soubory (Claude Code, Cursor atd.):** + +- **BMad nainstalován:** Nasměrujte na složku `_bmad` a ptejte se přímo +- **Chcete hlubší kontext:** Naklonujte si [celé repo](https://github.com/bmad-code-org/BMAD-METHOD) + +**Pokud používáte ChatGPT nebo Claude.ai:** + +Načtěte `llms-full.txt` do vaší relace: + +```text +https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt +``` + +### 3. Položte svou otázku + +:::note[Příklad] +**O:** „Řekni mi nejrychlejší způsob, jak něco vytvořit s BMad“ + +**A:** Použijte Quick Flow: Spusťte `bmad-quick-dev` — vyjasní váš záměr, naplánuje, implementuje, zreviduje a prezentuje výsledky v jednom workflow, přeskočí celé fáze plánování. +::: + +## Co získáte + +Přímé odpovědi o BMad — jak agenti fungují, co dělají workflow, proč jsou věci strukturované tak, jak jsou — bez čekání na odpověď od někoho jiného. + +## Tipy + +- **Ověřte překvapivé odpovědi** — LLM se občas mýlí. Zkontrolujte zdrojový soubor nebo se zeptejte na Discordu. +- **Buďte konkrétní** — „Co dělá krok 3 PRD workflow?“ je lepší než „Jak funguje PRD?“ + +## Stále jste uvízli? + +Zkusili jste přístup přes LLM a stále potřebujete pomoc? Nyní máte mnohem lepší otázku k položení. + +| Kanál | Použijte pro | +| ------------------------- | ------------------------------------------- | +| `#bmad-method-help` | Rychlé otázky (chat v reálném čase) | +| `help-requests` fórum | Detailní otázky (vyhledatelné, trvalé) | +| `#suggestions-feedback` | Nápady a požadavky na funkce | +| `#report-bugs-and-issues` | Hlášení chyb | + +**Discord:** [discord.gg/gk8jAdXWmj](https://discord.gg/gk8jAdXWmj) + +**GitHub Issues:** [github.com/bmad-code-org/BMAD-METHOD/issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) (pro jasné chyby) diff --git a/docs/cs/how-to/install-bmad.md b/docs/cs/how-to/install-bmad.md new file mode 100644 index 000000000..548b99e13 --- /dev/null +++ b/docs/cs/how-to/install-bmad.md @@ -0,0 +1,116 @@ +--- +title: "Jak nainstalovat BMad" +description: Průvodce instalací BMad ve vašem projektu krok za krokem +sidebar: + order: 1 +--- + +Použijte příkaz `npx bmad-method install` k nastavení BMad ve vašem projektu s výběrem modulů a AI nástrojů. + +Pokud chcete použít neinteraktivní instalátor a zadat všechny možnosti na příkazové řádce, podívejte se na [tento návod](./non-interactive-installation.md). + +## Kdy to použít + +- Začínáte nový projekt s BMad +- Přidáváte BMad do existující kódové báze +- Aktualizujete stávající instalaci BMad + +:::note[Předpoklady] +- **Node.js** 20+ (vyžadováno pro instalátor) +- **Git** (doporučeno) +- **AI nástroj** (Claude Code, Cursor nebo podobný) +::: + +## Kroky + +### 1. Spusťte instalátor + +```bash +npx bmad-method install +``` + +:::tip[Chcete nejnovější prereleaseový build?] +Použijte dist-tag `next`: +```bash +npx bmad-method@next install +``` + +Získáte novější změny dříve, s vyšší šancí na nestabilitu oproti výchozí instalaci. +::: + +:::tip[Bleeding edge] +Pro instalaci nejnovější verze z hlavní větve (může být nestabilní): +```bash +npx github:bmad-code-org/BMAD-METHOD install +``` +::: + +### 2. Zvolte umístění instalace + +Instalátor se zeptá, kam nainstalovat soubory BMad: + +- Aktuální adresář (doporučeno pro nové projekty, pokud jste adresář vytvořili sami a spouštíte z něj) +- Vlastní cesta + +### 3. Vyberte své AI nástroje + +Vyberte, které AI nástroje používáte: + +- Claude Code +- Cursor +- Ostatní + +Každý nástroj má svůj vlastní způsob integrace skills. Instalátor vytvoří drobné prompt soubory pro aktivaci workflow a agentů — jednoduše je umístí tam, kde je váš nástroj očekává. + +:::note[Povolení skills] +Některé platformy vyžadují explicitní povolení skills v nastavení, než se zobrazí. Pokud nainstalujete BMad a nevidíte skills, zkontrolujte nastavení vaší platformy nebo se zeptejte svého AI asistenta, jak skills povolit. +::: + +### 4. Zvolte moduly + +Instalátor zobrazí dostupné moduly. Vyberte ty, které potřebujete — většina uživatelů chce pouze **BMad Method** (modul pro vývoj softwaru). + +### 5. Následujte výzvy + +Instalátor vás provede zbytkem — vlastní obsah, nastavení atd. + +## Co získáte + +```text +váš-projekt/ +├── _bmad/ +│ ├── bmm/ # Vaše vybrané moduly +│ │ └── config.yaml # Nastavení modulu (pokud byste ho někdy potřebovali změnit) +│ ├── core/ # Povinný základní modul +│ └── ... +├── _bmad-output/ # Generované artefakty +├── .claude/ # Claude Code skills (pokud používáte Claude Code) +│ └── skills/ +│ ├── bmad-help/ +│ ├── bmad-persona/ +│ └── ... +└── .cursor/ # Cursor skills (pokud používáte Cursor) + └── skills/ + └── ... +``` + +## Ověření instalace + +Spusťte `bmad-help` pro ověření, že vše funguje, a zjistěte, co dělat dál. + +**BMad-Help je váš inteligentní průvodce**, který: +- Potvrdí, že vaše instalace funguje +- Ukáže, co je dostupné na základě nainstalovaných modulů +- Doporučí váš první krok + +Můžete mu také klást otázky: +``` +bmad-help I just installed, what should I do first? +bmad-help What are my options for a SaaS project? +``` + +## Řešení problémů + +**Instalátor vyhodí chybu** — Zkopírujte výstup do svého AI asistenta a nechte ho to vyřešit. + +**Instalátor fungoval, ale něco nefunguje později** — Vaše AI potřebuje kontext BMad, aby pomohla. Podívejte se na [Jak získat odpovědi o BMad](./get-answers-about-bmad.md) pro návod, jak nasměrovat AI na správné zdroje. diff --git a/docs/cs/how-to/non-interactive-installation.md b/docs/cs/how-to/non-interactive-installation.md new file mode 100644 index 000000000..12ea31eb3 --- /dev/null +++ b/docs/cs/how-to/non-interactive-installation.md @@ -0,0 +1,153 @@ +--- +title: Neinteraktivní instalace +description: Instalace BMad pomocí příznaků příkazové řádky pro CI/CD pipelines a automatizované nasazení +sidebar: + order: 2 +--- + +Použijte příznaky příkazové řádky k neinteraktivní instalaci BMad. To je užitečné pro: + +## Kdy to použít + +- Automatizovaná nasazení a CI/CD pipelines +- Skriptované instalace +- Hromadné instalace napříč více projekty +- Rychlé instalace se známými konfiguracemi + +:::note[Předpoklady] +Vyžaduje [Node.js](https://nodejs.org) v20+ a `npx` (součástí npm). +::: + +## Dostupné příznaky + +### Možnosti instalace + +| Příznak | Popis | Příklad | +|---------|-------|---------| +| `--directory ` | Instalační adresář | `--directory ~/projects/myapp` | +| `--modules ` | Čárkou oddělená ID modulů | `--modules bmm,bmb` | +| `--tools ` | Čárkou oddělená ID nástrojů/IDE (použijte `none` pro přeskočení) | `--tools claude-code,cursor` nebo `--tools none` | +| `--action ` | Akce pro existující instalace: `install` (výchozí), `update` nebo `quick-update` | `--action quick-update` | + +### Základní konfigurace + +| Příznak | Popis | Výchozí | +|---------|-------|---------| +| `--user-name ` | Jméno, které agenti použijí | Systémové uživatelské jméno | +| `--communication-language ` | Jazyk komunikace agentů | English | +| `--document-output-language ` | Jazyk výstupních dokumentů | English | +| `--output-folder ` | Cesta k výstupní složce | _bmad-output | + +### Další možnosti + +| Příznak | Popis | +|---------|-------| +| `-y, --yes` | Přijmout všechna výchozí nastavení a přeskočit výzvy | +| `-d, --debug` | Povolit ladící výstup pro generování manifestu | + +## ID modulů + +Dostupná ID modulů pro příznak `--modules`: + +- `bmm` — BMad Method Master +- `bmb` — BMad Builder + +Zkontrolujte [registr BMad](https://github.com/bmad-code-org) pro dostupné externí moduly. + +## ID nástrojů/IDE + +Dostupná ID nástrojů pro příznak `--tools`: + +**Preferované:** `claude-code`, `cursor` + +Spusťte `npx bmad-method install` interaktivně jednou pro zobrazení aktuálního seznamu podporovaných nástrojů, nebo zkontrolujte [konfiguraci kódů platforem](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/cli/installers/lib/ide/platform-codes.yaml). + +## Režimy instalace + +| Režim | Popis | Příklad | +|-------|-------|---------| +| Plně neinteraktivní | Zadejte všechny příznaky pro přeskočení výzev | `npx bmad-method install --directory . --modules bmm --tools claude-code --yes` | +| Polo-interaktivní | Zadejte některé příznaky; BMad se zeptá na zbytek | `npx bmad-method install --directory . --modules bmm` | +| Pouze výchozí | Přijměte vše výchozí s `-y` | `npx bmad-method install --yes` | +| Bez nástrojů | Přeskočte konfiguraci nástrojů/IDE | `npx bmad-method install --modules bmm --tools none` | + +## Příklady + +### Instalace v CI/CD pipeline + +```bash +#!/bin/bash +# install-bmad.sh + +npx bmad-method install \ + --directory "${GITHUB_WORKSPACE}" \ + --modules bmm \ + --tools claude-code \ + --user-name "CI Bot" \ + --communication-language English \ + --document-output-language English \ + --output-folder _bmad-output \ + --yes +``` + +### Aktualizace existující instalace + +```bash +npx bmad-method install \ + --directory ~/projects/myapp \ + --action update \ + --modules bmm,bmb,custom-module +``` + +### Rychlá aktualizace (zachování nastavení) + +```bash +npx bmad-method install \ + --directory ~/projects/myapp \ + --action quick-update +``` + +## Co získáte + +- Plně nakonfigurovaný adresář `_bmad/` ve vašem projektu +- Agenty a workflow nakonfigurované pro vybrané moduly a nástroje +- Složku `_bmad-output/` pro generované artefakty + +## Validace a zpracování chyb + +BMad validuje všechny zadané příznaky: + +- **Adresář** — Musí být platná cesta s oprávněním k zápisu +- **Moduly** — Upozorní na neplatná ID modulů (ale nespadne) +- **Nástroje** — Upozorní na neplatná ID nástrojů (ale nespadne) +- **Vlastní obsah** — Každá cesta musí obsahovat platný soubor `module.yaml` +- **Akce** — Musí být jedna z: `install`, `update`, `quick-update` + +Neplatné hodnoty buď: +1. Zobrazí chybu a ukončí se (pro kritické možnosti jako adresář) +2. Zobrazí varování a přeskočí (pro volitelné položky jako vlastní obsah) +3. Přepnou na interaktivní výzvy (pro chybějící povinné hodnoty) + +:::tip[Osvědčené postupy] +- Používejte absolutní cesty pro `--directory` pro zamezení nejednoznačnosti +- Otestujte příznaky lokálně před použitím v CI/CD pipelines +- Kombinujte s `-y` pro skutečně bezobslužné instalace +- Použijte `--debug` pokud narazíte na problémy během instalace +::: + +## Řešení problémů + +### Instalace selže s „Invalid directory“ + +- Cesta k adresáři musí existovat (nebo musí existovat jeho nadřazený adresář) +- Potřebujete oprávnění k zápisu +- Cesta musí být absolutní nebo správně relativní k aktuálnímu adresáři + +### Modul nenalezen + +- Ověřte, že ID modulu je správné +- Externí moduly musí být dostupné v registru + +:::note[Stále jste uvízli?] +Spusťte s `--debug` pro detailní výstup, zkuste interaktivní režim pro izolaci problému, nebo nahlaste na . +::: diff --git a/docs/cs/how-to/project-context.md b/docs/cs/how-to/project-context.md new file mode 100644 index 000000000..420e34ace --- /dev/null +++ b/docs/cs/how-to/project-context.md @@ -0,0 +1,127 @@ +--- +title: "Správa kontextu projektu" +description: Vytvoření a údržba project-context.md pro vedení AI agentů +sidebar: + order: 8 +--- + +Použijte soubor `project-context.md` k zajištění toho, aby AI agenti dodržovali technické preference a pravidla implementace vašeho projektu ve všech workflow. Aby byl vždy dostupný, můžete také přidat řádek `Important project context and conventions are located in [cesta k project context]/project-context.md` do souboru kontextu nebo pravidel vašeho nástroje (jako je `AGENTS.md`). + +:::note[Předpoklady] +- BMad Method nainstalován +- Znalost technologického stacku a konvencí vašeho projektu +::: + +## Kdy to použít + +- Máte silné technické preference před začátkem architektury +- Dokončili jste architekturu a chcete zachytit rozhodnutí pro implementaci +- Pracujete na existující kódové bázi se zavedenými vzory +- Všimnete si, že agenti dělají nekonzistentní rozhodnutí napříč stories + +## Krok 1: Vyberte přístup + +**Ruční vytvoření** — Nejlepší, když přesně víte, jaká pravidla chcete dokumentovat + +**Generování po architektuře** — Nejlepší pro zachycení rozhodnutí učiněných během solutioningu + +**Generování pro existující projekty** — Nejlepší pro objevení vzorů v existujících kódových bázích + +## Krok 2: Vytvořte soubor + +### Možnost A: Ruční vytvoření + +Vytvořte soubor na `_bmad-output/project-context.md`: + +```bash +mkdir -p _bmad-output +touch _bmad-output/project-context.md +``` + +Přidejte váš technologický stack a pravidla implementace: + +```markdown +--- +project_name: 'MyProject' +user_name: 'YourName' +date: '2026-02-15' +sections_completed: ['technology_stack', 'critical_rules'] +--- + +# Project Context for AI Agents + +## Technology Stack & Versions + +- Node.js 20.x, TypeScript 5.3, React 18.2 +- State: Zustand +- Testing: Vitest, Playwright +- Styling: Tailwind CSS + +## Critical Implementation Rules + +**TypeScript:** +- Strict mode enabled, no `any` types +- Use `interface` for public APIs, `type` for unions + +**Code Organization:** +- Components in `/src/components/` with co-located tests +- API calls use `apiClient` singleton — never fetch directly + +**Testing:** +- Unit tests focus on business logic +- Integration tests use MSW for API mocking +``` + +### Možnost B: Generování po architektuře + +Spusťte workflow v novém chatu: + +```bash +bmad-generate-project-context +``` + +Workflow skenuje váš dokument architektury a soubory projektu a generuje kontextový soubor zachycující učiněná rozhodnutí. + +### Možnost C: Generování pro existující projekty + +Pro existující projekty spusťte: + +```bash +bmad-generate-project-context +``` + +Workflow analyzuje vaši kódovou bázi, identifikuje konvence a vygeneruje kontextový soubor, který můžete zkontrolovat a upřesnit. + +## Krok 3: Ověřte obsah + +Zkontrolujte vygenerovaný soubor a ujistěte se, že zachycuje: + +- Správné verze technologií +- Vaše skutečné konvence (ne generické osvědčené postupy) +- Pravidla, která předcházejí běžným chybám +- Vzory specifické pro framework + +Ručně upravte pro doplnění chybějícího nebo odstranění nepřesností. + +## Co získáte + +Soubor `project-context.md`, který: + +- Zajistí, že všichni agenti dodržují stejné konvence +- Zabrání nekonzistentním rozhodnutím napříč stories +- Zachytí architektonická rozhodnutí pro implementaci +- Slouží jako reference pro vzory a pravidla vašeho projektu + +## Tipy + +:::tip[Osvědčené postupy] +- **Zaměřte se na neočividné** — Dokumentujte vzory, které agenti mohou přehlédnout (např. „Použijte JSDoc na každé veřejné třídě“), ne univerzální postupy jako „používejte smysluplné názvy proměnných.“ +- **Udržujte to stručné** — Tento soubor načítá každý implementační workflow. Dlouhé soubory plýtvají kontextem. Vylučte obsah, který platí pouze pro úzký rozsah nebo specifické stories. +- **Aktualizujte dle potřeby** — Upravte ručně, když se vzory změní, nebo přegenerujte po významných změnách architektury. +- Funguje pro projekty Quick Flow i plné metody BMad. +::: + +## Další kroky + +- [**Vysvětlení kontextu projektu**](../explanation/project-context.md) — Zjistěte více o tom, jak to funguje +- [**Mapa pracovních postupů**](../reference/workflow-map.md) — Podívejte se, které workflow načítají kontext projektu diff --git a/docs/cs/how-to/quick-fixes.md b/docs/cs/how-to/quick-fixes.md new file mode 100644 index 000000000..09f9484d6 --- /dev/null +++ b/docs/cs/how-to/quick-fixes.md @@ -0,0 +1,95 @@ +--- +title: "Rychlé opravy" +description: Jak provádět rychlé opravy a ad-hoc změny +sidebar: + order: 5 +--- + +Použijte **Quick Dev** pro opravy chyb, refaktoringy nebo malé cílené změny, které nevyžadují plnou metodu BMad. + +## Kdy to použít + +- Opravy chyb s jasnou, známou příčinou +- Malé refaktoringy (přejmenování, extrakce, restrukturalizace) omezené na několik souborů +- Drobné úpravy funkcí nebo změny konfigurace +- Aktualizace závislostí + +:::note[Předpoklady] +- BMad Method nainstalován (`npx bmad-method install`) +- AI-powered IDE (Claude Code, Cursor nebo podobné) +::: + +## Kroky + +### 1. Začněte nový chat + +Otevřete **novou chatovací relaci** ve vašem AI IDE. Opětovné použití relace z předchozího workflow může způsobit konflikty kontextu. + +### 2. Zadejte svůj záměr + +Quick Dev přijímá volně formulovaný záměr — před, s nebo po vyvolání. Příklady: + +```text +run quick-dev — Fix the login validation bug that allows empty passwords. +``` + +```text +run quick-dev — fix https://github.com/org/repo/issues/42 +``` + +```text +run quick-dev — implement the intent in _bmad-output/implementation-artifacts/my-intent.md +``` + +```text +I think the problem is in the auth middleware, it's not checking token expiry. +Let me look at it... yeah, src/auth/middleware.ts line 47 skips +the exp check entirely. run quick-dev +``` + +```text +run quick-dev +> What would you like to do? +Refactor UserService to use async/await instead of callbacks. +``` + +Prostý text, cesty k souborům, GitHub issue URL, odkazy na bug tracker — cokoli, co LLM dokáže převést na konkrétní záměr. + +### 3. Odpovězte na otázky a schvalte + +Quick Dev se může zeptat na upřesňující otázky nebo prezentovat krátkou specifikaci ke schválení před implementací. Odpovězte na otázky a schvalte, až budete s plánem spokojeni. + +### 4. Zkontrolujte a pushněte + +Quick Dev implementuje změnu, zreviduje svou práci, opraví problémy a commitne lokálně. Když je hotov, otevře dotčené soubory ve vašem editoru. + +- Projděte diff a potvrďte, že změna odpovídá vašemu záměru +- Pokud něco nevypadá dobře, řekněte agentovi, co opravit — může iterovat ve stejné relaci + +Až budete spokojeni, pushněte commit. Quick Dev nabídne push a vytvoření PR za vás. + +:::caution[Pokud se něco rozbije] +Pokud pushnutá změna způsobí neočekávané problémy, použijte `git revert HEAD` pro čisté vrácení posledního commitu. Poté začněte nový chat a spusťte Quick Dev znovu s jiným přístupem. +::: + +## Co získáte + +- Upravené zdrojové soubory s aplikovanou opravou nebo refaktoringem +- Procházející testy (pokud má váš projekt testovací sadu) +- Commit připravený k pushnutí s konvenční commit zprávou + +## Odložená práce + +Quick Dev udržuje každý běh zaměřený na jeden cíl. Pokud váš požadavek obsahuje více nezávislých cílů, nebo pokud revize odhalí předchozí problémy nesouvisející s vaší změnou, Quick Dev je odloží do souboru (`deferred-work.md` ve vašem adresáři implementačních artefaktů) místo toho, aby se pokusil vše řešit najednou. + +Zkontrolujte tento soubor po běhu — je to váš backlog věcí, ke kterým se vrátit. Každou odloženou položku lze zadat do nového běhu Quick Dev později. + +## Kdy přejít na formální plánování + +Zvažte použití plné metody BMad, když: + +- Změna ovlivňuje více systémů nebo vyžaduje koordinované aktualizace napříč mnoha soubory +- Nejste si jisti rozsahem a potřebujete nejprve zjišťování požadavků +- Potřebujete dokumentaci nebo architektonická rozhodnutí zaznamenaná pro tým + +Podívejte se na [Quick Dev](../explanation/quick-dev.md) pro více informací o tom, jak Quick Dev zapadá do metody BMad. diff --git a/docs/cs/how-to/shard-large-documents.md b/docs/cs/how-to/shard-large-documents.md new file mode 100644 index 000000000..53e059933 --- /dev/null +++ b/docs/cs/how-to/shard-large-documents.md @@ -0,0 +1,78 @@ +--- +title: "Průvodce dělením dokumentů" +description: Rozdělení velkých markdown souborů na menší organizované soubory pro lepší správu kontextu +sidebar: + order: 9 +--- + +Použijte nástroj `bmad-shard-doc`, pokud potřebujete rozdělit velké markdown soubory na menší, organizované soubory pro lepší správu kontextu. + +:::caution[Zastaralé] +Toto se již nedoporučuje a brzy s aktualizovanými workflow a většinou hlavních LLM a nástrojů podporujících subprocesy to bude zbytečné. +::: + +## Kdy to použít + +Použijte pouze pokud si všimnete, že váš zvolený nástroj / model nedokáže načíst a přečíst všechny dokumenty jako vstup, když je to potřeba. + +## Co je dělení dokumentů? + +Dělení dokumentů rozděluje velké markdown soubory na menší, organizované soubory na základě nadpisů úrovně 2 (`## Nadpis`). + +### Architektura + +```text +Před dělením: +_bmad-output/planning-artifacts/ +└── PRD.md (velký soubor o 50k tokenech) + +Po dělení: +_bmad-output/planning-artifacts/ +└── prd/ + ├── index.md # Obsah s popisy + ├── overview.md # Sekce 1 + ├── user-requirements.md # Sekce 2 + ├── technical-requirements.md # Sekce 3 + └── ... # Další sekce +``` + +## Kroky + +### 1. Spusťte nástroj Shard-Doc + +```bash +/bmad-shard-doc +``` + +### 2. Následujte interaktivní proces + +```text +Agent: Which document would you like to shard? +User: docs/PRD.md + +Agent: Default destination: docs/prd/ + Accept default? [y/n] +User: y + +Agent: Sharding PRD.md... + ✓ Created 12 section files + ✓ Generated index.md + ✓ Complete! +``` + +## Jak funguje vyhledávání workflow + +BMad workflow používají **duální systém vyhledávání**: + +1. **Nejprve zkusí celý dokument** — Hledá `document-name.md` +2. **Zkontroluje rozdělenou verzi** — Hledá `document-name/index.md` +3. **Pravidlo priority** — Celý dokument má přednost, pokud existují oba — odstraňte celý dokument, pokud chcete použít rozdělenou verzi + +## Podpora workflow + +Všechny BMM workflow podporují oba formáty: + +- Celé dokumenty +- Rozdělené dokumenty +- Automatická detekce +- Transparentní pro uživatele diff --git a/docs/cs/how-to/upgrade-to-v6.md b/docs/cs/how-to/upgrade-to-v6.md new file mode 100644 index 000000000..babe4c1af --- /dev/null +++ b/docs/cs/how-to/upgrade-to-v6.md @@ -0,0 +1,100 @@ +--- +title: "Jak upgradovat na v6" +description: Migrace z BMad v4 na v6 +sidebar: + order: 3 +--- + +Použijte instalátor BMad pro upgrade z v4 na v6, který zahrnuje automatickou detekci starších instalací a asistenci při migraci. + +## Kdy to použít + +- Máte nainstalovaný BMad v4 (složka `.bmad-method`) +- Chcete migrovat na novou architekturu v6 +- Máte existující plánovací artefakty k zachování + +:::note[Předpoklady] +- Node.js 20+ +- Existující instalace BMad v4 +::: + +## Kroky + +### 1. Spusťte instalátor + +Postupujte podle [instrukcí instalátoru](./install-bmad.md). + +### 2. Zpracování starší instalace + +Když je detekována v4, můžete: + +- Nechat instalátor zálohovat a odstranit `.bmad-method` +- Ukončit a zpracovat vyčištění ručně + +Pokud jste pojmenovali složku bmad method jinak, musíte ji odstranit ručně. + +### 3. Vyčištění IDE skills + +Ručně odstraňte starší v4 IDE příkazy/skills — například pokud máte Claude Code, hledejte vnořené složky začínající na bmad a odstraňte je: + +- `.claude/commands/` + +Nové v6 skills se instalují do: + +- `.claude/skills/` + +### 4. Migrace plánovacích artefaktů + +**Pokud máte plánovací dokumenty (Brief/PRD/UX/Architektura):** + +Přesuňte je do `_bmad-output/planning-artifacts/` s popisnými názvy: + +- Zahrňte `PRD` v názvu souboru pro PRD dokumenty +- Zahrňte `brief`, `architecture` nebo `ux-design` odpovídajícím způsobem +- Rozdělené dokumenty mohou být v pojmenovaných podsložkách + +**Pokud jste uprostřed plánování:** Zvažte restart s v6 workflow. Použijte existující dokumenty jako vstupy — nové workflow s progresivním objevováním, webovým vyhledáváním a plan mode IDE produkují lepší výsledky. + +### 5. Migrace probíhajícího vývoje + +Pokud máte vytvořené nebo implementované stories: + +1. Dokončete instalaci v6 +2. Umístěte `epics.md` nebo `epics/epic*.md` do `_bmad-output/planning-artifacts/` +3. Spusťte workflow `bmad-sprint-planning` Scrum Mastera +4. Řekněte SM, které epicy/stories jsou již dokončené + +## Co získáte + +**Sjednocená struktura v6:** + +```text +váš-projekt/ +├── _bmad/ # Jedna instalační složka +│ ├── _config/ # Vaše přizpůsobení +│ │ └── agents/ # Soubory přizpůsobení agentů +│ ├── core/ # Univerzální základní framework +│ ├── bmm/ # Modul BMad Method +│ ├── bmb/ # BMad Builder +│ └── cis/ # Creative Intelligence Suite +└── _bmad-output/ # Výstupní složka (v4 to byla složka dokumentů) +``` + +## Migrace modulů + +| Modul v4 | Stav v6 | +| ----------------------------- | ---------------------------------- | +| `.bmad-2d-phaser-game-dev` | Integrován do modulu BMGD | +| `.bmad-2d-unity-game-dev` | Integrován do modulu BMGD | +| `.bmad-godot-game-dev` | Integrován do modulu BMGD | +| `.bmad-infrastructure-devops` | Zastaralý — nový DevOps agent brzy | +| `.bmad-creative-writing` | Neadaptován — nový v6 modul brzy | + +## Klíčové změny + +| Koncept | v4 | v6 | +| --------------- | ------------------------------------ | -------------------------------------- | +| **Core** | `_bmad-core` byl vlastně BMad Method | `_bmad/core/` je univerzální framework | +| **Method** | `_bmad-method` | `_bmad/bmm/` | +| **Konfigurace** | Přímá editace souborů | `config.yaml` pro každý modul | +| **Dokumenty** | Vyžadované nastavení shardů | Plně flexibilní, auto-skenování | diff --git a/docs/cs/index.md b/docs/cs/index.md new file mode 100644 index 000000000..ade10d6a4 --- /dev/null +++ b/docs/cs/index.md @@ -0,0 +1,60 @@ +--- +title: Vítejte v metodě BMad +description: Framework pro vývoj řízený umělou inteligencí se specializovanými agenty, řízenými pracovními postupy a inteligentním plánováním +--- + +Metoda BMad (**B**uild **M**ore **A**rchitect **D**reams) je framework pro vývoj řízený umělou inteligencí v rámci ekosystému BMad Method, který vám pomáhá vytvářet software celým procesem od nápadu a plánování až po agentní implementaci. Poskytuje specializované AI agenty, řízené pracovní postupy a inteligentní plánování, které se přizpůsobí složitosti vašeho projektu, ať už opravujete chybu nebo budujete podnikovou platformu. + +Pokud jste zvyklí pracovat s AI asistenty pro kódování jako Claude, Cursor nebo GitHub Copilot, jste připraveni začít. + +:::note[🚀 V6 je tady a teprve začínáme!] +Architektura Skills, BMad Builder v1, automatizace Dev Loop a mnoho dalšího ve vývoji. **[Podívejte se na Plán rozvoje →](./roadmap)** +::: + +## Jste tu nově? Začněte tutoriálem + +Nejrychlejší způsob, jak pochopit BMad, je vyzkoušet si ho. + +- **[Začínáme s BMad](./tutorials/getting-started.md)** — Instalace a pochopení fungování BMad +- **[Mapa pracovních postupů](./reference/workflow-map.md)** — Vizuální přehled fází BMM, pracovních postupů a správy kontextu + +:::tip[Chcete se rovnou ponořit?] +Nainstalujte BMad a použijte skill `bmad-help` — provede vás vším na základě vašeho projektu a nainstalovaných modulů. +::: + +## Jak používat tuto dokumentaci + +Tato dokumentace je organizována do čtyř sekcí podle toho, co chcete dělat: + +| Sekce | Účel | +| -------------------- | ------------------------------------------------------------------------------------------------------------------ | +| **Tutoriály** | Orientované na učení. Průvodci krok za krokem, kteří vás provedou tvorbou něčeho. Začněte zde, pokud jste noví. | +| **Praktické návody** | Orientované na úkoly. Praktičtí průvodci pro řešení konkrétních problémů. „Jak přizpůsobím agenta?“ najdete zde. | +| **Vysvětlení** | Orientované na pochopení. Hluboké ponory do konceptů a architektury. Čtěte, když chcete vědět *proč*. | +| **Reference** | Orientované na informace. Technické specifikace agentů, pracovních postupů a konfigurace. | + +## Rozšíření a přizpůsobení + +Chcete rozšířit BMad o vlastní agenty, pracovní postupy nebo moduly? **[BMad Builder](https://bmad-builder-docs.bmad-method.org/)** poskytuje framework a nástroje pro vytváření vlastních rozšíření, ať už přidáváte nové schopnosti do BMad nebo budujete zcela nové moduly od základů. + +## Co budete potřebovat + +BMad funguje s jakýmkoli AI asistentem pro kódování, který podporuje vlastní systémové prompty nebo kontextové soubory projektu. Oblíbené možnosti zahrnují: + +- **[Claude Code](https://code.claude.com)** — CLI nástroj od Anthropic (doporučený) +- **[Cursor](https://cursor.sh)** — AI-first editor kódu +- **[Codex CLI](https://github.com/openai/codex)** — Terminálový kódovací agent od OpenAI + +Měli byste být obeznámeni se základními koncepty vývoje softwaru jako správa verzí, struktura projektu a agilní pracovní postupy. Žádná předchozí zkušenost se systémy agentů ve stylu BMad není vyžadována — právě od toho je tato dokumentace. + +## Připojte se ke komunitě + +Získejte pomoc, sdílejte co budujete, nebo přispějte do BMad: + +- **[Discord](https://discord.gg/gk8jAdXWmj)** — Chatujte s ostatními uživateli BMad, pokládejte otázky, sdílejte nápady +- **[GitHub](https://github.com/bmad-code-org/BMAD-METHOD)** — Zdrojový kód, issues a příspěvky +- **[YouTube](https://www.youtube.com/@BMadCode)** — Video tutoriály a návody + +## Další krok + +Jste připraveni se ponořit? **[Začněte s BMad](./tutorials/getting-started.md)** a vytvořte svůj první projekt. diff --git a/docs/cs/reference/agents.md b/docs/cs/reference/agents.md new file mode 100644 index 000000000..6b2d81c87 --- /dev/null +++ b/docs/cs/reference/agents.md @@ -0,0 +1,55 @@ +--- +title: Agenti +description: Výchozí BMM agenti s jejich skill ID, spouštěči nabídky a primárními workflow +sidebar: + order: 2 +--- + +## Výchozí agenti + +Tato stránka uvádí výchozí BMM (Agile suite) agenty, kteří se instalují s BMad Method, společně s jejich skill ID, spouštěči nabídky a primárními workflow. Každý agent se vyvolává jako skill. + +## Poznámky + +- Každý agent je dostupný jako skill, generovaný instalátorem. Skill ID (např. `bmad-dev`) se používá k vyvolání agenta. +- Spouštěče jsou krátké kódy nabídky (např. `CP`) a fuzzy shody zobrazené v nabídce každého agenta. +- Generování QA testů zajišťuje workflow skill `bmad-qa-generate-e2e-tests`, dostupný přes Developer agenta. Plný Test Architect (TEA) žije ve vlastním modulu. + +| Agent | Skill ID | Spouštěče | Primární workflow | +| --------------------------- | -------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| Analyst (Mary) | `bmad-analyst` | `BP`, `MR`, `DR`, `TR`, `CB`, `WB`, `DP` | Brainstorm, průzkum trhu, doménový výzkum, technický výzkum, tvorba briefu, PRFAQ výzva, dokumentace projektu | +| Product Manager (John) | `bmad-pm` | `CP`, `VP`, `EP`, `CE`, `IR`, `CC` | Tvorba/validace/editace PRD, tvorba epiců a stories, připravenost implementace, korekce kurzu | +| Architect (Winston) | `bmad-architect` | `CA`, `IR` | Tvorba architektury, připravenost implementace | +| Developer (Amelia) | `bmad-agent-dev` | `DS`, `QD`, `QA`, `CR`, `SP`, `CS`, `ER` | Dev story, Quick Dev, generování QA testů, revize kódu, plánování sprintu, tvorba story, retrospektiva epicu | +| UX Designer (Sally) | `bmad-ux-designer` | `CU` | Tvorba UX designu | +| Technical Writer (Paige) | `bmad-tech-writer` | `DP`, `WD`, `US`, `MG`, `VD`, `EC` | Dokumentace projektu, psaní dokumentu, aktualizace standardů, generování Mermaid, validace dok., vysvětlení konceptu | + +## Typy spouštěčů + +Spouštěče nabídky agentů používají dva různé typy vyvolání. Znalost typu spouštěče vám pomůže poskytnout správný vstup. + +### Workflow spouštěče (bez argumentů) + +Většina spouštěčů načítá strukturovaný soubor workflow. Zadejte kód spouštěče a agent zahájí workflow a vyzve vás k zadání vstupu v každém kroku. + +Příklady: `CP` (tvorba PRD), `DS` (Dev story), `CA` (tvorba architektury), `QD` (Quick Dev) + +### Konverzační spouštěče (vyžadují argumenty) + +Některé spouštěče zahajují volnou konverzaci místo strukturovaného workflow. Tyto očekávají, že popíšete, co potřebujete, společně s kódem spouštěče. + +| Agent | Spouštěč | Co poskytnout | +| --- | --- | --- | +| Technical Writer (Paige) | `WD` | Popis dokumentu k napsání | +| Technical Writer (Paige) | `US` | Preference nebo konvence k přidání do standardů | +| Technical Writer (Paige) | `MG` | Popis diagramu a typ (sekvence, vývojový diagram atd.) | +| Technical Writer (Paige) | `VD` | Dokument k validaci a oblasti zaměření | +| Technical Writer (Paige) | `EC` | Název konceptu k vysvětlení | + +**Příklad:** + +```text +WD Write a deployment guide for our Docker setup +MG Create a sequence diagram showing the auth flow +EC Explain how the module system works +``` diff --git a/docs/cs/reference/commands.md b/docs/cs/reference/commands.md new file mode 100644 index 000000000..e3bb52a2b --- /dev/null +++ b/docs/cs/reference/commands.md @@ -0,0 +1,135 @@ +--- +title: Skills +description: Reference BMad skills — co to je, jak fungují a kde je najít. +sidebar: + order: 3 +--- + +Skills jsou předpřipravené prompty, které načítají agenty, spouštějí workflow nebo provádějí úkoly ve vašem IDE. Instalátor BMad je generuje z vašich nainstalovaných modulů při instalaci. Pokud později přidáte, odeberete nebo změníte moduly, přeinstalujte pro synchronizaci skills (viz [Řešení problémů](#řešení-problémů)). + +## Skills vs. spouštěče nabídky agentů + +BMad nabízí dva způsoby zahájení práce a slouží k různým účelům. + +| Mechanismus | Jak se vyvolává | Co se stane | +| --- | --- | --- | +| **Skill** | Zadejte název skillu (např. `bmad-help`) ve vašem IDE | Přímo načte agenta, spustí workflow nebo provede úkol | +| **Spouštěč nabídky agenta** | Nejprve načtěte agenta, pak zadejte krátký kód (např. `DS`) | Agent interpretuje kód a spustí odpovídající workflow, přičemž zůstává v charakteru | + +Spouštěče nabídky agentů vyžadují aktivní relaci agenta. Používejte skills, když víte, který workflow chcete. Používejte spouštěče, když již pracujete s agentem a chcete přepnout úkol bez opuštění konverzace. + +## Jak se skills generují + +Když spustíte `npx bmad-method install`, instalátor čte manifesty každého vybraného modulu a zapíše jeden skill na agenta, workflow, úkol a nástroj. Každý skill je adresář obsahující soubor `SKILL.md`, který instruuje AI k načtení odpovídajícího zdrojového souboru a následování jeho instrukcí. + +Instalátor používá šablony pro každý typ skillu: + +| Typ skillu | Co generovaný soubor dělá | +| --- | --- | +| **Spouštěč agenta** | Načte soubor persony agenta, aktivuje jeho nabídku a zůstává v charakteru | +| **Workflow skill** | Načte konfiguraci workflow a následuje jeho kroky | +| **Task skill** | Načte samostatný soubor úkolu a následuje jeho instrukce | +| **Tool skill** | Načte samostatný soubor nástroje a následuje jeho instrukce | + +:::note[Opětovné spuštění instalátoru] +Pokud přidáte nebo odeberete moduly, spusťte instalátor znovu. Přegeneruje všechny soubory skills tak, aby odpovídaly vašemu aktuálnímu výběru modulů. +::: + +## Kde žijí soubory skills + +Instalátor zapisuje soubory skills do adresáře specifického pro IDE uvnitř vašeho projektu. Přesná cesta závisí na IDE, které jste vybrali během instalace. + +| IDE / CLI | Adresář skills | +| --- | --- | +| Claude Code | `.claude/skills/` | +| Cursor | `.cursor/skills/` | +| Windsurf | `.windsurf/skills/` | +| Další IDE | Viz výstup instalátoru pro cílovou cestu | + +Každý skill je adresář obsahující soubor `SKILL.md`. Například instalace Claude Code vypadá takto: + +```text +.claude/skills/ +├── bmad-help/ +│ └── SKILL.md +├── bmad-create-prd/ +│ └── SKILL.md +├── bmad-agent-dev/ +│ └── SKILL.md +└── ... +``` + +Název adresáře určuje název skillu ve vašem IDE. Například adresář `bmad-agent-dev/` registruje skill `bmad-agent-dev`. + +## Jak objevit vaše skills + +Zadejte název skillu ve vašem IDE pro jeho vyvolání. Některé platformy vyžadují povolení skills v nastavení, než se zobrazí. + +Spusťte `bmad-help` pro kontextové poradenství k dalšímu kroku. + +:::tip[Rychlé objevování] +Generované adresáře skills ve vašem projektu jsou kanonický seznam. Otevřete je v prohlížeči souborů, abyste viděli každý skill s jeho popisem. +::: + +## Kategorie skills + +### Agentní skills + +Agentní skills načítají specializovanou AI personu s definovanou rolí, komunikačním stylem a nabídkou workflow. Po načtení agent zůstává v charakteru a reaguje na spouštěče nabídky. + +| Příklad skillu | Agent | Role | +| --- | --- | --- | +| `bmad-agent-dev` | Amelia (Developer) | Implementuje stories s přísným dodržováním specifikací | +| `bmad-pm` | John (Product Manager) | Vytváří a validuje PRD | +| `bmad-architect` | Winston (Architect) | Navrhuje systémovou architekturu | + +Viz [Agenti](./agents.md) pro úplný seznam výchozích agentů a jejich spouštěčů. + +### Workflow skills + +Workflow skills spouštějí strukturovaný, vícekrokový proces bez předchozího načtení persony agenta. Načtou konfiguraci workflow a následují jeho kroky. + +| Příklad skillu | Účel | +| --- | --- | +| `bmad-product-brief` | Vytvoření product briefu — řízené discovery, když je váš koncept jasný | +| `bmad-prfaq` | [Working Backwards PRFAQ](../explanation/analysis-phase.md#prfaq-working-backwards) výzva pro zátěžový test vašeho produktového konceptu | +| `bmad-create-prd` | Vytvoření dokumentu požadavků (PRD) | +| `bmad-create-architecture` | Návrh systémové architektury | +| `bmad-create-epics-and-stories` | Vytvoření epiců a stories | +| `bmad-dev-story` | Implementace story | +| `bmad-code-review` | Spuštění revize kódu | +| `bmad-quick-dev` | Sjednocený quick flow — vyjasnění záměru, plán, implementace, revize, prezentace | + +Viz [Mapa pracovních postupů](./workflow-map.md) pro kompletní referenci workflow organizovanou podle fází. + +### Task a tool skills + +Tasks a tools jsou samostatné operace, které nevyžadují kontext agenta nebo workflow. + +**BMad-Help: Váš inteligentní průvodce** + +`bmad-help` je vaše primární rozhraní pro objevení, co dělat dál. Zkoumá váš projekt, rozumí dotazům v přirozeném jazyce a doporučuje další povinný nebo volitelný krok na základě nainstalovaných modulů. + +:::note[Příklad] +``` +bmad-help +bmad-help I have a SaaS idea and know all the features. Where do I start? +bmad-help What are my options for UX design? +``` +::: + +**Další základní tasks a tools** + +Základní modul zahrnuje 11 vestavěných nástrojů — revize, komprese, brainstorming, správa dokumentů a další. Viz [Základní nástroje](./core-tools.md) pro kompletní referenci. + +## Konvence pojmenování + +Všechny skills používají prefix `bmad-` následovaný popisným názvem (např. `bmad-dev`, `bmad-create-prd`, `bmad-help`). Viz [Moduly](./modules.md) pro dostupné moduly. + +## Řešení problémů + +**Skills se nezobrazují po instalaci.** Některé platformy vyžadují explicitní povolení skills v nastavení. Zkontrolujte dokumentaci vašeho IDE nebo se zeptejte AI asistenta, jak skills povolit. Může být také nutné restartovat IDE nebo znovu načíst okno. + +**Očekávané skills chybí.** Instalátor generuje skills pouze pro moduly, které jste vybrali. Spusťte `npx bmad-method install` znovu a ověřte výběr modulů. Zkontrolujte, že soubory skills existují v očekávaném adresáři. + +**Skills z odebraného modulu se stále zobrazují.** Instalátor automaticky nemaže staré soubory skills. Odstraňte zastaralé adresáře z adresáře skills vašeho IDE, nebo smažte celý adresář skills a přeinstalujte pro čistou sadu. diff --git a/docs/cs/reference/core-tools.md b/docs/cs/reference/core-tools.md new file mode 100644 index 000000000..1fca20336 --- /dev/null +++ b/docs/cs/reference/core-tools.md @@ -0,0 +1,292 @@ +--- +title: Základní nástroje +description: Reference všech vestavěných úkolů a workflow dostupných v každé instalaci BMad bez dalších modulů. +sidebar: + order: 2 +--- + +Každá instalace BMad zahrnuje sadu základních skills, které lze použít v kombinaci s čímkoli — samostatné úkoly a workflow, které fungují napříč všemi projekty, všemi moduly a všemi fázemi. Ty jsou vždy dostupné bez ohledu na to, které volitelné moduly nainstalujete. + +:::tip[Rychlá cesta] +Spusťte jakýkoli základní nástroj zadáním jeho názvu skillu (např. `bmad-help`) ve vašem IDE. Nevyžaduje relaci agenta. +::: + +## Přehled + +| Nástroj | Typ | Účel | +| --- | --- | --- | +| [`bmad-help`](#bmad-help) | Task | Kontextové poradenství, co dělat dál | +| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | Facilitace interaktivních brainstormingových sezení | +| [`bmad-party-mode`](#bmad-party-mode) | Workflow | Orchestrace skupinových diskuzí více agentů | +| [`bmad-distillator`](#bmad-distillator) | Task | Bezeztrátová LLM-optimalizovaná komprese dokumentů | +| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Task | Iterativní zdokonalování LLM výstupu | +| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Task | Cynická revize hledající chybějící a chybné | +| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Task | Vyčerpávající analýza větvících cest pro neošetřené hraniční případy | +| [`bmad-editorial-review-prose`](#bmad-editorial-review-prose) | Task | Klinická jazyková korektura pro komunikační srozumitelnost | +| [`bmad-editorial-review-structure`](#bmad-editorial-review-structure) | Task | Strukturální editace — škrty, sloučení a reorganizace | +| [`bmad-shard-doc`](#bmad-shard-doc) | Task | Rozdělení velkých markdown souborů do organizovaných sekcí | +| [`bmad-index-docs`](#bmad-index-docs) | Task | Generování nebo aktualizace indexu dokumentů ve složce | + +## bmad-help + +**Váš inteligentní průvodce tím, co přijde dál.** — Zkoumá stav vašeho projektu, detekuje, co bylo uděláno, a doporučuje další povinný nebo volitelný krok. + +**Použijte když:** + +- Dokončili jste workflow a chcete vědět, co dál +- Jste noví v BMad a potřebujete orientaci +- Jste uvízlí a chcete kontextovou radu +- Nainstalovali jste nové moduly a chcete vidět, co je dostupné + +**Jak to funguje:** + +1. Skenuje projekt pro existující artefakty (PRD, architektura, stories atd.) +2. Detekuje nainstalované moduly a dostupné workflow +3. Doporučuje další kroky v pořadí priority — nejprve povinné, pak volitelné +4. Prezentuje každé doporučení s příkazem skillu a stručným popisem + +**Vstup:** Volitelný dotaz v přirozeném jazyce (např. `bmad-help I have a SaaS idea, where do I start?`) + +**Výstup:** Prioritizovaný seznam doporučených dalších kroků s příkazy skills + +## bmad-brainstorming + +**Generování různorodých nápadů prostřednictvím interaktivních kreativních technik.** — Facilitované brainstormingové sezení, které načítá osvědčené ideační metody z knihovny technik a vede vás k 100+ nápadům před organizací. + +**Použijte když:** + +- Začínáte nový projekt a potřebujete prozkoumat problémový prostor +- Jste uvízlí s generováním nápadů a potřebujete strukturovanou kreativitu +- Chcete použít osvědčené ideační frameworky (SCAMPER, reverzní brainstorming atd.) + +**Jak to funguje:** + +1. Nastaví brainstormingové sezení s vaším tématem +2. Načte kreativní techniky z knihovny metod +3. Provede vás technikou za technikou, generuje nápady +4. Aplikuje anti-bias protokol — mění kreativní doménu každých 10 nápadů +5. Produkuje append-only dokument sezení se všemi nápady organizovanými podle techniky + +**Vstup:** Téma brainstormingu nebo formulace problému, volitelný kontextový soubor + +**Výstup:** `brainstorming-session-{date}.md` se všemi generovanými nápady + +:::note[Cíl množství] +Kouzlo se děje v nápadech 50–100. Workflow povzbuzuje generování 100+ nápadů před organizací. +::: + +## bmad-party-mode + +**Orchestrace skupinových diskuzí více agentů.** — Načte všechny nainstalované BMad agenty a facilituje přirozenou konverzaci, kde každý agent přispívá svou unikátní odborností a osobností. + +**Použijte když:** + +- Potřebujete více expertních perspektiv na rozhodnutí +- Chcete, aby agenti zpochybňovali předpoklady ostatních +- Zkoumáte složité téma překračující více domén + +**Jak to funguje:** + +1. Načte manifest agentů se všemi nainstalovanými osobnostmi +2. Analyzuje vaše téma a vybere 2–3 nejrelevantnější agenty +3. Agenti se střídají v přispívání, s přirozenou kříženou diskuzí a nesouhlasy +4. Rotuje účast agentů pro zajištění různorodých perspektiv +5. Ukončete pomocí `goodbye`, `end party` nebo `quit` + +**Vstup:** Diskuzní téma nebo otázka, s volitelnou specifikací person + +**Výstup:** Real-time multi-agentní konverzace s udržovanými osobnostmi agentů + +## bmad-distillator + +**Bezeztrátová LLM-optimalizovaná komprese zdrojových dokumentů.** — Produkuje husté, tokenově efektivní destiláty, které zachovávají všechny informace pro následné LLM zpracování. Ověřitelné prostřednictvím round-trip rekonstrukce. + +**Použijte když:** + +- Dokument je příliš velký pro kontextové okno LLM +- Potřebujete tokenově efektivní verze výzkumů, specifikací nebo plánovacích artefaktů +- Chcete ověřit, že během komprese nebyly ztraceny žádné informace + +**Jak to funguje:** + +1. **Analýza** — Čte zdrojové dokumenty, identifikuje hustotu informací a strukturu +2. **Komprese** — Převádí prózu na hustý odrážkový formát, odstraňuje dekorativní formátování +3. **Ověření** — Kontroluje úplnost pro zajištění zachování všech informací +4. **Validace** (volitelné) — Round-trip rekonstrukční test dokazuje bezeztrátovou kompresi + +**Vstup:** + +- `source_documents` (povinné) — Cesty k souborům, složkám nebo glob vzory +- `downstream_consumer` (volitelné) — Co to konzumuje (např. „tvorba PRD“) +- `token_budget` (volitelné) — Přibližná cílová velikost +- `--validate` (příznak) — Spuštění round-trip rekonstrukčního testu + +**Výstup:** Destilátové markdown soubory s reportem kompresního poměru (např. „3.2:1“) + +## bmad-advanced-elicitation + +**Iterativní zdokonalování LLM výstupu metodami elicitace.** — Vybírá z knihovny elicitačních technik pro systematické zlepšování obsahu více průchody. + +**Použijte když:** + +- LLM výstup působí povrchně nebo genericky +- Chcete prozkoumat téma z více analytických úhlů +- Zdokonalujete kritický dokument a chcete hlubší myšlení + +**Jak to funguje:** + +1. Načte registr metod s 5+ elicitačními technikami +2. Vybere 5 nejlépe odpovídajících metod podle typu a složitosti obsahu +3. Prezentuje interaktivní nabídku — vyberte metodu, zamíchejte nebo zobrazte vše +4. Aplikuje vybranou metodu k vylepšení obsahu +5. Znovu prezentuje možnosti pro iterativní zlepšení, dokud nevyberete „Pokračovat“ + +**Vstup:** Sekce obsahu k vylepšení + +**Výstup:** Vylepšená verze obsahu s aplikovanými zlepšeními + +## bmad-review-adversarial-general + +**Cynická revize, která předpokládá existenci problémů a hledá je.** — Zaujme perspektivu skeptického, otráveného recenzenta s nulovou tolerancí pro nedbalou práci. Hledá, co chybí, ne jen co je špatně. + +**Použijte když:** + +- Potřebujete zajištění kvality před finalizací výstupu +- Chcete zátěžově otestovat specifikaci, story nebo dokument +- Chcete najít mezery v pokrytí, které optimistické revize přehlédnou + +**Jak to funguje:** + +1. Čte obsah s cynickou, kritickou perspektivou +2. Identifikuje problémy v úplnosti, správnosti a kvalitě +3. Specificky hledá, co chybí — ne jen co je přítomné a špatné +4. Musí najít minimálně 10 problémů nebo analyzuje hlouběji + +**Vstup:** + +- `content` (povinné) — Diff, specifikace, story, dokument nebo jakýkoli artefakt +- `also_consider` (volitelné) — Další oblasti k zvážení + +**Výstup:** Markdown seznam 10+ nálezů s popisy + +## bmad-review-edge-case-hunter + +**Procházení každé větvící cesty a hraničních podmínek, hlášení pouze neošetřených případů.** — Čistě metodologický přístup trasování cest, který mechanicky odvozuje třídy hraničních případů. + +**Použijte když:** + +- Chcete vyčerpávající pokrytí hraničních případů pro kód nebo logiku +- Potřebujete doplněk k adversariální revizi (jiná metodologie, jiné nálezy) +- Revidujete diff nebo funkci pro hraniční podmínky + +**Jak to funguje:** + +1. Enumeruje všechny větvící cesty v obsahu +2. Mechanicky odvozuje třídy případů: chybějící else/default, nestřežené vstupy, off-by-one, přetečení aritmetiky, implicitní typová koerce, race conditions, mezery v timeoutech +3. Testuje každou cestu proti existujícím ochranám +4. Hlásí pouze neošetřené cesty — tiše zahazuje ošetřené + +**Vstup:** + +- `content` (povinné) — Diff, celý soubor nebo funkce +- `also_consider` (volitelné) — Další oblasti k zvážení + +**Výstup:** JSON pole nálezů, každý s `location`, `trigger_condition`, `guard_snippet` a `potential_consequence` + +:::note[Komplementární revize] +Spusťte obě `bmad-review-adversarial-general` a `bmad-review-edge-case-hunter` společně pro ortogonální pokrytí. Adversariální revize zachytí problémy kvality a úplnosti; hunter hraničních případů zachytí neošetřené cesty. +::: + +## bmad-editorial-review-prose + +**Klinická jazyková korektura zaměřená na srozumitelnost komunikace.** — Reviduje text pro problémy bránící porozumění. Aplikuje baseline Microsoft Writing Style Guide. Zachovává autorský hlas. + +**Použijte když:** + +- Napsali jste dokument a chcete vylepšit psaní +- Potřebujete zajistit srozumitelnost pro konkrétní publikum +- Chcete komunikační opravy bez změn stylistických preferencí + +**Jak to funguje:** + +1. Čte obsah, přeskakuje bloky kódu a frontmatter +2. Identifikuje komunikační problémy (ne stylistické preference) +3. Deduplikuje stejné problémy napříč více lokacemi +4. Produkuje třísloupcovou tabulku oprav + +**Vstup:** + +- `content` (povinné) — Markdown, prostý text nebo XML +- `style_guide` (volitelné) — Projektově specifický průvodce stylem +- `reader_type` (volitelné) — `humans` (výchozí) pro srozumitelnost/plynulost, nebo `llm` pro přesnost/konzistenci + +**Výstup:** Třísloupcová markdown tabulka: Původní text | Revidovaný text | Změny + +## bmad-editorial-review-structure + +**Strukturální editace — navrhuje škrty, sloučení, přesuny a zhuštění.** — Reviduje organizaci dokumentu a navrhuje substantivní změny pro zlepšení srozumitelnosti a toku před jazykovou korekcí. + +**Použijte když:** + +- Dokument byl vytvořen z více subprocesů a potřebuje strukturální koherenci +- Chcete zkrátit dokument při zachování porozumění +- Potřebujete identifikovat porušení rozsahu nebo pohřbené kritické informace + +**Jak to funguje:** + +1. Analyzuje dokument proti 5 strukturním modelům (Tutorial, Reference, Explanation, Prompt, Strategic) +2. Identifikuje redundance, porušení rozsahu a pohřbené informace +3. Produkuje prioritizovaná doporučení: CUT, MERGE, MOVE, CONDENSE, QUESTION, PRESERVE +4. Odhaduje celkovou redukci ve slovech a procentech + +**Vstup:** + +- `content` (povinné) — Dokument k revizi +- `purpose` (volitelné) — Zamýšlený účel (např. „quickstart tutoriál“) +- `target_audience` (volitelné) — Kdo to čte +- `reader_type` (volitelné) — `humans` nebo `llm` +- `length_target` (volitelné) — Cílová redukce (např. „o 30 % kratší“) + +**Výstup:** Shrnutí dokumentu, prioritizovaný seznam doporučení a odhadovaná redukce + +## bmad-shard-doc + +**Rozdělení velkých markdown souborů do organizovaných souborů sekcí.** — Používá nadpisy úrovně 2 jako body dělení k vytvoření složky samostatných souborů sekcí s indexem. + +**Použijte když:** + +- Markdown dokument narostl na nezvládnutelnou velikost (500+ řádků) +- Chcete rozložit monolitický dokument na navigovatelné sekce +- Potřebujete samostatné soubory pro paralelní editaci nebo správu LLM kontextu + +**Jak to funguje:** + +1. Validuje, že zdrojový soubor existuje a je markdown +2. Dělí na nadpisech úrovně 2 (`##`) do číslovaných souborů sekcí +3. Vytváří `index.md` s manifestem sekcí a odkazy +4. Vyzve vás ke smazání, archivaci nebo zachování originálu + +**Vstup:** Cesta ke zdrojovému markdown souboru, volitelná cílová složka + +**Výstup:** Složka s `index.md` a `01-{sekce}.md`, `02-{sekce}.md` atd. + +## bmad-index-docs + +**Generování nebo aktualizace indexu všech dokumentů ve složce.** — Skenuje adresář, čte každý soubor pro pochopení jeho účelu a produkuje organizovaný `index.md` s odkazy a popisy. + +**Použijte když:** + +- Potřebujete lehký index pro rychlé LLM skenování dostupných dokumentů +- Složka dokumentace narostla a potřebuje organizovaný obsah +- Chcete automaticky generovaný přehled, který zůstává aktuální + +**Jak to funguje:** + +1. Skenuje cílový adresář pro všechny neskryté soubory +2. Čte každý soubor pro pochopení jeho skutečného účelu +3. Seskupuje soubory podle typu, účelu nebo podadresáře +4. Generuje stručné popisy (3–10 slov každý) + +**Vstup:** Cesta k cílové složce + +**Výstup:** `index.md` s organizovanými výpisy souborů, relativními odkazy a stručnými popisy diff --git a/docs/cs/reference/modules.md b/docs/cs/reference/modules.md new file mode 100644 index 000000000..792d28246 --- /dev/null +++ b/docs/cs/reference/modules.md @@ -0,0 +1,76 @@ +--- +title: Oficiální moduly +description: Doplňkové moduly pro tvorbu vlastních agentů, kreativní inteligenci, vývoj her a testování +sidebar: + order: 4 +--- + +BMad se rozšiřuje prostřednictvím oficiálních modulů, které vyberete během instalace. Tyto doplňkové moduly poskytují specializované agenty, workflow a úkoly pro specifické domény nad rámec vestavěného jádra a BMM (Agile suite). + +:::tip[Instalace modulů] +Spusťte `npx bmad-method install` a vyberte požadované moduly. Instalátor se postará o stažení, konfiguraci a integraci s IDE automaticky. +::: + +## BMad Builder + +Vytvářejte vlastní agenty, workflow a doménově specifické moduly s řízenou asistencí. BMad Builder je meta-modul pro rozšiřování samotného frameworku. + +- **Kód:** `bmb` +- **npm:** [`bmad-builder`](https://www.npmjs.com/package/bmad-builder) +- **GitHub:** [bmad-code-org/bmad-builder](https://github.com/bmad-code-org/bmad-builder) + +**Poskytuje:** + +- Agent Builder — tvorba specializovaných AI agentů s vlastní odborností a přístupem k nástrojům +- Workflow Builder — návrh strukturovaných procesů s kroky a rozhodovacími body +- Module Builder — balíčkování agentů a workflow do sdílitelných, publikovatelných modulů +- Interaktivní nastavení s YAML konfigurací a podporou npm publikování + +## Creative Intelligence Suite + +AI nástroje pro strukturovanou kreativitu, ideaci a inovace v rané fázi vývoje. Suite poskytuje více agentů, kteří facilitují brainstorming, design thinking a řešení problémů pomocí osvědčených frameworků. + +- **Kód:** `cis` +- **npm:** [`bmad-creative-intelligence-suite`](https://www.npmjs.com/package/bmad-creative-intelligence-suite) +- **GitHub:** [bmad-code-org/bmad-module-creative-intelligence-suite](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite) + +**Poskytuje:** + +- Agenty Innovation Strategist, Design Thinking Coach a Brainstorming Coach +- Problem Solver a Creative Problem Solver pro systematické a laterální myšlení +- Storyteller a Presentation Master pro narativy a prezentace +- Ideační frameworky včetně SCAMPER, reverzního brainstormingu a přeformulování problémů + +## Game Dev Studio + +Strukturované workflow pro vývoj her adaptované pro Unity, Unreal, Godot a vlastní enginy. Podporuje rychlé prototypování přes Quick Flow a plnoscálovou produkci s epicky řízenými sprinty. + +- **Kód:** `gds` +- **npm:** [`bmad-game-dev-studio`](https://www.npmjs.com/package/bmad-game-dev-studio) +- **GitHub:** [bmad-code-org/bmad-module-game-dev-studio](https://github.com/bmad-code-org/bmad-module-game-dev-studio) + +**Poskytuje:** + +- Workflow pro generování Game Design Document (GDD) +- Režim Quick Dev pro rychlé prototypování +- Podporu narativního designu pro postavy, dialogy a budování světa +- Pokrytí 21+ typů her s architektonickým vedením specifickým pro engine + +## Test Architect (TEA) + +Podniková testovací strategie, vedení automatizace a rozhodování o release gate prostřednictvím expertního agenta a devíti strukturovaných workflow. TEA jde daleko za vestavěného QA agenta s prioritizací založenou na riziku a trasovatelností požadavků. + +- **Kód:** `tea` +- **npm:** [`bmad-method-test-architecture-enterprise`](https://www.npmjs.com/package/bmad-method-test-architecture-enterprise) +- **GitHub:** [bmad-code-org/bmad-method-test-architecture-enterprise](https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise) + +**Poskytuje:** + +- Agenta Murat (Master Test Architect a Quality Advisor) +- Workflow pro testovací design, ATDD, automatizaci, revizi testů a trasovatelnost +- Hodnocení NFR, nastavení CI a scaffolding frameworku +- Prioritizaci P0-P3 s volitelnými integracemi Playwright Utils a MCP + +## Komunitní moduly + +Komunitní moduly a marketplace modulů přicházejí. Sledujte [organizaci BMad na GitHubu](https://github.com/bmad-code-org) pro aktualizace. diff --git a/docs/cs/reference/testing.md b/docs/cs/reference/testing.md new file mode 100644 index 000000000..e5c061e06 --- /dev/null +++ b/docs/cs/reference/testing.md @@ -0,0 +1,106 @@ +--- +title: Možnosti testování +description: Srovnání vestavěného QA agenta (Quinn) s modulem Test Architect (TEA) pro automatizaci testů. +sidebar: + order: 5 +--- + +BMad poskytuje dvě testovací cesty: vestavěného QA agenta pro rychlé generování testů a instalovatelný modul Test Architect pro podnikovou testovací strategii. + +## Který byste měli použít? + +| Faktor | Quinn (vestavěný QA) | Modul TEA | +| --- | --- | --- | +| **Nejlepší pro** | Malé až střední projekty, rychlé pokrytí | Velké projekty, regulované nebo složité domény | +| **Nastavení** | Nic k instalaci — součástí BMM | Instalace zvlášť přes `npx bmad-method install` | +| **Přístup** | Generujte testy rychle, iterujte později | Nejprve plánujte, pak generujte s trasovatelností | +| **Typy testů** | API a E2E testy | API, E2E, ATDD, NFR a další | +| **Strategie** | Happy path + kritické hraniční případy | Prioritizace založená na riziku (P0–P3) | +| **Počet workflow** | 1 (Automate) | 9 (design, ATDD, automate, review, trace a další) | + +:::tip[Začněte s Quinnem] +Většina projektů by měla začít s Quinnem. Pokud později budete potřebovat testovací strategii, quality gates nebo trasovatelnost požadavků, nainstalujte TEA vedle něj. +::: + +## Vestavěný QA agent (Quinn) + +Quinn je vestavěný QA agent v modulu BMM (Agile suite). Rychle generuje funkční testy pomocí existujícího testovacího frameworku vašeho projektu — bez konfigurace nebo další instalace. + +**Spouštěč:** `QA` nebo `bmad-qa-generate-e2e-tests` + +### Co Quinn dělá + +Quinn spouští jeden workflow (Automate), který projde pěti kroky: + +1. **Detekce testovacího frameworku** — skenuje `package.json` a existující testovací soubory pro váš framework (Jest, Vitest, Playwright, Cypress nebo jakýkoli standardní runner). Pokud neexistuje, analyzuje stack projektu a navrhne jeden. +2. **Identifikace funkcí** — zeptá se, co testovat, nebo automaticky objeví funkce v kódové bázi. +3. **Generování API testů** — pokrývá stavové kódy, strukturu odpovědí, happy path a 1–2 chybové případy. +4. **Generování E2E testů** — pokrývá uživatelské workflow se sémantickými lokátory a asercemi viditelných výsledků. +5. **Spuštění a ověření** — provede generované testy a okamžitě opraví selhání. + +Quinn produkuje shrnutí testů uložené do složky implementačních artefaktů vašeho projektu. + +### Vzory testů + +Generované testy sledují filozofii „jednoduché a udržovatelné“: + +- **Pouze standardní API frameworku** — žádné externí utility nebo vlastní abstrakce +- **Sémantické lokátory** pro UI testy (role, popisky, text místo CSS selektorů) +- **Nezávislé testy** bez závislostí na pořadí +- **Žádné hardcoded waity nebo sleep** +- **Jasné popisy**, které se čtou jako dokumentace funkcí + +:::note[Rozsah] +Quinn generuje pouze testy. Pro revizi kódu a validaci stories použijte workflow Code Review (`CR`). +::: + +### Kdy použít Quinna + +- Rychlé pokrytí testy pro novou nebo existující funkci +- Automatizace testů přátelská k začátečníkům bez pokročilého nastavení +- Standardní vzory testů, které může číst a udržovat jakýkoli vývojář +- Malé až střední projekty, kde komplexní testovací strategie není potřeba + +## Modul Test Architect (TEA) + +TEA je samostatný modul, který poskytuje expertního agenta (Murat) a devět strukturovaných workflow pro podnikové testování. Jde za rámec generování testů do testovací strategie, plánování založeného na riziku, quality gates a trasovatelnosti požadavků. + +- **Dokumentace:** [Dokumentace modulu TEA](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/) +- **Instalace:** `npx bmad-method install` a výběr modulu TEA +- **npm:** [`bmad-method-test-architecture-enterprise`](https://www.npmjs.com/package/bmad-method-test-architecture-enterprise) + +### Co TEA poskytuje + +| Workflow | Účel | +| --- | --- | +| Test Design | Vytvoření komplexní testovací strategie vázané na požadavky | +| ATDD | Acceptance-test-driven development s kritérii stakeholderů | +| Automate | Generování testů s pokročilými vzory a utilitami | +| Test Review | Validace kvality a pokrytí testů proti strategii | +| Traceability | Mapování testů zpět na požadavky pro audit a compliance | +| NFR Assessment | Hodnocení nefunkčních požadavků (výkon, bezpečnost) | +| CI Setup | Konfigurace provádění testů v CI pipelines | +| Framework Scaffolding | Nastavení testovací infrastruktury a struktury projektu | +| Release Gate | Datově založená rozhodnutí go/no-go pro release | + +TEA také podporuje prioritizaci P0–P3 založenou na riziku a volitelné integrace s Playwright Utils a MCP nástroji. + +### Kdy použít TEA + +- Projekty vyžadující trasovatelnost požadavků nebo compliance dokumentaci +- Týmy potřebující prioritizaci testů založenou na riziku napříč mnoha funkcemi +- Podniková prostředí s formálními quality gates před releasem +- Složité domény, kde musí být testovací strategie naplánována před psaním testů +- Projekty, které přerostly jednoduchý workflow Quinna + +## Jak testování zapadá do workflow + +Quinn workflow Automate se objevuje ve Fázi 4 (Implementace) mapy workflow BMad Method. Je navržen ke spuštění **po dokončení celého epicu** — jakmile jsou všechny stories v epicu implementovány a zrevidovány. Typická sekvence: + +1. Pro každou story v epicu: implementace s Dev (`DS`), pak validace pomocí Code Review (`CR`) +2. Po dokončení epicu: generování testů s Quinnem (`QA`) nebo TEA workflow Automate +3. Spuštění retrospektivy (`bmad-retrospective`) pro zachycení získaných zkušeností + +Quinn pracuje přímo ze zdrojového kódu bez načítání plánovacích dokumentů (PRD, architektura). TEA workflow mohou integrovat s upstream plánovacími artefakty pro trasovatelnost. + +Pro více o tom, kde testování zapadá do celkového procesu, viz [Mapa pracovních postupů](./workflow-map.md). diff --git a/docs/cs/reference/workflow-map.md b/docs/cs/reference/workflow-map.md new file mode 100644 index 000000000..4dd67dd83 --- /dev/null +++ b/docs/cs/reference/workflow-map.md @@ -0,0 +1,89 @@ +--- +title: "Mapa pracovních postupů" +description: Vizuální reference fází workflow BMad Method a jejich výstupů +sidebar: + order: 1 +--- + +BMad Method (BMM) je modul v ekosystému BMad, zaměřený na dodržování osvědčených postupů context engineeringu a plánování. AI agenti fungují nejlépe s jasným, strukturovaným kontextem. Systém BMM buduje tento kontext progresivně napříč 4 odlišnými fázemi — každá fáze a volitelně více workflow v každé fázi produkují dokumenty, které informují další, takže agenti vždy vědí, co budovat a proč. + +Zdůvodnění a koncepty vycházejí z agilních metodik, které byly v průmyslu úspěšně používány jako mentální framework. + +Pokud si kdykoli nejste jisti, co dělat, skill `bmad-help` vám pomůže zůstat na cestě nebo vědět, co dělat dál. Vždy se můžete odkázat sem — ale `bmad-help` je plně interaktivní a mnohem rychlejší, pokud již máte nainstalovaný BMad Method. Navíc, pokud používáte různé moduly, které rozšířily BMad Method nebo přidaly další komplementární moduly — `bmad-help` se vyvíjí a zná vše, co je dostupné, aby vám dal nejlepší radu v daném okamžiku. + +Důležitá poznámka: Každý workflow níže lze spustit přímo vaším nástrojem přes skill nebo načtením agenta a použitím záznamu z nabídky agenta. + + + +

+ Otevřít diagram v novém panelu ↗ +

+ +## Fáze 1: Analýza (volitelná) + +Prozkoumejte problémový prostor a validujte nápady před závazkem k plánování. + +| Workflow | Účel | Produkuje | +| ------------------------------- | -------------------------------------------------------------------------- | ------------------------- | +| `bmad-brainstorming` | Brainstorming nápadů na projekt s řízenou facilitací brainstormingového kouče | `brainstorming-report.md` | +| `bmad-domain-research`, `bmad-market-research`, `bmad-technical-research` | Validace tržních, technických nebo doménových předpokladů | Výzkumné nálezy | +| `bmad-product-brief` | Zachycení strategické vize — nejlepší, když je váš koncept jasný | `product-brief.md` | +| `bmad-prfaq` | Working Backwards — zátěžový test a zformování vašeho produktového konceptu | `prfaq-{project}.md` | + +## Fáze 2: Plánování + +Definujte, co budovat a pro koho. + +| Workflow | Účel | Produkuje | +| --------------------------- | ---------------------------------------- | ------------ | +| `bmad-create-prd` | Definice požadavků (FR/NFR) | `PRD.md` | +| `bmad-create-ux-design` | Návrh uživatelského zážitku (když záleží na UX) | `ux-spec.md` | + +## Fáze 3: Solutioning + +Rozhodněte, jak to budovat, a rozložte práci na stories. + +| Workflow | Účel | Produkuje | +| ----------------------------------------- | ------------------------------------------ | --------------------------- | +| `bmad-create-architecture` | Explicitní technická rozhodnutí | `architecture.md` s ADR | +| `bmad-create-epics-and-stories` | Rozložení požadavků na implementovatelnou práci | Soubory epiců se stories | +| `bmad-check-implementation-readiness` | Kontrola brány před implementací | Rozhodnutí PASS/CONCERNS/FAIL | + +## Fáze 4: Implementace + +Budujte to, jednu story po druhé. Brzy plná automatizace fáze 4! + +| Workflow | Účel | Produkuje | +| -------------------------- | ------------------------------------------------------------------------ | -------------------------------- | +| `bmad-sprint-planning` | Inicializace sledování (jednou na projekt pro sekvencování dev cyklu) | `sprint-status.yaml` | +| `bmad-create-story` | Příprava další story pro implementaci | `story-[slug].md` | +| `bmad-dev-story` | Implementace story | Fungující kód + testy | +| `bmad-code-review` | Validace kvality implementace | Schváleno nebo požadovány změny | +| `bmad-correct-course` | Řešení významných změn uprostřed sprintu | Aktualizovaný plán nebo přesměrování | +| `bmad-sprint-status` | Sledování průběhu sprintu a stavu stories | Aktualizace stavu sprintu | +| `bmad-retrospective` | Revize po dokončení epicu | Poučení | + +## Quick Flow (paralelní cesta) + +Přeskočte fáze 1–3 pro malou, dobře pochopenou práci. + +| Workflow | Účel | Produkuje | +| ------------------ | --------------------------------------------------------------------------- | -------------------- | +| `bmad-quick-dev` | Sjednocený quick flow — vyjasněte záměr, plánujte, implementujte, revidujte a prezentujte | `spec-*.md` + kód | + +## Správa kontextu + +Každý dokument se stává kontextem pro další fázi. PRD říká architektovi, jaká omezení záleží. Architektura říká dev agentovi, jaké vzory následovat. Soubory stories poskytují zaměřený, kompletní kontext pro implementaci. Bez této struktury agenti dělají nekonzistentní rozhodnutí. + +### Kontext projektu + +:::tip[Doporučeno] +Vytvořte `project-context.md` pro zajištění toho, aby AI agenti dodržovali pravidla a preference vašeho projektu. Tento soubor funguje jako ústava vašeho projektu — vede implementační rozhodnutí napříč všemi workflow. Tento volitelný soubor lze vygenerovat na konci tvorby architektury, nebo u existujícího projektu ho lze také vygenerovat pro zachycení toho, co je důležité pro zachování souladu se současnými konvencemi. +::: + +**Jak ho vytvořit:** + +- **Ručně** — Vytvořte `_bmad-output/project-context.md` s vaším technologickým stackem a pravidly implementace +- **Vygenerujte ho** — Spusťte `bmad-generate-project-context` pro automatické generování z vaší architektury nebo kódové báze + +[**Zjistit více o project-context.md**](../explanation/project-context.md) diff --git a/docs/cs/roadmap.mdx b/docs/cs/roadmap.mdx new file mode 100644 index 000000000..14de53750 --- /dev/null +++ b/docs/cs/roadmap.mdx @@ -0,0 +1,136 @@ +--- +title: Plán rozvoje +description: Co chystáme pro BMad – funkce, vylepšení a komunitní příspěvky +--- + +# Metoda BMad: Veřejný plán rozvoje + +Metoda BMad, modul BMad Method (BMM) a BMad Builder (BMB) se neustále vyvíjejí. Zde je přehled toho, na čem pracujeme a co přijde dál. + +
+ +

Probíhá

+ +
+
+ 🧩 +

Univerzální architektura Skills

+

Jeden skill, jakákoli platforma. Napište jednou, spusťte kdekoli.

+
+
+ 🏗️ +

BMad Builder v1

+

Vytvářejte produkční AI agenty a pracovní postupy s vestavěnými eval testy, týmy a elegantní degradací.

+
+
+ 🧠 +

Systém kontextu projektu

+

Vaše AI skutečně rozumí vašemu projektu. Kontextový systém reagující na framework, který se vyvíjí s vaším kódem.

+
+
+ 📦 +

Centralizované Skills

+

Nainstalujte jednou, používejte všude. Sdílejte skills mezi projekty bez zbytečných souborů.

+
+
+ 🔄 +

Adaptivní Skills

+

Skills, které znají váš nástroj. Optimalizované varianty pro Claude, Codex, Kimi, OpenCode a mnoho dalších.

+
+
+ 📝 +

Blog BMad Team Pros

+

Návody, články a postřehy od týmu. Brzy spouštíme.

+
+
+ +

Na startu

+ +
+
+ 🏪 +

Skill Marketplace

+

Objevujte, instalujte a aktualizujte komunitní skills. Jeden curl příkaz od superschopností.

+
+
+ 🎨 +

Přizpůsobení pracovních postupů

+

Přizpůsobte si to. Integrujte Jira, Linear, vlastní výstupy — váš workflow, vaše pravidla.

+
+
+ 🚀 +

Optimalizace fází 1–3

+

Bleskurychlé plánování s kontextovým sběrem sub-agentů. Režim YOLO kombinovaný s řízenou kvalitou.

+
+
+ 🌐 +

Připraveno pro podniky

+

SSO, auditní logy, týmové pracovní prostory. Všechny ty nudné věci, díky kterým firmy řeknou ano.

+
+
+ 💎 +

Exploze komunitních modulů

+

Zábava, bezpečnost, terapie, roleplay a mnohem víc. Rozšiřte platformu BMad Method.

+
+
+ +

Automatizace Dev Loop

+

Volitelný autopilot pro vývoj. Nechte AI řídit tok práce a přitom udržujte vysokou kvalitu.

+
+
+ +

Komunita a tým

+ +
+
+ 🎙️ +

Podcast metody BMad

+

Rozhovory o AI-nativním vývoji. Spouštíme 1. března 2026!

+
+
+ 🎓 +

Master Class metody BMad

+

Od uživatele k expertovi. Hluboké ponory do každé fáze, každého workflow, každého tajemství.

+
+
+ 🏗️ +

Master Class BMad Builder

+

Vytvářejte vlastní agenty. Pokročilé techniky pro chvíle, kdy jste připraveni tvořit, ne jen používat.

+
+
+ +

BMad Prototype First

+

Od nápadu k fungujícímu prototypu v jedné relaci. Vytvořte svou vysněnou aplikaci jako umělecké dílo.

+
+
+ 🌴 +

BMad BALM!

+

Správa života pro AI-nativní uživatele. Úkoly, návyky, cíle — váš AI kopilot pro všechno.

+
+
+ 🖥️ +

Oficiální UI

+

Krásné rozhraní pro celý ekosystém BMad. Síla CLI, lesk GUI.

+
+
+ 🔒 +

BMad in a Box

+

Self-hosted, bez připojení, podnikové kvality. Váš AI asistent, vaše infrastruktura, vaše kontrola.

+
+
+ +
+

Chcete přispět?

+

+ Toto je pouze částečný seznam toho, co je plánováno. Open source tým BMad vítá přispěvatele!{" "}
+ Přidejte se k nám na GitHubu a pomozte formovat budoucnost vývoje řízeného AI. +

+

+ Líbí se vám, co budujeme? Oceníme jak jednorázovou, tak měsíční{" "}podporu. +

+

+ Pro firemní sponzoring, partnerské dotazy, přednášky, školení nebo mediální dotazy:{" "} + contact@bmadcode.com +

+
+
diff --git a/docs/cs/tutorials/getting-started.md b/docs/cs/tutorials/getting-started.md new file mode 100644 index 000000000..76a7b113b --- /dev/null +++ b/docs/cs/tutorials/getting-started.md @@ -0,0 +1,276 @@ +--- +title: "Začínáme" +description: Nainstalujte BMad a vytvořte svůj první projekt +--- + +Vytvářejte software rychleji pomocí pracovních postupů řízených AI se specializovanými agenty, kteří vás provedou plánováním, architekturou a implementací. + +## Co se naučíte + +- Nainstalovat a inicializovat BMad Method pro nový projekt +- Používat **BMad-Help** — vašeho inteligentního průvodce, který ví, co dělat dál +- Vybrat správnou plánovací cestu pro velikost vašeho projektu +- Postupovat fázemi od požadavků k fungujícímu kódu +- Efektivně používat agenty a pracovní postupy + +:::note[Předpoklady] +- **Node.js 20+** — Vyžadováno pro instalátor +- **Git** — Doporučeno pro správu verzí +- **AI-powered IDE** — Claude Code, Cursor nebo podobné +- **Nápad na projekt** — I jednoduchý stačí pro učení +::: + +:::tip[Nejsnadnější cesta] +**Instalace** → `npx bmad-method install` +**Zeptejte se** → `bmad-help what should I do first?` +**Tvořte** → Nechte BMad-Help vás provést workflow po workflow +::: + +## Seznamte se s BMad-Help: Váš inteligentní průvodce + +**BMad-Help je nejrychlejší způsob, jak začít s BMad.** Nemusíte si pamatovat workflow nebo fáze — prostě se zeptejte a BMad-Help: + +- **Prozkoumá váš projekt** a zjistí, co už bylo uděláno +- **Ukáže vaše možnosti** na základě nainstalovaných modulů +- **Doporučí, co dál** — včetně prvního povinného úkolu +- **Odpoví na otázky** jako „Mám nápad na SaaS, kde začít?“ + +### Jak používat BMad-Help + +Spusťte ho ve vašem AI IDE vyvoláním skillu: + +``` +bmad-help +``` + +Nebo ho spojte s otázkou pro kontextové poradenství: + +``` +bmad-help I have an idea for a SaaS product, I already know all the features I want. where do I get started? +``` + +BMad-Help odpoví s: +- Co je doporučeno pro vaši situaci +- Jaký je první povinný úkol +- Jak vypadá zbytek procesu + +### Řídí i pracovní postupy + +BMad-Help nejen odpovídá na otázky — **automaticky se spouští na konci každého workflow** a řekne vám přesně, co dělat dál. Žádné hádání, žádné prohledávání dokumentace — jen jasné pokyny k dalšímu povinnému workflow. + +:::tip[Začněte zde] +Po instalaci BMad okamžitě vyvolejte skill `bmad-help`. Detekuje, jaké moduly máte nainstalované, a navede vás ke správnému výchozímu bodu pro váš projekt. +::: + +## Pochopení BMad + +BMad vám pomáhá vytvářet software prostřednictvím řízených pracovních postupů se specializovanými AI agenty. Proces probíhá ve čtyřech fázích: + +| Fáze | Název | Co se děje | +| ---- | -------------- | ------------------------------------------------------- | +| 1 | Analýza | Brainstorming, průzkum, product brief nebo PRFAQ *(volitelné)* | +| 2 | Plánování | Vytvoření požadavků (PRD nebo specifikace) | +| 3 | Solutioning | Návrh architektury *(pouze BMad Method/Enterprise)* | +| 4 | Implementace | Budování epic po epicu, story po story | + +**[Otevřete Mapu pracovních postupů](../reference/workflow-map.md)** pro prozkoumání fází, workflow a správy kontextu. + +Na základě složitosti vašeho projektu nabízí BMad tři plánovací cesty: + +| Cesta | Nejlepší pro | Vytvořené dokumenty | +| --------------- | -------------------------------------------------------------- | -------------------------------------- | +| **Quick Flow** | Opravy chyb, jednoduché funkce, jasný rozsah (1–15 stories) | Pouze tech-spec | +| **BMad Method** | Produkty, platformy, složité funkce (10–50+ stories) | PRD + architektura + UX | +| **Enterprise** | Compliance, multi-tenant systémy (30+ stories) | PRD + architektura + bezpečnost + DevOps | + +:::note +Počty stories jsou orientační, ne definitivní. Vyberte si cestu podle potřeb plánování, ne podle počtu stories. +::: + +## Instalace + +Otevřete terminál v adresáři vašeho projektu a spusťte: + +```bash +npx bmad-method install +``` + +Pokud chcete nejnovější prereleaseový build místo výchozího release kanálu, použijte `npx bmad-method@next install`. + +Při výzvě k výběru modulů zvolte **BMad Method**. + +Instalátor vytvoří dvě složky: +- `_bmad/` — agenti, workflow, úkoly a konfigurace +- `_bmad-output/` — prozatím prázdná, ale zde se budou ukládat vaše artefakty + +:::tip[Váš další krok] +Otevřete vaše AI IDE ve složce projektu a spusťte: + +``` +bmad-help +``` + +BMad-Help detekuje, co jste dokončili, a doporučí přesně, co dělat dál. Můžete mu také klást otázky jako „Jaké mám možnosti?“ nebo „Mám nápad na SaaS, kde začít?“ +::: + +:::note[Jak načítat agenty a spouštět workflow] +Každý workflow má **skill**, který vyvoláte jménem ve vašem IDE (např. `bmad-create-prd`). Váš AI nástroj rozpozná název `bmad-*` a spustí ho — nemusíte načítat agenty zvlášť. Můžete také vyvolat agentní skill přímo pro obecnou konverzaci (např. `bmad-agent-pm` pro PM agenta). +::: + +:::caution[Nové chaty] +Vždy začněte nový chat pro každý workflow. Tím předejdete problémům s kontextovými omezeními. +::: + +## Krok 1: Vytvořte svůj plán + +Projděte fázemi 1–3. **Pro každý workflow používejte nové chaty.** + +:::tip[Kontext projektu (volitelné)] +Před začátkem zvažte vytvoření `project-context.md` pro dokumentaci vašich technických preferencí a pravidel implementace. Tím zajistíte, že všichni AI agenti budou dodržovat vaše konvence v průběhu celého projektu. + +Vytvořte ho ručně na `_bmad-output/project-context.md` nebo ho vygenerujte po architektuře pomocí `bmad-generate-project-context`. [Zjistit více](../explanation/project-context.md). +::: + +### Fáze 1: Analýza (volitelná) + +Všechny workflow v této fázi jsou volitelné: +- **brainstorming** (`bmad-brainstorming`) — Řízená ideace +- **průzkum** (`bmad-market-research` / `bmad-domain-research` / `bmad-technical-research`) — Tržní, doménový a technický průzkum +- **product-brief** (`bmad-product-brief`) — Doporučený základní dokument, když je váš koncept jasný +- **prfaq** (`bmad-prfaq`) — Working Backwards výzva pro zátěžový test a zformování vašeho produktového konceptu + +### Fáze 2: Plánování (povinná) + +**Pro BMad Method a Enterprise cesty:** +1. Vyvolejte **PM agenta** (`bmad-agent-pm`) v novém chatu +2. Spusťte workflow `bmad-create-prd` (`bmad-create-prd`) +3. Výstup: `PRD.md` + +**Pro Quick Flow cestu:** +- Spusťte `bmad-quick-dev` — zvládne plánování i implementaci v jednom workflow, přeskočte k implementaci + +:::note[UX Design (volitelné)] +Pokud má váš projekt uživatelské rozhraní, vyvolejte **UX-Designer agenta** (`bmad-agent-ux-designer`) a spusťte UX design workflow (`bmad-create-ux-design`) po vytvoření PRD. +::: + +### Fáze 3: Solutioning (BMad Method/Enterprise) + +**Vytvoření architektury** +1. Vyvolejte **Architect agenta** (`bmad-agent-architect`) v novém chatu +2. Spusťte `bmad-create-architecture` (`bmad-create-architecture`) +3. Výstup: Dokument architektury s technickými rozhodnutími + +**Vytvoření epiců a stories** + +:::tip[Vylepšení ve V6] +Epicy a stories se nyní vytvářejí *po* architektuře. Tím vznikají kvalitnější stories, protože architektonická rozhodnutí (databáze, API vzory, tech stack) přímo ovlivňují rozklad práce. +::: + +1. Vyvolejte **PM agenta** (`bmad-agent-pm`) v novém chatu +2. Spusťte `bmad-create-epics-and-stories` (`bmad-create-epics-and-stories`) +3. Workflow využívá jak PRD, tak architekturu k vytvoření technicky informovaných stories + +**Kontrola připravenosti k implementaci** *(vysoce doporučeno)* +1. Vyvolejte **Architect agenta** (`bmad-agent-architect`) v novém chatu +2. Spusťte `bmad-check-implementation-readiness` (`bmad-check-implementation-readiness`) +3. Validuje soudržnost všech plánovacích dokumentů + +## Krok 2: Sestavte svůj projekt + +Jakmile je plánování dokončeno, přejděte k implementaci. **Každý workflow by měl běžet v novém chatu.** + +### Inicializace plánování sprintu + +Vyvolejte **Developer agenta** (`bmad-agent-dev`) a spusťte `bmad-sprint-planning` (`bmad-sprint-planning`). Tím se vytvoří `sprint-status.yaml` pro sledování všech epiců a stories. + +### Cyklus vývoje + +Pro každou story opakujte tento cyklus s novými chaty: + +| Krok | Agent | Workflow | Příkaz | Účel | +| ---- | ----- | -------------------- | -------------------------- | ---------------------------------- | +| 1 | DEV | `bmad-create-story` | `bmad-create-story` | Vytvoření story souboru z epicu | +| 2 | DEV | `bmad-dev-story` | `bmad-dev-story` | Implementace story | +| 3 | DEV | `bmad-code-review` | `bmad-code-review` | Validace kvality *(doporučeno)* | + +Po dokončení všech stories v epicu vyvolejte **Developer agenta** (`bmad-agent-dev`) a spusťte `bmad-retrospective` (`bmad-retrospective`). + +## Co jste dosáhli + +Naučili jste se základy budování s BMad: + +- Nainstalovali BMad a nakonfigurovali ho pro vaše IDE +- Inicializovali projekt s vybranou plánovací cestou +- Vytvořili plánovací dokumenty (PRD, architektura, epicy a stories) +- Pochopili cyklus vývoje pro implementaci + +Váš projekt nyní obsahuje: + +```text +váš-projekt/ +├── _bmad/ # Konfigurace BMad +├── _bmad-output/ +│ ├── planning-artifacts/ +│ │ ├── PRD.md # Váš dokument požadavků +│ │ ├── architecture.md # Technická rozhodnutí +│ │ └── epics/ # Soubory epiců a stories +│ ├── implementation-artifacts/ +│ │ └── sprint-status.yaml # Sledování sprintu +│ └── project-context.md # Pravidla implementace (volitelné) +└── ... +``` + +## Rychlý přehled + +| Workflow | Příkaz | Agent | Účel | +| ------------------------------------- | ------------------------------------------ | --------- | ----------------------------------------------- | +| **`bmad-help`** ⭐ | `bmad-help` | Jakýkoli | **Váš inteligentní průvodce — ptejte se na cokoli!** | +| `bmad-create-prd` | `bmad-create-prd` | PM | Vytvoření dokumentu požadavků (PRD) | +| `bmad-create-architecture` | `bmad-create-architecture` | Architect | Vytvoření dokumentu architektury | +| `bmad-generate-project-context` | `bmad-generate-project-context` | Analyst | Vytvoření souboru kontextu projektu | +| `bmad-create-epics-and-stories` | `bmad-create-epics-and-stories` | PM | Rozklad PRD na epicy | +| `bmad-check-implementation-readiness` | `bmad-check-implementation-readiness` | Architect | Validace soudržnosti plánování | +| `bmad-sprint-planning` | `bmad-sprint-planning` | DEV | Inicializace sledování sprintu | +| `bmad-create-story` | `bmad-create-story` | DEV | Vytvoření souboru story | +| `bmad-dev-story` | `bmad-dev-story` | DEV | Implementace story | +| `bmad-code-review` | `bmad-code-review` | DEV | Revize implementovaného kódu | + +## Časté otázky + +**Potřebuji vždy architekturu?** +Pouze pro BMad Method a Enterprise cesty. Quick Flow přeskakuje ze specifikace rovnou k implementaci. + +**Mohu později změnit svůj plán?** +Ano. Workflow `bmad-correct-course` (`bmad-correct-course`) řeší změny rozsahu během implementace. + +**Co když chci nejdřív brainstormovat?** +Vyvolejte Analyst agenta (`bmad-agent-analyst`) a spusťte `bmad-brainstorming` (`bmad-brainstorming`) před zahájením PRD. + +**Musím dodržovat striktní pořadí?** +Ne striktně. Jakmile se naučíte postup, můžete spouštět workflow přímo pomocí Rychlého přehledu výše. + +## Získání pomoci + +:::tip[První zastávka: BMad-Help] +**Vyvolejte `bmad-help` kdykoli** — je to nejrychlejší způsob, jak se odpoutat. Zeptejte se na cokoli: +- „Co mám dělat po instalaci?“ +- „Zasekl jsem se na workflow X“ +- „Jaké mám možnosti pro Y?“ +- „Ukaž mi, co bylo dosud uděláno“ + +BMad-Help prozkoumá váš projekt, detekuje, co jste dokončili, a řekne vám přesně, co dělat dál. +::: + +- **Během workflow** — Agenti vás provázejí otázkami a vysvětleními +- **Komunita** — [Discord](https://discord.gg/gk8jAdXWmj) (#bmad-method-help, #report-bugs-and-issues) + +## Klíčové poznatky + +:::tip[Zapamatujte si] +- **Začněte s `bmad-help`** — Váš inteligentní průvodce, který zná váš projekt a možnosti +- **Vždy používejte nové chaty** — Začněte nový chat pro každý workflow +- **Cesta záleží** — Quick Flow používá `bmad-quick-dev`; Method/Enterprise vyžadují PRD a architekturu +- **BMad-Help se spouští automaticky** — Každý workflow končí pokyny, co dělat dál +::: + +Jste připraveni začít? Nainstalujte BMad, vyvolejte `bmad-help` a nechte svého inteligentního průvodce ukázat cestu. diff --git a/docs/explanation/analysis-phase.md b/docs/explanation/analysis-phase.md new file mode 100644 index 000000000..f05d89120 --- /dev/null +++ b/docs/explanation/analysis-phase.md @@ -0,0 +1,70 @@ +--- +title: "Analysis Phase: From Idea to Foundation" +description: What brainstorming, research, product briefs, and PRFAQs are — and when to use each +sidebar: + order: 1 +--- + +The Analysis phase (Phase 1) helps you think clearly about your product before committing to building it. Every tool in this phase is optional, but skipping analysis entirely means your PRD is built on assumptions instead of insight. + +## Why Analysis Before Planning? + +A PRD answers "what should we build and why?" If you feed it vague thinking, you get a vague PRD — and every downstream document inherits that vagueness. Architecture built on a weak PRD makes wrong technical bets. Stories derived from weak architecture miss edge cases. The cost compounds. + +Analysis tools exist to make your PRD sharp. They attack the problem from different angles — creative exploration, market reality, customer clarity, feasibility — so that by the time you sit down with the PM agent, you know what you're building and for whom. + +## The Tools + +### Brainstorming + +**What it is.** A facilitated creative session using proven ideation techniques. The AI acts as coach, pulling ideas out of you through structured exercises — not generating ideas for you. + +**Why it's here.** Raw ideas need space to develop before they get locked into requirements. Brainstorming creates that space. It's especially valuable when you have a problem domain but no clear solution, or when you want to explore multiple directions before committing. + +**When to use it.** You have a vague sense of what you want to build but haven't crystallized the concept. Or you have a concept but want to pressure-test it against alternatives. + +See [Brainstorming](./brainstorming.md) for a deeper look at how sessions work. + +### Research (Market, Domain, Technical) + +**What it is.** Three focused research workflows that investigate different dimensions of your idea. Market research examines competitors, trends, and user sentiment. Domain research builds subject-matter expertise and terminology. Technical research evaluates feasibility, architecture options, and implementation approaches. + +**Why it's here.** Building on assumptions is the fastest way to build something nobody needs. Research grounds your concept in reality — what competitors already exist, what users actually struggle with, what's technically feasible, and what industry-specific constraints you'll face. + +**When to use it.** You're entering an unfamiliar domain, you suspect competitors exist but haven't mapped them, or your concept depends on technical capabilities you haven't validated. Run one, two, or all three — each stands alone. + +### Product Brief + +**What it is.** A guided discovery session that produces a 1-2 page executive summary of your product concept. The AI acts as a collaborative Business Analyst, helping you articulate the vision, target audience, value proposition, and scope. + +**Why it's here.** The product brief is the gentler path into planning. It captures your strategic vision in a structured format that feeds directly into PRD creation. It works best when you already have conviction about your concept — you know the customer, the problem, and roughly what you want to build. The brief organizes and sharpens that thinking. + +**When to use it.** Your concept is relatively clear and you want to document it efficiently before creating a PRD. You're confident in the direction and don't need your assumptions aggressively challenged. + +### PRFAQ (Working Backwards) + +**What it is.** Amazon's Working Backwards methodology adapted as an interactive challenge. You write the press release announcing your finished product before a single line of code exists, then answer the hardest questions customers and stakeholders would ask. The AI acts as a relentless but constructive product coach. + +**Why it's here.** The PRFAQ is the rigorous path into planning. It forces customer-first clarity by making you defend every claim. If you can't write a compelling press release, the product isn't ready. If customer FAQ answers reveal gaps, those are gaps you'd discover much later — and more expensively — during implementation. The gauntlet surfaces weak thinking early, when it's cheapest to fix. + +**When to use it.** You want your concept stress-tested before committing resources. You're unsure whether users will actually care. You want to validate that you can articulate a clear, defensible value proposition. Or you simply want the discipline of Working Backwards to sharpen your thinking. + +## Which Should I Use? + +| Situation | Recommended tool | +| --------- | ---------------- | +| "I have a vague idea, not sure where to start" | Brainstorming | +| "I need to understand the market before deciding" | Research | +| "I know what I want to build, just need to document it" | Product Brief | +| "I want to make sure this idea is actually worth building" | PRFAQ | +| "I want to explore, then validate, then document" | Brainstorming → Research → PRFAQ or Brief | + +Product Brief and PRFAQ both produce input for the PRD — choose one based on how much challenge you want. The brief is collaborative discovery. The PRFAQ is a gauntlet. Both get you to the same destination; the PRFAQ tests whether your concept deserves to get there. + +:::tip[Not Sure?] +Run `bmad-help` and describe your situation. It will recommend the right starting point based on what you've already done and what you're trying to accomplish. +::: + +## What Happens After Analysis? + +Analysis outputs feed directly into Phase 2 (Planning). The PRD workflow accepts product briefs, PRFAQ documents, research findings, and brainstorming reports as input — it synthesizes whatever you've produced into structured requirements. The more analysis you do, the sharper your PRD. diff --git a/docs/explanation/checkpoint-preview.md b/docs/explanation/checkpoint-preview.md new file mode 100644 index 000000000..d7d5ece14 --- /dev/null +++ b/docs/explanation/checkpoint-preview.md @@ -0,0 +1,92 @@ +--- +title: "Checkpoint Preview" +description: LLM-assisted human-in-the-loop review that guides you through a change from purpose to details +sidebar: + order: 3 +--- + +`bmad-checkpoint-preview` is an interactive, LLM-assisted human-in-the-loop review workflow. It walks you through a code change — from purpose and context into details — so you can make an informed decision about whether to ship, rework, or dig deeper. + +![Checkpoint Preview workflow diagram](/diagrams/checkpoint-preview-diagram.png) + +## The Typical Flow + +You run `bmad-quick-dev`. It clarifies your intent, builds a spec, implements the change, and when it's done it appends a review trail to the spec file and opens it in your editor. You look at the spec and see the change touched 20 files across several modules. + +You could eyeball the diff. But 20 files is where eyeballing starts to fail — you lose the thread, miss a connection between two distant changes, or approve something you didn't fully understand. So instead, you say "checkpoint" and the LLM walks you through it. + +That handoff — from autonomous implementation back to human judgment — is the primary use case. Quick-dev runs long with minimal supervision. Checkpoint Preview is where you take back the wheel. + +## Why It Exists + +Code review has two failure modes. In one, the reviewer skims the diff, nothing jumps out, and they approve. In the other, they methodically read every file but lose the thread — they see the trees and miss the forest. Both result in the same outcome: the review didn't catch the thing that mattered. + +The underlying issue is sequencing. A raw diff presents changes in file order, which is almost never the order that builds understanding. You see a helper function before you know why it exists. You see a schema change before you understand what feature it supports. The reviewer has to reconstruct the author's intent from scattered clues, and that reconstruction is where attention fails. + +Checkpoint Preview solves this by making the LLM do the reconstruction work. It reads the diff, the spec (if one exists), and the surrounding codebase, then presents the change in an order designed for comprehension — not for `git diff`. + +## How It Works + +The workflow has five steps. Each step builds on the previous one, progressively shifting from "what is this?" toward "should we ship it?" + +### 1. Orientation + +The workflow identifies the change (from a PR, commit, branch, spec file, or the current git state) and produces a one-line intent summary plus surface area stats: files changed, modules touched, lines of logic, boundary crossings, and new public interfaces. + +This is the "is this what I think it is?" moment. Before reading any code, the reviewer confirms they're looking at the right thing and calibrates their expectations for scope. + +### 2. Walkthrough + +The change is organized by **concern** — cohesive design intents like "input validation" or "API contract" — not by file. Each concern gets a short explanation of *why* this approach was chosen, followed by clickable `path:line` stops that the reviewer can follow through the code. + +This is the design judgment step. The reviewer evaluates whether the approach is right for the system, not whether the code is correct. Concerns are sequenced top-down: the highest-level intent first, then supporting implementation. The reviewer never encounters a reference to something they haven't seen yet. + +### 3. Detail Pass + +After the reviewer understands the design, the workflow surfaces 2-5 spots where a mistake would have the highest blast radius. These are tagged by risk category — `[auth]`, `[schema]`, `[billing]`, `[public API]`, `[security]`, and others — and ordered by how much breaks if they're wrong. + +This is not a bug hunt. Automated tests and CI handle correctness. The detail pass activates risk awareness: "here are the places where being wrong costs the most." If the reviewer wants to go deeper on a specific area, they can say "dig into [area]" for a targeted correctness-focused re-review. + +If the spec went through adversarial review loops (machine hardening), those findings are surfaced here too — not the bugs that were fixed, but the decisions that the review loop flagged that the reviewer should be aware of. + +### 4. Testing + +Suggests 2-5 ways to manually observe the change working. Not automated test commands — manual observations that build confidence no test suite provides. A UI interaction to try, a CLI command to run, an API request to send, with expected results for each. + +If the change has no user-visible behavior, it says so. No invented busywork. + +### 5. Wrap-Up + +The reviewer makes the call: approve, rework, or keep discussing. If approving a PR, the workflow can help with `gh pr review --approve`. If reworking, it helps diagnose whether the problem was the approach, the spec, or the implementation, and helps draft actionable feedback tied to specific code locations. + +## It's a Conversation, Not a Report + +The workflow presents each step as a starting point, not a final word. Between steps — or in the middle of one — you can talk to the LLM, ask questions, challenge its framing, or pull in other skills to get a different perspective: + +- **"run advanced elicitation on the error handling"** — push the LLM to reconsider and refine its analysis of a specific area +- **"party mode on whether this schema migration is safe"** — bring multiple agent perspectives into a focused debate +- **"run code review"** — generate structured agentic findings with adversarial and edge-case analysis + +The checkpoint workflow doesn't lock you into a linear path. It gives you structure when you want it and gets out of the way when you want to explore. The five steps are there to make sure you see the whole picture, but how deep you go at each step — and what tools you bring in — is entirely up to you. + +## The Review Trail + +The walkthrough step works best when it has a **Suggested Review Order** — a list of stops the spec author wrote to guide reviewers through the change. When a spec includes this, the workflow uses it directly. + +When no author-produced trail exists, the workflow generates one from the diff and codebase context. A generated trail is lower quality than an author-produced one, but far better than reading changes in file order. + +## When to Use It + +The primary scenario is the handoff from `bmad-quick-dev`: the implementation is done, the spec file is open in your editor with a review trail appended, and you need to decide whether to ship. Say "checkpoint" and go. + +It also works standalone: + +- **Reviewing a PR** — especially one with more than a handful of files or cross-cutting changes +- **Onboarding to a change** — when you need to understand what happened on a branch you didn't write +- **Sprint review** — the workflow can pick up stories marked `review` in your sprint status file + +Invoke it by saying "checkpoint" or "walk me through this change." It works in any terminal, but you'll get more out of it inside an IDE — VS Code, Cursor, or similar — because the workflow produces `path:line` references at every step. In an IDE-embedded terminal those are clickable, so you can jump from file to file as you follow the review trail. + +## What It Is Not + +Checkpoint Preview is not a substitute for automated review. It does not run linters, type checkers, or test suites. It does not assign severity scores or produce pass/fail verdicts. It is a reading guide that helps a human apply their judgment where it matters most. diff --git a/docs/fr/_STYLE_GUIDE.md b/docs/fr/_STYLE_GUIDE.md index 18907a4fb..b0f3453d9 100644 --- a/docs/fr/_STYLE_GUIDE.md +++ b/docs/fr/_STYLE_GUIDE.md @@ -353,7 +353,7 @@ Uniquement pour les parcours méthode BMad et Enterprise. Quick Dev passe direct ### Puis-je modifier mon plan plus tard ? -Oui. Utilisez `bmad-correct-course` pour gérer les changements de portée. +Oui. Utilisez `bmad-correct-course` pour gérer les changements de portée en cours d’implémentation. **Une question sans réponse ici ?** [Ouvrez une issue](...) ou posez votre question sur [Discord](...). ``` diff --git a/docs/fr/explanation/advanced-elicitation.md b/docs/fr/explanation/advanced-elicitation.md index de097752e..83ea232cd 100644 --- a/docs/fr/explanation/advanced-elicitation.md +++ b/docs/fr/explanation/advanced-elicitation.md @@ -2,7 +2,7 @@ title: "Élicitation Avancée" description: Pousser le LLM à repenser son travail en utilisant des méthodes de raisonnement structurées sidebar: - order: 6 + order: 8 --- Faites repenser au LLM ce qu'il vient de générer. Vous choisissez une méthode de raisonnement, il l'applique à sa propre sortie, et vous décidez de conserver ou non les améliorations. diff --git a/docs/fr/explanation/adversarial-review.md b/docs/fr/explanation/adversarial-review.md index 235db5f23..fa080f85d 100644 --- a/docs/fr/explanation/adversarial-review.md +++ b/docs/fr/explanation/adversarial-review.md @@ -2,7 +2,7 @@ title: "Revue Contradictoire" description: Technique de raisonnement forcée qui empêche les revues paresseuses du style "ça à l'air bon" sidebar: - order: 5 + order: 7 --- Forcez une analyse plus approfondie en exigeant que des problèmes soient trouvés. diff --git a/docs/fr/explanation/analysis-phase.md b/docs/fr/explanation/analysis-phase.md new file mode 100644 index 000000000..2206f95df --- /dev/null +++ b/docs/fr/explanation/analysis-phase.md @@ -0,0 +1,74 @@ +--- +title: "Phase d'analyse : de l'Idée aux Fondations" +description: Ce que sont le brainstorming, la recherche, les product briefs et les PRFAQs — et quand les utiliser +sidebar: + order: 1 +--- + +La phase d'Analyse (Phase 1) vous aide à penser clairement à votre produit avant de vous engager à le construire. Chaque outil de cette phase est optionnel, mais sauter l'analyse entièrement signifie que votre PRD sera construit sur des suppositions plutôt que sur des connaissances approfondies. + +## Pourquoi Analyser avant de Planifier ? + +Un PRD répond à la question « que devons-nous construire et pourquoi ? » Si vous l'alimentez avec une réflexion vague, vous obtiendrez un PRD vague — et chaque document en aval héritera de cette imprécision. Une architecture bâtie sur un PRD faible prend de mauvaises décisions techniques. Les stories dérivées d'une architecture faible manquent de edge cases. Le coût s'accumule. + +Les outils d'analyse existent pour rendre votre PRD précis. Ils attaquent le problème sous différents angles — exploration créative, réalité du marché, clarté client, faisabilité — pour qu'au moment de vous asseoir avec l'agent PM, vous sachiez ce que vous construisez et pour qui. + +## Les Outils + +### Brainstorming + +**Quoi.** Une session créative facilitée utilisant des techniques d'idéation éprouvées. L'IA agit comme coach, extrayant vos idées à travers des exercices structurés — pas en les générant pour vous. + +**Pourquoi.** Les idées brutes ont besoin d'espace pour se développer avant d'être verrouillées dans des exigences. Le brainstorming crée cet espace. Il est particulièrement précieux quand vous avez un espace-problème mais pas de solution claire, ou quand vous voulez explorer plusieurs pistes avant de vous engager. + +**Quand.** Vous avez une vague idée de ce que vous voulez construire mais n'avez pas encore cristallisé le concept. Ou vous avez un concept mais voulez l'éprouver face à des alternatives. + +Voir [Brainstorming](./brainstorming.md) pour un aperçu plus approfondi du fonctionnement des sessions. + +### Recherche (Marché, Domaine, Technique) + +**Quoi.** Trois workflows de recherche ciblés qui investiguent différentes dimensions de votre idée. La recherche marché examine les concurrents, les tendances et le sentiment utilisateur. La recherche domaine construit l'expertise métier et la terminologie. La recherche technique évalue la faisabilité, les options d'architecture et les approches d'implémentation. + +**Pourquoi.** Construire sur des suppositions est le moyen le plus rapide de construire quelque chose dont personne n'a besoin. La recherche ancre votre concept dans la réalité — quels concurrents existent déjà, avec quoi les utilisateurs luttent réellement, ce qui est techniquement faisable, et quelles contraintes spécifiques à l'industrie vous affronterez. + +**Quand.** Vous entrez dans un domaine inconnu, vous soupçonnez que des concurrents existent mais ne les avez pas cartographiés, ou votre concept dépend de capacités techniques que vous n'avez pas validées. Lancez-en un, deux ou les trois — chaque workflow de recherche fonctionne de manière autonome. + +### Product Brief[^1] + +**Quoi.** Une session de découverte guidée qui produit un résumé exécutif de 1-2 pages de votre concept produit. L'IA agit comme un analyste commercial collaboratif, vous aidant à articuler la vision, le public cible, la proposition de valeur et le périmètre. + +**Pourquoi.** Le product brief est le chemin le plus doux vers la planification. Il capture votre vision stratégique dans un format structuré qui alimente directement la création du PRD. Il fonctionne mieux quand vous avez déjà la conviction à propos de votre concept — vous connaissez le client, le problème et approximativement ce que vous voulez construire. Le brief organise et affine cette réflexion. + +**Quand.** Votre concept est relativement clair et vous voulez le documenter efficacement avant de créer un PRD. Vous êtes confiant dans la direction et n'avez pas besoin que vos suppositions soient agressivement remises en question. + +### PRFAQ (Working Backwards) + +**Quoi.** La méthodologie Working Backwards d'Amazon adaptée en défi interactif. Vous rédigez le communiqué de presse annonçant votre produit fini avant qu'une seule ligne de code n'existe, puis répondez aux questions les plus difficiles que les clients et les parties prenantes poseraient. L'IA agit comme un coach produit implacable mais constructif. + +**Pourquoi.** Le PRFAQ est le chemin rigoureux vers la planification. Il force la clarté orientée client en vous obligeant à défendre chaque affirmation. Si vous ne pouvez pas rédiger un communiqué de presse convaincant, le produit n'est pas prêt. Si les réponses de la FAQ client révèlent des lacunes, ce sont des lacunes que vous découvrirez bien plus tard — et plus coûteusement — pendant l'implémentation. Le défi fait remonter les failles de réflexion tôt, quand c'est le moins cher de les corriger. + +**Quand.** Vous voulez que votre concept soit éprouvé avant d'engager des ressources. Vous n'êtes pas sûr que les utilisateurs s'en soucieront réellement. Vous voulez valider que vous pouvez articuler une proposition de valeur claire et défendable. Ou vous voulez simplement la discipline du Working Backwards pour affiner votre réflexion. + +## Lequel utiliser ? + +| Situation | Outil recommandé | +|-------------------------------------------------------------------------------|--------------------------------------------| +| « J'ai une idée vague, je ne sais pas par où commencer » | Brainstorming | +| « J'ai besoin de comprendre le marché avant de décider » | Recherche | +| « Je sais ce que je veux construire, j'ai juste besoin de le documenter » | Product Brief | +| « Je veux m'assurer que cette idée vaut vraiment la peine d'être construite » | PRFAQ | +| « Je veux explorer, puis valider, puis documenter » | Brainstorming → Recherche → PRFAQ ou Brief | + +Le Product Brief et le PRFAQ produisent tous deux des entrées pour le PRD — choisissez-en un en fonction du niveau de défi que vous souhaitez. Le brief est une découverte collaborative. Le PRFAQ est un défi. Les deux vous mènent à la même destination ; le PRFAQ teste si votre concept mérite d'y arriver. + +:::tip[Pas sûr ?] +Exécutez `bmad-help` et décrivez votre situation. Il vous recommandera le bon point de départ en fonction de ce que vous avez déjà accompli et de ce que vous essayez de réaliser. +::: + +## Que se passe-t-il après l'analyse ? + +Les résultats de l'analyse alimentent directement la Phase 2 (Planification). Le workflow PRD accepte les product briefs, les documents PRFAQ, les conclusions de recherche et les rapports de brainstorming en entrée — il synthétise tout ce que vous avez produit en exigences structurées. Plus vous faites d'analyse, plus votre PRD sera précis. + +## Glossaire + +[^1]: Brief : document synthétique qui formalise le contexte, les objectifs, le périmètre et les contraintes d'un projet ou d'une demande, afin d'aligner rapidement les parties prenantes avant le travail détaillé. diff --git a/docs/fr/explanation/checkpoint-preview.md b/docs/fr/explanation/checkpoint-preview.md new file mode 100644 index 000000000..7eb8cc679 --- /dev/null +++ b/docs/fr/explanation/checkpoint-preview.md @@ -0,0 +1,92 @@ +--- +title: "Checkpoint Preview" +description: Revue assistée par LLM, avec intervention humaine, qui vous guide à travers une modification, de son objectif jusqu’aux détails +sidebar: + order: 4 +--- + +`bmad-checkpoint-preview` est un workflow de revue interactif, assisté par LLM, avec intervention humaine. Il vous guide à travers une modification de code — de l'intention et du contexte jusqu'aux détails — afin que vous puissiez prendre une décision éclairée sur la mise en production, la refonte ou l'approfondissement. + +![Diagramme du workflow Checkpoint Preview](/diagrams/checkpoint-preview-diagram-fr.webp) + +## Le Flux Typique + +Vous lancez `bmad-quick-dev`. Il clarifie votre intention, construit une spécification, implémente la modification, et une fois terminé, il ajoute un historique de revue au fichier de spécification et l'ouvre dans votre éditeur. Vous regardez la spec et constatez que la modification a touché 20 fichiers dans plusieurs modules. + +Vous pourriez survoler le diff. Mais 20 fichiers, c'est le moment où le survol commence à échouer — on perd le fil, on rate un lien entre deux modifications éloignées, ou on approuve quelque chose qu'on n'a pas pleinement compris. Alors au lieu de cela, vous dites « checkpoint » et le LLM vous guide à travers la modification. + +Ce passage de relais — de l'implémentation autonome au jugement humain — est le cas d'usage principal. Quick-dev s'exécute longtemps avec une supervision minimale. Checkpoint Preview, c'est là où vous reprenez le volant. + +## Pourquoi + +La revue de code a deux modes d'échec. Dans le premier, le réviseur survole le diff, rien ne saute aux yeux, et il approuve. Dans le second, il lit méthodiquement chaque fichier mais perd le fil — il voit les arbres et rate la forêt. Les deux aboutissent au même résultat : la revue n'a pas repéré ce qui comptait. + +Le problème sous-jacent est le séquençage. Un diff brut présente les modifications dans l'ordre des fichiers, ce qui est presque jamais l'ordre qui construit la compréhension. Vous voyez une fonction utilitaire avant de savoir pourquoi elle existe. Vous voyez une modification de schéma avant de comprendre quelle fonctionnalité elle supporte. Le réviseur doit reconstruire l'intention de l'auteur à partir d'indices dispersés, et c'est cette reconstruction qui fait défaut à l'attention. + +Checkpoint Preview résout ce problème en confiant le travail de reconstruction au LLM. Il lit le diff, la spécification (si elle existe) et la base de code environnante, puis présente la modification dans un ordre conçu pour la compréhension — et non pour `git diff`. + +## Comment ça fonctionne + +Le workflow comporte cinq étapes. Chaque étape s'appuie sur la précédente, passant progressivement de « qu'est-ce que c'est ? » à « devons-nous publier ça ? » + +### 1. Orientation + +Le workflow identifie la modification (à partir d'une PR, d'un commit, d'une branche, d'un fichier de spécification ou de l'état git actuel) et produit un résumé d'intention en une ligne ainsi que des statistiques de surface : fichiers modifiés, modules touchés, lignes de logique, dépassements de boundaries et nouvelles interfaces publiques. + +C'est le moment « est-ce bien ce que je crois ? ». Avant de lire le moindre code, le réviseur confirme qu'il regarde la bonne chose et calibre ses attentes quant à la portée. + +### 2. Visite guidée + +La modification est organisée par **préoccupation** — des intentions de conception cohérentes comme « validation des entrées » ou « contrat d'API » — et non par fichier. Chaque préoccupation fait l'objet d'une courte explication du *pourquoi* de cette approche, suivie d'arrêts cliquables `chemin:ligne` que le réviseur peut suivre dans le code. + +C'est l'étape du jugement de conception. Le réviseur évalue si l'approche est adaptée au système, et non si le code est correct. Les préoccupations sont séquencées de haut en bas : l'intention de plus haut niveau en premier, puis l'implémentation de support. Le réviseur ne rencontre jamais une référence à quelque chose qu'il n'a pas encore vu. + +### 3. Passage en revue des détails + +Une fois que le réviseur comprend la conception, le workflow met en évidence 2 à 5 endroits où une erreur aurait l’impact le plus important. Ceux-ci sont étiquetés par catégorie de risque — `[auth]`, `[schéma]`, `[facturation]`, `[API publique]`, `[sécurité]`, et d'autres — et ordonnés selon l'impact en cas d'erreur. + +Ce n'est pas une chasse aux bugs. Les tests automatisés et la CI gèrent la correction. Le passage en revue des détails active la conscience du risque : « voici les endroits où se tromper coûte le plus cher ». Si le réviseur veut approfondir un domaine spécifique, il peut dire « approfondis [domaine] » pour une re-revue ciblée axée sur la correction. + +Si la spécification a passé des boucles de revues contradictoires (machine hardening), ces résultats sont également présentés ici — pas les bugs qui ont été corrigés, mais les décisions que la boucle de revue a signalées et dont le réviseur devrait être conscient. + +### 4. Tests + +Propose 2 à 5 façons d'observer manuellement la modification en action. Pas des commandes de test automatisé — des observations manuelles qui renforcent la confiance au-delà de ce que toute suite de tests peut fournir. Une interaction UI à essayer, une commande CLI à lancer, une requête API à envoyer, avec les résultats attendus pour chacune. + +Si la modification n'a aucun comportement visible par l'utilisateur, il le dit. Pas de travail inventé. + +### 5. Conclusion + +Le réviseur prend la décision : approuver, retravailler ou continuer la discussion. S'il approuve une PR, le workflow peut aider avec `gh pr review --approve`. S'il demande une refonte, il aide à diagnostiquer si le problème vient de l'approche, de la spécification ou de l'implémentation, et aide à rédiger un retour actionnable lié à des emplacements de code spécifiques. + +## C'est une conversation, pas un rapport + +Le workflow présente chaque étape comme un point de départ, pas un mot final. Entre les étapes — ou au milieu d'une — vous pouvez parler au LLM, poser des questions, remettre en question son cadrage ou faire appel à d'autres skills pour obtenir une perspective différente : + +- **« lance l'élicitation avancée sur la gestion des erreurs »** — pousse le LLM à reconsidérer et affiner son analyse d'un domaine spécifique +- **« active le party mode sur la sécurité de cette migration de schéma »** — fait intervenir plusieurs perspectives agentiques dans un débat ciblé +- **« lance la revue de code »** — génère des résultats structurés avec analyse adversariale et cas limites + +Le workflow checkpoint ne vous enferme pas dans un chemin linéaire. Il vous donne de la structure quand vous la souhaitez et s'efface quand vous voulez explorer. Les cinq étapes sont là pour s'assurer que vous voyez le tableau complet, mais la profondeur à laquelle vous allez à chaque étape — et les outils que vous y apportez — est entièrement entre vos mains. + +## L'historique de revue + +L'étape de visite guidée fonctionne mieux lorsqu'elle dispose d'un **ordre de revue suggéré** — une liste d'arrêts que l'auteur de la spécification a rédigée pour guider les réviseurs à travers la modification. Lorsqu'une spécification inclut cet ordre, le workflow l'utilise directement. + +Lorsqu'aucun historique produit par l'auteur n'existe, le workflow en génère un à partir du diff et du contexte de la base de code. Un historique généré est de qualité inférieure à un historique produit par l'auteur, mais nettement supérieur à la lecture des modifications dans l'ordre des fichiers. + +## Quand l'utiliser + +Le scénario principal est le passage de relais depuis `bmad-quick-dev` : l'implémentation est terminée, le fichier de spécification est ouvert dans votre éditeur avec un historique de revue ajouté, et vous devez décider si vous publiez. Dites « checkpoint » et c'est parti. + +Il fonctionne aussi de manière autonome : + +- **Revue d'une PR** — surtout celles avec plus de quelques fichiers ou des modifications transversales +- **Prise en main d'une modification** — quand vous devez comprendre ce qui s'est passé sur une branche que vous n'avez pas écrite +- **Revue de sprint** — le workflow peut récupérer les stories marquées `review` dans votre fichier de statut de sprint + +Invoquez-le en disant « checkpoint » ou « guide-moi à travers cette modification ». Il fonctionne dans n'importe quel terminal, mais vous en tirerez plus de parti dans un IDE — VS Code, Cursor ou similaire — car le workflow produit des références `chemin:ligne` à chaque étape. Dans un terminal intégré à un IDE, celles-ci sont cliquables, ce qui vous permet de sauter de fichier en fichier en suivant l'historique de revue. + +## Ce que ce n'est pas + +Checkpoint Preview ne remplace pas la revue automatisée. Il ne lance pas de linters, de vérificateurs de types ou de suites de tests. Il n'attribue pas de scores de sévérité et ne produit pas de verdicts pass/échec. C'est un guide de lecture qui aide un humain à appliquer son jugement là où cela compte le plus. diff --git a/docs/fr/explanation/established-projects-faq.md b/docs/fr/explanation/established-projects-faq.md index 94cd3d3a7..b95d41105 100644 --- a/docs/fr/explanation/established-projects-faq.md +++ b/docs/fr/explanation/established-projects-faq.md @@ -2,7 +2,7 @@ title: "FAQ Projets Existants" description: Questions courantes sur l'utilisation de la méthode BMad sur des projets existants sidebar: - order: 8 + order: 11 --- Réponses rapides aux questions courantes sur l'utilisation de la méthode BMad (BMM) sur des projets existants. diff --git a/docs/fr/explanation/party-mode.md b/docs/fr/explanation/party-mode.md index c1250aef2..7e9439447 100644 --- a/docs/fr/explanation/party-mode.md +++ b/docs/fr/explanation/party-mode.md @@ -2,7 +2,7 @@ title: "Party Mode" description: Collaboration multi-agents - regroupez tous vos agents IA dans une seule conversation sidebar: - order: 7 + order: 9 --- Regroupez tous vos agents IA dans une seule conversation. diff --git a/docs/fr/explanation/preventing-agent-conflicts.md b/docs/fr/explanation/preventing-agent-conflicts.md index 93d880308..e987d1cde 100644 --- a/docs/fr/explanation/preventing-agent-conflicts.md +++ b/docs/fr/explanation/preventing-agent-conflicts.md @@ -2,7 +2,7 @@ title: "Prévention des conflits entre agents" description: Comment l'architecture empêche les conflits lorsque plusieurs agents implémentent un système sidebar: - order: 4 + order: 6 --- Lorsque plusieurs agents IA implémentent différentes parties d'un système, ils peuvent prendre des décisions techniques contradictoires. La documentation d'architecture prévient cela en établissant des standards partagés. diff --git a/docs/fr/explanation/project-context.md b/docs/fr/explanation/project-context.md index 4888010fe..c1c3647f8 100644 --- a/docs/fr/explanation/project-context.md +++ b/docs/fr/explanation/project-context.md @@ -2,7 +2,7 @@ title: "Contexte du Projet" description: Comment project-context.md guide les agents IA avec les règles et préférences de votre projet sidebar: - order: 7 + order: 10 --- Le fichier `project-context.md` est le guide d'implémentation de votre projet pour les agents IA. Similaire à une « constitution » dans d'autres systèmes de développement, il capture les règles, les patterns et les préférences qui garantissent une génération de code cohérente à travers tous les workflows. diff --git a/docs/fr/explanation/quick-dev.md b/docs/fr/explanation/quick-dev.md index e45cd5d3c..2f64e4f66 100644 --- a/docs/fr/explanation/quick-dev.md +++ b/docs/fr/explanation/quick-dev.md @@ -2,7 +2,7 @@ title: "Quick Dev" description: Réduire la friction de l’interaction humaine sans renoncer aux points de contrôle qui protègent la qualité des résultats sidebar: - order: 2 + order: 3 --- Intention en entrée, modifications de code en sortie, avec aussi peu d'interactions humaines dans la boucle que possible — sans sacrifier la qualité. diff --git a/docs/fr/explanation/why-solutioning-matters.md b/docs/fr/explanation/why-solutioning-matters.md index fcd922aeb..515ab4007 100644 --- a/docs/fr/explanation/why-solutioning-matters.md +++ b/docs/fr/explanation/why-solutioning-matters.md @@ -2,7 +2,7 @@ title: "Pourquoi le Solutioning est Important" description: Comprendre pourquoi la phase de solutioning est critique pour les projets multi-epics sidebar: - order: 3 + order: 5 --- La Phase 3 (Solutioning) traduit le **quoi** construire (issu de la Planification) en **comment** le construire (conception technique). Cette phase évite les conflits entre agents dans les projets multi-epics en documentant les décisions architecturales avant le début de l'implémentation. diff --git a/docs/fr/how-to/customize-bmad.md b/docs/fr/how-to/customize-bmad.md index c8975cc55..76bb14502 100644 --- a/docs/fr/how-to/customize-bmad.md +++ b/docs/fr/how-to/customize-bmad.md @@ -58,7 +58,7 @@ Modifier la façon dont l'agent se présente : ```yaml agent: metadata: - name: 'Bob l’éponge' # Par défaut : "Mary" + name: 'Bob l’éponge' # Par défaut : "Amelia" ``` **Persona** diff --git a/docs/fr/how-to/get-answers-about-bmad.md b/docs/fr/how-to/get-answers-about-bmad.md index d2632b4aa..7e05e11d4 100644 --- a/docs/fr/how-to/get-answers-about-bmad.md +++ b/docs/fr/how-to/get-answers-about-bmad.md @@ -5,111 +5,55 @@ sidebar: order: 4 --- -## Commencez ici : BMad-Help +Utilisez l'aide intégrée de BMad, la documentation source ou la communauté pour obtenir des réponses — du plus rapide au plus approfondi. -**Le moyen le plus rapide d'obtenir des réponses sur BMad est le skill `bmad-help`.** Ce guide intelligent répondra à plus de 80 % de toutes les questions et est disponible directement dans votre IDE pendant que vous travaillez. +## 1. Demandez à BMad-Help -BMad-Help est bien plus qu'un outil de recherche — il : -- **Inspecte votre projet** pour voir ce qui a déjà été réalisé -- **Comprend le langage naturel** — posez vos questions en français courant -- **S'adapte à vos modules installés** — affiche les options pertinentes -- **Se lance automatiquement après les workflows** — vous indique exactement quoi faire ensuite -- **Recommande la première tâche requise** — plus besoin de deviner par où commencer - -### Comment utiliser BMad-Help - -Appelez-le par son nom dans votre session IA : +Le moyen le plus rapide d'obtenir des réponses. Le skill `bmad-help` est disponible directement dans votre session IA et répond à plus de 80 % des questions — il inspecte votre projet, voit ce que vous avez accompli et vous dit quoi faire ensuite. ``` -bmad-help +bmad-help J'ai une idée de SaaS et je connais toutes les fonctionnalités. Par où commencer ? +bmad-help Quelles sont mes options pour le design UX ? +bmad-help Je suis bloqué sur le workflow PRD ``` :::tip Vous pouvez également utiliser `/bmad-help` ou `$bmad-help` selon votre plateforme, mais `bmad-help` tout seul devrait fonctionner partout. ::: -Combinez-le avec une requête en langage naturel : +## 2. Approfondissez avec les sources -``` -bmad-help J'ai une idée de SaaS et je connais toutes les fonctionnalités. Par où commencer ? -bmad-help Quelles sont mes options pour le design UX ? -bmad-help Je suis bloqué sur le workflow PRD -bmad-help Montre-moi ce qui a été fait jusqu'à maintenant -``` +BMad-Help s'appuie sur votre configuration installée. Pour les questions sur les éléments internes de BMad, son historique ou son architecture — ou si vous faites des recherches sur BMad avant de l'installer — pointez votre IA directement vers les sources. -BMad-Help répond avec : -- Ce qui est recommandé pour votre situation -- Quelle est la première tâche requise -- À quoi ressemble le reste du processus - -## Quand utiliser ce guide - -Utilisez cette section lorsque : -- Vous souhaitez comprendre l'architecture ou les éléments internes de BMad -- Vous avez besoin de réponses au-delà de ce que BMad-Help fournit -- Vous faites des recherches sur BMad avant l'installation -- Vous souhaitez explorer le code source directement - -## Étapes - -### 1. Choisissez votre source - -| Source | Idéal pour | Exemples | -|-------------------------|------------------------------------------------------|---------------------------------------| -| **Dossier `_bmad`** | Comment fonctionne BMad — agents, workflows, prompts | "Que fait l'agent Analyste ?" | -| **Repo GitHub complet** | Historique, installateur, architecture | "Qu'est-ce qui a changé dans la v6 ?" | -| **`llms-full.txt`** | Aperçu rapide depuis la documentation | "Expliquez les quatre phases de BMad" | - -Le dossier `_bmad` est créé lorsque vous installez BMad. Si vous ne l'avez pas encore, clonez le repo à la place. - -### 2. Pointez votre IA vers la source - -**Si votre IA peut lire des fichiers (Claude Code, Cursor, etc.) :** - -- **BMad installé :** Pointez vers le dossier `_bmad` et posez vos questions directement -- **Vous voulez plus de contexte :** Clonez le [repo complet](https://github.com/bmad-code-org/BMAD-METHOD) - -**Si vous utilisez ChatGPT ou Claude.ai (LLM en ligne) :** - -Importez `llms-full.txt` dans votre session : - -```text -https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt -``` - - -### 3. Posez votre question +Clonez ou ouvrez le [dépôt BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) et posez vos questions à votre IA. Tout outil capable d'utiliser des agents (Claude Code, Cursor, Windsurf, etc.) peut lire les sources et répondre directement à vos questions. :::note[Exemple] **Q :** "Quel est le moyen le plus rapide de construire quelque chose avec BMad ?" -**R :** Utilisez le workflow Quick Dev : Lancez `bmad-quick-dev` — il clarifie votre intention, planifie, implémente, révise et présente les résultats dans un seul workflow, en sautant les phases de planification complètes. +**R :** Utilisez le flux rapide : Lancez `bmad-quick-dev` — il clarifie votre intention, planifie, implémente, révise et présente les résultats dans un seul workflow, en sautant les phases de planification complètes. ::: -## Ce que vous obtenez +**Conseils pour de meilleures réponses :** -Des réponses directes sur BMad — comment fonctionnent les agents, ce que font les workflows, pourquoi les choses sont structurées ainsi — sans attendre la réponse de quelqu'un. - -## Conseils - -- **Vérifiez les réponses surprenantes** — Les LLM font parfois des erreurs. Consultez le fichier source ou posez la question sur Discord. - **Soyez précis** — "Que fait l'étape 3 du workflow PRD ?" est mieux que "Comment fonctionne le PRD ?" +- **Vérifiez les affirmations surprenantes** — Les LLM font parfois des erreurs. Consultez le fichier source ou posez la question sur Discord. -## Toujours bloqué ? +### Vous n'utilisez pas d'agent ? Utilisez le site de documentation -Avez-vous essayé l'approche LLM et avez encore besoin d'aide ? Vous avez maintenant une bien meilleure question à poser. +Si votre IA ne peut pas lire des fichiers locaux (ChatGPT, Claude.ai, etc.), importez [llms-full.txt](https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt) dans votre session — c'est un instantané en un seul fichier de la documentation BMad. + +## 3. Demandez à quelqu'un + +Si ni BMad-Help ni la source n'ont répondu à votre question, vous avez maintenant une bien meilleure question à poser. | Canal | Utilisé pour | | ------------------------- | ------------------------------------------- | -| `#bmad-method-help` | Questions rapides (chat en temps réel) | -| Forum `help-requests` | Questions détaillées (recherchables, persistants) | +| Forum `help-requests` | Questions | | `#suggestions-feedback` | Idées et demandes de fonctionnalités | -| `#report-bugs-and-issues` | Rapports de bugs | **Discord :** [discord.gg/gk8jAdXWmj](https://discord.gg/gk8jAdXWmj) -**GitHub Issues :** [github.com/bmad-code-org/BMAD-METHOD/issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) (pour les bugs clairs) - +**GitHub Issues :** [github.com/bmad-code-org/BMAD-METHOD/issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) *Toi !* *Bloqué* *dans la file d'attente—* diff --git a/docs/fr/how-to/install-bmad.md b/docs/fr/how-to/install-bmad.md index 4f79743ea..c58f00c23 100644 --- a/docs/fr/how-to/install-bmad.md +++ b/docs/fr/how-to/install-bmad.md @@ -72,7 +72,7 @@ L'installateur affiche les modules disponibles. Sélectionnez ceux dont vous ave ### 5. Suivre les instructions -L'installateur vous guide pour le reste — contenu personnalisé, paramètres, etc. +L'installateur vous guide pour le reste — paramètres, intégrations d'outils, etc. ## Ce que vous obtenez diff --git a/docs/fr/how-to/non-interactive-installation.md b/docs/fr/how-to/non-interactive-installation.md index 46e8ad4dc..87498285b 100644 --- a/docs/fr/how-to/non-interactive-installation.md +++ b/docs/fr/how-to/non-interactive-installation.md @@ -27,7 +27,6 @@ Nécessite [Node.js](https://nodejs.org) v20+ et `npx` (inclus avec npm). | `--directory ` | Répertoire d'installation | `--directory ~/projects/myapp` | | `--modules ` | IDs de modules séparés par des virgules | `--modules bmm,bmb` | | `--tools ` | IDs d'outils/IDE séparés par des virgules (utilisez `none` pour ignorer) | `--tools claude-code,cursor` ou `--tools none` | -| `--custom-content ` | Chemins vers des modules personnalisés séparés par des virgules | `--custom-content ~/my-module,~/another-module` | | `--action ` | Action pour les installations existantes : `install` (par défaut), `update`, ou `quick-update` | `--action quick-update` | ### Configuration principale @@ -37,7 +36,19 @@ Nécessite [Node.js](https://nodejs.org) v20+ et `npx` (inclus avec npm). | `--user-name ` | Nom à utiliser par les agents | Nom d'utilisateur système | | `--communication-language ` | Langue de communication des agents | Anglais | | `--document-output-language ` | Langue de sortie des documents | Anglais | -| `--output-folder ` | Chemin du dossier de sortie | _bmad-output | +| `--output-folder ` | Chemin du dossier de sortie (voir les règles de résolution ci-dessous) | `_bmad-output` | + +#### Résolution du chemin du dossier de sortie + +La valeur passée à `--output-folder` (ou saisie de manière interactive) est résolue selon ces règles : + +| Type d'entrée | Exemple | Résolu comme | +|-------------------------------|----------------------------|--------------------------------------------------------------| +| Chemin relatif (par défaut) | `_bmad-output` | `/_bmad-output` | +| Chemin relatif avec traversée | `../../shared-outputs` | Chemin absolu normalisé — ex. `/Users/me/shared-outputs` | +| Chemin absolu | `/Users/me/shared-outputs` | Utilisé tel quel — la racine du projet n'est **pas** ajoutée | + +Le chemin résolu est ce que les agents et les workflows vont utiliser lors de l'écriture des fichiers de sortie. L'utilisation d'un chemin absolu ou d'un chemin relatif avec traversée vous permet de diriger tous les artefacts générés vers un répertoire en dehors de l'arborescence de votre projet — utile pour les configurations partagées ou les monorepos. ### Autres options @@ -61,7 +72,7 @@ IDs d'outils disponibles pour l’option `--tools` : **Recommandés :** `claude-code`, `cursor` -Exécutez `npx bmad-method install` de manière interactive une fois pour voir la liste complète actuelle des outils pris en charge, ou consultez la [configuration des codes de la plateforme](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/cli/installers/lib/ide/platform-codes.yaml). +Exécutez `npx bmad-method install` de manière interactive une fois pour voir la liste complète actuelle des outils pris en charge, ou consultez la [configuration des codes de la plateforme](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/installer/ide/platform-codes.yaml). ## Modes d'installation @@ -108,16 +119,6 @@ npx bmad-method install \ --action quick-update ``` -### Installation avec du contenu personnalisé - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --modules bmm \ - --custom-content ~/my-custom-module,~/another-module \ - --tools claude-code -``` - ## Ce que vous obtenez - Un répertoire `_bmad/` entièrement configuré dans votre projet @@ -131,16 +132,16 @@ BMad valide toutes les options fournis : - **Directory** — Doit être un chemin valide avec des permissions d'écriture - **Modules** — Avertit des IDs de modules invalides (mais n'échoue pas) - **Tools** — Avertit des IDs d'outils invalides (mais n'échoue pas) -- **Custom Content** — Chaque chemin doit contenir un fichier `module.yaml` valide - **Action** — Doit être l'une des suivantes : `install`, `update`, `quick-update` Les valeurs invalides entraîneront soit : 1. L’affichage d’un message d'erreur suivi d’un exit (pour les options critiques comme le répertoire) -2. Un avertissement puis la continuation de l’installation (pour les éléments optionnels comme le contenu personnalisé) +2. Un avertissement puis la continuation de l’installation (pour les éléments optionnels) 3. Un retour aux invites interactives (pour les valeurs requises manquantes) :::tip[Bonnes pratiques] - Utilisez des chemins absolus pour `--directory` pour éviter toute ambiguïté +- Utilisez un chemin absolu pour `--output-folder` lorsque vous souhaitez que les artefacts soient écrits en dehors de l'arborescence du projet (ex. un répertoire de sorties partagé dans un monorepo) - Testez les options localement avant de les utiliser dans des pipelines CI/CD - Combinez avec `-y` pour des installations vraiment sans surveillance - Utilisez `--debug` si vous rencontrez des problèmes lors de l'installation @@ -159,13 +160,6 @@ Les valeurs invalides entraîneront soit : - Vérifiez que l'ID du module est correct - Les modules externes doivent être disponibles dans le registre -### Chemin de contenu personnalisé invalide - -Assurez-vous que chaque chemin de contenu personnalisé : -- Pointe vers un répertoire -- Contient un fichier `module.yaml` à la racine -- Possède un champ `code` dans `module.yaml` - :::note[Toujours bloqué ?] Exécutez avec `--debug` pour une sortie détaillée, essayez le mode interactif pour isoler le problème, ou signalez-le à . ::: diff --git a/docs/fr/how-to/upgrade-to-v6.md b/docs/fr/how-to/upgrade-to-v6.md index 6468dc729..bd600cbcb 100644 --- a/docs/fr/how-to/upgrade-to-v6.md +++ b/docs/fr/how-to/upgrade-to-v6.md @@ -61,8 +61,8 @@ Si vous avez des stories[^3] créées ou implémentées : 1. Terminez l'installation v6 2. Placez `epics.md` ou `epics/epic*.md`[^2] dans `_bmad-output/planning-artifacts/` -3. Lancez le workflow `bmad-sprint-planning`[^4] -4. Indiquez quels epics/stories sont déjà terminés +3. Lancez le workflow Développeur `bmad-sprint-planning`[^4] +4. Indiquez à l’agent quels epics/stories sont déjà terminés ## Ce que vous obtenez diff --git a/docs/fr/reference/agents.md b/docs/fr/reference/agents.md index 1fa8057ea..2d6248dba 100644 --- a/docs/fr/reference/agents.md +++ b/docs/fr/reference/agents.md @@ -1,26 +1,28 @@ --- title: Agents -description: Agents BMM par défaut avec leurs identifiants de skill, déclencheurs de menu et workflows principaux (Analyst, Architect, UX Designer, Technical Writer) +description: Agents BMM par défaut avec leurs identifiants de skill, déclencheurs de menu et workflows principaux sidebar: order: 2 --- ## Agents par défaut -Cette page liste les quatre agents BMM (suite Agile) par défaut installés avec la méthode BMad, ainsi que leurs identifiants de skill, déclencheurs de menu et workflows principaux. Chaque agent est invoqué en tant que skill. +Cette page liste les agents BMM (suite Agile) par défaut installés avec la méthode BMad, ainsi que leurs identifiants de skill, déclencheurs de menu et workflows principaux. Chaque agent est invoqué en tant que skill. ## Notes -- Chaque agent est disponible en tant que skill, généré par l’installateur. L’identifiant de skill (par exemple, `bmad-analyst`) est utilisé pour invoquer l’agent. +- Chaque agent est disponible en tant que skill, généré par l’installateur. L’identifiant de skill (par exemple, `bmad-dev`) est utilisé pour invoquer l’agent. - Les déclencheurs sont les codes courts de menu (par exemple, `BP`) et les correspondances approximatives affichés dans chaque menu d’agent. -- La génération de tests QA est gérée par le skill de workflow `bmad-qa-generate-e2e-tests`. L’architecte de tests complet (TEA) se trouve dans son propre module. +- La génération de tests QA est gérée par le skill de workflow `bmad-qa-generate-e2e-tests`, disponible par l’agent Développeur. L’architecte de tests complet (TEA) se trouve dans son propre module. -| Agent | Identifiant de skill | Déclencheurs | Workflows principaux | -|------------------------|----------------------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Analyste (Mary) | `bmad-analyst` | `BP`, `MR`, `DR`, `TR`, `CB`, `DP` | Brainstorming du projet, Recherche marché/domaine/technique, Création du brief[^1], Documentation du projet | -| Architecte (Winston) | `bmad-architect` | `CA`, `IR` | Créer l’architecture, Préparation à l’implémentation | -| Designer UX (Sally) | `bmad-ux-designer` | `CU` | Création du design UX[^2] | -| Rédacteur Technique (Paige) | `bmad-tech-writer` | `DP`, `WD`, `US`, `MG`, `VD`, `EC` | Documentation du projet, Rédaction de documents, Mise à jour des standards, Génération de diagrammes Mermaid, Validation de documents, Explication de concepts | +| Agent | Identifiant de skill | Déclencheurs | Workflows principaux | +|-----------------------------|----------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Analyste (Mary) | `bmad-analyst` | `BP`, `MR`, `DR`, `TR`, `CB`, `WB`, `DP` | Brainstorming du projet, Recherche marché/domaine/technique, Création du brief[^1], Défi PRFAQ, Documentation du projet | +| Product Manager (John) | `bmad-pm` | `CP`, `VP`, `EP`, `CE`, `IR`, `CC` | Créer/Valider/Éditer un PRD, Créer des Epics et Stories, vérifier l’état de préparation à l’Implémentation, Corriger le Cours | +| Architecte (Winston) | `bmad-architect` | `CA`, `IR` | Créer l’architecture, Préparation à l’implémentation | +| Développeur (Amelia) | `bmad-agent-dev` | `DS`, `QD`, `QA`, `CR`, `SP`, `CS`, `ER` | Dev Story, Quick Dev, Génération de Tests QA, Code Review, Sprint Planning, Créer Story, Rétrospective d’Epic | +| Designer UX (Sally) | `bmad-ux-designer` | `CU` | Création du design UX[^2] | +| Rédacteur Technique (Paige) | `bmad-tech-writer` | `DP`, `WD`, `US`, `MG`, `VD`, `EC` | Documentation du projet, Rédaction de documents, Mise à jour des standards, Génération de diagrammes Mermaid, Validation de documents, Explication de concepts | ## Types de déclencheurs @@ -30,7 +32,7 @@ Les déclencheurs de menu d'agent utilisent deux types d'invocation différents. La plupart des déclencheurs chargent un fichier de workflow structuré. Tapez le code du déclencheur et l'agent démarre le workflow, vous demandant de saisir les informations à chaque étape. -Exemples : `BP` (Brainstorm Project), `CA` (Create Architecture), `CU` (Create UX Design) +Exemples : `CP` (Create PRD), `DS` (Dev Story), `CA` (Create Architecture), `QD` (Quick Dev) ### Déclencheurs conversationnels (arguments requis) diff --git a/docs/fr/reference/commands.md b/docs/fr/reference/commands.md index 1048976da..a93f331b9 100644 --- a/docs/fr/reference/commands.md +++ b/docs/fr/reference/commands.md @@ -2,7 +2,7 @@ title: Skills description: Référence des skills BMad — ce qu'ils sont, comment ils fonctionnent et où les trouver. sidebar: - order: 3 + order: 4 --- Les skills sont des prompts pré-construits qui chargent des agents, exécutent des workflows ou lancent des tâches dans votre IDE. L'installateur BMad les génère à partir de vos modules installés au moment de l'installation. Si vous ajoutez, supprimez ou modifiez des modules ultérieurement, relancez l'installateur pour garder les skills synchronisés (voir [Dépannage](#dépannage)). @@ -54,12 +54,12 @@ Chaque skill est un répertoire contenant un fichier `SKILL.md`. Par exemple, un │ └── SKILL.md ├── bmad-create-prd/ │ └── SKILL.md -├── bmad-analyst/ +├── bmad-agent-dev/ │ └── SKILL.md └── ... ``` -Le nom du répertoire détermine le nom du skill dans votre IDE. Par exemple, le répertoire `bmad-analyst/` enregistre le skill `bmad-analyst`. +Le nom du répertoire détermine le nom du skill dans votre IDE. Par exemple, le répertoire `bmad-agent-dev/` enregistre le skill `bmad-agent-dev`. ## Comment découvrir vos skills @@ -75,23 +75,24 @@ Les répertoires de skills générés dans votre projet sont la liste de référ ### Skills d'agent -Les skills d'agent chargent une persona[^2] IA spécialisée avec un rôle défini, un style de communication et un menu de workflows. Une fois chargé, l'agent reste en caractère et répond aux déclencheurs du menu. +Les skills d'agent chargent un persona[^2] IA spécialisé avec un rôle défini, un style de communication et un menu de workflows. Une fois chargé, l'agent reste en caractère et répond aux déclencheurs du menu. -| Exemple de skill | Agent | Rôle | -| --- | --- | --- | -| `bmad-analyst` | Mary (Analyste) | Brainstorming de projets, recherche, création de briefs | -| `bmad-architect` | Winston (Architecte) | Conçoit l'architecture système | -| `bmad-ux-designer` | Sally (Designer UX) | Crée les designs UX | -| `bmad-tech-writer` | Paige (Rédacteur Technique) | Documente les projets, rédige des guides, génère des diagrammes | +| Exemple de skill | Agent | Rôle | +|------------------|------------------------|-------------------------------------------------------------| +| `bmad-agent-dev` | Amelia (Développeur) | Implémente les stories avec une adhérence stricte aux specs | +| `bmad-pm` | John (Product Manager) | Crée et valide les PRDs[^1] | +| `bmad-architect` | Winston (Architecte) | Conçoit l'architecture système | Consultez [Agents](./agents.md) pour la liste complète des agents par défaut et leurs déclencheurs. ### Skills de workflow -Les skills de workflow exécutent un processus structuré en plusieurs étapes sans charger d'abord une persona d'agent. Ils chargent une configuration de workflow et suivent ses étapes. +Les skills de workflow exécutent un processus structuré en plusieurs étapes sans charger d'abord un persona d'agent. Ils chargent une configuration de workflow et suivent ses étapes. | Exemple de skill | Objectif | | --- | --- | +| `bmad-product-brief` | Créer un product brief[^3] — découverte guidée lorsque votre concept est clair | +| `bmad-prfaq` | Défi [PRFAQ Working Backwards](../explanation/analysis-phase.md#prfaq-working-backwards) pour éprouver votre concept produit | | `bmad-create-prd` | Créer un PRD[^1] | | `bmad-create-architecture` | Concevoir l'architecture système | | `bmad-create-epics-and-stories` | Créer des epics et des stories | @@ -123,7 +124,7 @@ Le module principal inclut 11 outils intégrés — revues, compression, brainst ## Convention de nommage -Tous les skills utilisent le préfixe `bmad-` suivi d'un nom descriptif (ex. `bmad-analyst`, `bmad-create-prd`, `bmad-help`). Consultez [Modules](./modules.md) pour les modules disponibles. +Tous les skills utilisent le préfixe `bmad-` suivi d'un nom descriptif (ex. `bmad-agent-dev`, `bmad-create-prd`, `bmad-help`). Consultez [Modules](./modules.md) pour les modules disponibles. ## Dépannage @@ -136,4 +137,5 @@ Tous les skills utilisent le préfixe `bmad-` suivi d'un nom descriptif (ex. `bm ## Glossaire [^1]: PRD (Product Requirements Document) : document de référence qui décrit les objectifs du produit, les besoins utilisateurs, les fonctionnalités attendues, les contraintes et les critères de succès, afin d’aligner les équipes sur ce qui doit être construit et pourquoi. -[^2]: Persona : dans le contexte de BMad, une persona désigne un agent IA avec un rôle défini, un style de communication et une expertise spécifiques (ex. Mary l'analyste, Winston l'architecte). Chaque persona garde son "caractère" pendant les interactions. +[^2]: Persona : dans le contexte de BMad, un persona désigne un agent IA avec un rôle défini, un style de communication et une expertise spécifiques (ex. Mary l'analyste, Winston l'architecte). Chaque persona garde son "caractère" pendant les interactions. +[^3]: Brief : document synthétique qui formalise le contexte, les objectifs, le périmètre et les contraintes d'un projet ou d'une demande, afin d'aligner rapidement les parties prenantes avant le travail détaillé. diff --git a/docs/fr/reference/core-tools.md b/docs/fr/reference/core-tools.md index 808b4c3bd..644a849fc 100644 --- a/docs/fr/reference/core-tools.md +++ b/docs/fr/reference/core-tools.md @@ -2,7 +2,7 @@ title: Outils Principaux description: Référence pour toutes les tâches et tous les workflows intégrés disponibles dans chaque installation BMad sans modules supplémentaires. sidebar: - order: 2 + order: 3 --- Chaque installation BMad comprend un ensemble de compétences principales qui peuvent être utilisées conjointement avec tout ce que vous faites — des tâches et des workflows autonomes qui fonctionnent dans tous les projets, tous les modules et toutes les phases. Ceux-ci sont toujours disponibles, quels que soient les modules optionnels que vous installez. diff --git a/docs/fr/reference/modules.md b/docs/fr/reference/modules.md index 8c0ae8126..60f7e7e4c 100644 --- a/docs/fr/reference/modules.md +++ b/docs/fr/reference/modules.md @@ -2,7 +2,7 @@ title: Modules Officiels description: Modules additionnels pour créer des agents personnalisés, de l'intelligence créative, du développement de jeux et des tests sidebar: - order: 4 + order: 5 --- BMad s'étend via des modules officiels que vous sélectionnez lors de l'installation. Ces modules additionnels fournissent des agents, des workflows et des tâches spécialisés pour des domaines spécifiques, au-delà du noyau intégré et de BMM (suite Agile). diff --git a/docs/fr/reference/testing.md b/docs/fr/reference/testing.md index a7e487df4..d0d762691 100644 --- a/docs/fr/reference/testing.md +++ b/docs/fr/reference/testing.md @@ -2,7 +2,7 @@ title: Options de Testing description: Comparaison du workflow QA intégré avec le module Test Architect (TEA) pour l'automatisation des tests. sidebar: - order: 5 + order: 6 --- BMad propose deux approches de test : un workflow QA[^1] intégré pour une génération rapide de tests et un module Test Architect installable pour une stratégie de test de qualité entreprise. @@ -24,9 +24,9 @@ La plupart des projets devraient commencer avec le workflow QA intégré. Si vou ## Workflow QA Intégré -Le workflow QA intégré est inclus dans le module BMM (suite Agile). Il génère rapidement des tests fonctionnels en utilisant le framework de test existant de votre projet — aucune configuration ni installation supplémentaire requise. +Le workflow QA intégré (`bmad-qa-generate-e2e-tests`) fait partie du module BMM (suite Agile), disponible via l'agent Developer. Il génère rapidement des tests fonctionnels en utilisant le framework de test existant de votre projet — aucune configuration ni installation supplémentaire requise. -**Déclencheur :** `QA` ou `bmad-qa-generate-e2e-tests` +**Déclencheur :** `QA` (via l'agent Developer) ou `bmad-qa-generate-e2e-tests` ### Ce que le Workflow QA Fait @@ -98,7 +98,7 @@ TEA supporte également la priorisation basée sur les risques P0-P3 et des int Le workflow Automate du QA intégré apparaît dans la Phase 4 (Implémentation) de la carte de workflow méthode BMad. Il est conçu pour s'exécuter **après qu'un epic complet soit terminé** — une fois que toutes les stories d'un epic ont été implémentées et revues. Une séquence typique : 1. Pour chaque story de l'epic : implémenter avec Dev Story (`DS`), puis valider avec Code Review (`CR`) -2. Après la fin de l'epic : générer les tests avec le workflow QA (`QA`) ou le workflow Automate de TEA +2. Après la fin de l'epic : générer les tests avec `QA` (via l'agent Developer) ou le workflow Automate de TEA 3. Lancer la rétrospective (`bmad-retrospective`) pour capturer les leçons apprises Le workflow QA travaille directement à partir du code source sans charger les documents de planification (PRD, architecture). Les workflows TEA peuvent s'intégrer avec les artefacts de planification en amont pour la traçabilité. diff --git a/docs/fr/reference/workflow-map.md b/docs/fr/reference/workflow-map.md index 50821c6fd..1a72e2618 100644 --- a/docs/fr/reference/workflow-map.md +++ b/docs/fr/reference/workflow-map.md @@ -21,13 +21,14 @@ Note finale importante : Chaque workflow ci-dessous peut être exécuté directe ## Phase 1 : Analyse (Optionnelle) -Explorez l’espace problème et validez les idées avant de vous engager dans la planification. +Explorez l’espace problème et validez les idées avant de vous engager dans la planification. [**Découvrez ce que fait chaque outil et quand l’utiliser**](../explanation/analysis-phase.md). | Workflow | Objectif | Produit | |---------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------| -| `bmad-brainstorming` | Brainstormez des idées de projet avec l'accompagnement guidé d'un coach de brainstorming | `brainstorming-report.md` | +| `bmad-brainstorming` | Brainstormez des idées de projet avec l’accompagnement guidé d’un coach de brainstorming | `brainstorming-report.md` | | `bmad-domain-research`, `bmad-market-research`, `bmad-technical-research` | Validez les hypothèses de marché, techniques ou de domaine | Rapport de recherches | -| `bmad-create-product-brief` | Capturez la vision stratégique | `product-brief.md` | +| `bmad-product-brief` | Capturez la vision stratégique — idéal lorsque votre concept est clair | `product-brief.md` | +| `bmad-prfaq` | Working Backwards — éprouvez et forgez votre concept produit | `prfaq-{project}.md` | ## Phase 2 : Planification diff --git a/docs/fr/tutorials/getting-started.md b/docs/fr/tutorials/getting-started.md index 70d6e3095..8d729debf 100644 --- a/docs/fr/tutorials/getting-started.md +++ b/docs/fr/tutorials/getting-started.md @@ -68,7 +68,7 @@ BMad vous aide à construire des logiciels grâce à des workflows guidés avec | Phase | Nom | Ce qui se passe | |-------|----------------|----------------------------------------------------------------| -| 1 | Analyse | Brainstorming, recherche, product brief *(optionnel)* | +| 1 | Analyse | Brainstorming, recherche, product brief ou PRFAQ *(optionnel)* | | 2 | Planification | Créer les exigences (PRD[^1] ou spécification technique) | | 3 | Solutioning | Concevoir l'architecture *(BMad Method/Enterprise uniquement)* | | 4 | Implémentation | Construire epic[^2] par epic, story[^3] par story | @@ -114,7 +114,7 @@ BMad-Help détectera ce que vous avez accompli et recommandera exactement quoi f ::: :::note[Comment charger les agents et exécuter les workflows] -Chaque workflow possède une **skill** que vous invoquez par nom dans votre IDE (par ex., `bmad-create-prd`). Votre outil IA reconnaîtra le nom `bmad-*` et l'exécutera. +Chaque workflow possède une **skill** que vous invoquez par nom dans votre IDE (par ex., `bmad-create-prd`). Votre outil IA reconnaîtra le nom `bmad-*` et l'exécutera — vous n'avez pas besoin de charger les agents séparément. Vous pouvez aussi invoquer directement une skill d'agent pour une conversation générale (par ex., `bmad-agent-pm` pour l'agent PM). ::: :::caution[Nouveaux chats] @@ -133,29 +133,32 @@ Créez-le manuellement dans `_bmad-output/project-context.md` ou générez-le ap ### Phase 1 : Analyse (Optionnel) -Tous les workflows de cette phase sont optionnels : +Tous les workflows de cette phase sont optionnels. [**Pas sûr de quel outil utiliser ?**](../explanation/analysis-phase.md) - **brainstorming** (`bmad-brainstorming`) — Idéation guidée - **research** (`bmad-market-research` / `bmad-domain-research` / `bmad-technical-research`) — Recherche marché, domaine et technique -- **create-product-brief** (`bmad-create-product-brief`) — Document de base recommandé +- **product-brief** (`bmad-product-brief`) — Document de base recommandé lorsque votre concept est clair +- **prfaq** (`bmad-prfaq`) — Défi Working Backwards pour éprouver et forger votre concept produit ### Phase 2 : Planification (Requis) **Pour les voies BMad Method et Enterprise :** -1. Exécutez `bmad-create-prd` dans un nouveau chat -2. Sortie : `PRD.md` +1. Invoquez l'**agent PM** (`bmad-agent-pm`) dans un nouveau chat +2. Exécutez le workflow `bmad-create-prd` (`bmad-create-prd`) +3. Sortie : `PRD.md` **Pour la voie Quick Dev :** -- Utilisez le workflow `bmad-quick-dev` (`bmad-quick-dev`) à la place du PRD, puis passez à l'implémentation +- Exécutez `bmad-quick-dev` — il gère la planification et l'implémentation dans un seul workflow, passez directement à l'implémentation :::note[Design UX (Optionnel)] -Si votre projet a une interface utilisateur, exécutez le workflow de design UX (`bmad-create-ux-design`) après avoir créé votre PRD. +Si votre projet a une interface utilisateur, invoquez l'**agent Designer UX** (`bmad-agent-ux-designer`) et exécutez le workflow de design UX (`bmad-create-ux-design`) après avoir créé votre PRD. ::: ### Phase 3 : Solutioning (méthode BMad/Enterprise) **Créer l'Architecture** -1. Exécutez `bmad-create-architecture` dans un nouveau chat -2. Sortie : Document d'architecture avec les décisions techniques +1. Invoquez l'**agent Architecte** (`bmad-agent-architect`) dans un nouveau chat +2. Exécutez `bmad-create-architecture` (`bmad-create-architecture`) +3. Sortie : Document d'architecture avec les décisions techniques **Créer les Epics et Stories** @@ -163,12 +166,14 @@ Si votre projet a une interface utilisateur, exécutez le workflow de design UX Les epics et stories sont maintenant créés *après* l'architecture. Cela produit des stories de meilleure qualité car les décisions d'architecture (base de données, patterns d'API, pile technologique) affectent directement la façon dont le travail doit être décomposé. ::: -1. Exécutez `bmad-create-epics-and-stories` dans un nouveau chat -2. Le workflow utilise à la fois le PRD et l'Architecture pour créer des stories techniquement éclairées +1. Invoquez l'**agent PM** (`bmad-agent-pm`) dans un nouveau chat +2. Exécutez `bmad-create-epics-and-stories` (`bmad-create-epics-and-stories`) +3. Le workflow utilise à la fois le PRD et l'Architecture pour créer des stories techniquement éclairées **Vérification de préparation à l'implémentation** *(Hautement recommandé)* -1. Exécutez `bmad-check-implementation-readiness` dans un nouveau chat -2. Valide la cohérence entre tous les documents de planification +1. Invoquez l'**agent Architecte** (`bmad-agent-architect`) dans un nouveau chat +2. Exécutez `bmad-check-implementation-readiness` (`bmad-check-implementation-readiness`) +3. Valide la cohérence entre tous les documents de planification ## Étape 2 : Construire votre projet @@ -176,19 +181,19 @@ Une fois la planification terminée, passez à l'implémentation. **Chaque workf ### Initialiser la planification de sprint -Exécutez `bmad-sprint-planning` dans un nouveau chat. Cela crée `sprint-status.yaml` pour suivre tous les epics et stories. +Invoquez **l’agent Développeur** (`bmad-agent-dev`) et lancez `bmad-sprint-planning`. Cela crée `sprint-status.yaml` pour suivre tous les epics et stories. ### Le cycle de construction Pour chaque story, répétez ce cycle avec de nouveaux chats : -| Étape | Workflow | Commande | Objectif | -| ----- | --------------------- | --------------------- | ----------------------------------- | -| 1 | `bmad-create-story` | `bmad-create-story` | Créer le fichier story depuis l'epic | -| 2 | `bmad-dev-story` | `bmad-dev-story` | Implémenter la story | -| 3 | `bmad-code-review` | `bmad-code-review` | Validation de qualité *(recommandé)* | +| Étape | AGENT | Workflow | Commande | Objectif | +|-------|-------|---------------------|---------------------|--------------------------------------| +| 1 | DEV | `bmad-create-story` | `bmad-create-story` | Créer le fichier story depuis l'epic | +| 2 | DEV | `bmad-dev-story` | `bmad-dev-story` | Implémenter la story | +| 3 | DEV | `bmad-code-review` | `bmad-code-review` | Validation de qualité *(recommandé)* | -Après avoir terminé toutes les stories d'un epic, exécutez `bmad-retrospective` dans un nouveau chat. +Après avoir terminé toutes les stories d'un epic, invoquez **l’agent Développeur** (`bmad-agent-dev`), et exécutez `bmad-retrospective`. ## Ce que vous avez accompli @@ -217,18 +222,18 @@ your-project/ ## Référence rapide -| Workflow | Commande | Objectif | -| ------------------------------------- | ------------------------------------------- | ------------------------------------------------ | -| **`bmad-help`** ⭐ | `bmad-help` | **Votre guide intelligent — posez n'importe quelle question !** | -| `bmad-create-prd` | `bmad-create-prd` | Créer le document d'exigences produit | -| `bmad-create-architecture` | `bmad-create-architecture` | Créer le document d'architecture | -| `bmad-generate-project-context` | `bmad-generate-project-context` | Créer le fichier de contexte projet | -| `bmad-create-epics-and-stories` | `bmad-create-epics-and-stories` | Décomposer le PRD en epics | -| `bmad-check-implementation-readiness` | `bmad-check-implementation-readiness` | Valider la cohérence de planification | -| `bmad-sprint-planning` | `bmad-sprint-planning` | Initialiser le suivi de sprint | -| `bmad-create-story` | `bmad-create-story` | Créer un fichier story | -| `bmad-dev-story` | `bmad-dev-story` | Implémenter une story | -| `bmad-code-review` | `bmad-code-review` | Revoir le code implémenté | +| Workflow | Commande | Agent | Objectif | +|---------------------------------------|---------------------------------------|-----------|-----------------------------------------------------------------| +| **`bmad-help`** ⭐ | `bmad-help` | Tous | **Votre guide intelligent — posez n'importe quelle question !** | +| `bmad-create-prd` | `bmad-create-prd` | PM | Créer le document d'exigences produit | +| `bmad-create-architecture` | `bmad-create-architecture` | Architect | Créer le document d'architecture | +| `bmad-generate-project-context` | `bmad-generate-project-context` | Analyst | Créer le fichier de contexte projet | +| `bmad-create-epics-and-stories` | `bmad-create-epics-and-stories` | PM | Décomposer le PRD en epics | +| `bmad-check-implementation-readiness` | `bmad-check-implementation-readiness` | Architect | Valider la cohérence de planification | +| `bmad-sprint-planning` | `bmad-sprint-planning` | DEV | Initialiser le suivi de sprint | +| `bmad-create-story` | `bmad-create-story` | DEV | Créer un fichier story | +| `bmad-dev-story` | `bmad-dev-story` | DEV | Implémenter une story | +| `bmad-code-review` | `bmad-code-review` | DEV | Revoir le code implémenté | ## Questions fréquentes @@ -236,7 +241,7 @@ your-project/ Uniquement pour les voies méthode BMad et Enterprise. Quick Dev passe directement de la spécification technique (spec) à l'implémentation. **Puis-je modifier mon plan plus tard ?** -Oui. Utilisez `bmad-correct-course` pour gérer les changements de périmètre. +Oui. Utilisez `bmad-correct-course` pour gérer les changements de périmètre en cours d’implémentation. **Et si je veux d'abord faire du brainstorming ?** Invoquez l'agent Analyst (`bmad-agent-analyst`) et exécutez `bmad-brainstorming` (`bmad-brainstorming`) avant de commencer votre PRD. diff --git a/docs/how-to/customize-bmad.md b/docs/how-to/customize-bmad.md index 15832df89..e77d94a72 100644 --- a/docs/how-to/customize-bmad.md +++ b/docs/how-to/customize-bmad.md @@ -1,8 +1,8 @@ --- -title: "How to Customize BMad" +title: 'How to Customize BMad' description: Customize agents, workflows, and modules while preserving update compatibility sidebar: - order: 7 + order: 8 --- Use the `.customize.yaml` files to tailor agent behavior, personas, and menus while preserving your changes across updates. @@ -15,9 +15,10 @@ Use the `.customize.yaml` files to tailor agent behavior, personas, and menus wh - You want agents to perform specific actions every time they start up :::note[Prerequisites] + - BMad installed in your project (see [How to Install BMad](./install-bmad.md)) - A text editor for YAML files -::: + ::: :::caution[Keep Your Customizations Safe] Always use the `.customize.yaml` files described here rather than editing agent files directly. The installer overwrites agent files during updates, but preserves your `.customize.yaml` changes. @@ -136,10 +137,10 @@ npx bmad-method install The installer detects the existing installation and offers these options: -| Option | What It Does | -| ---------------------------- | ------------------------------------------------------------------- | +| Option | What It Does | +| ---------------------------- | -------------------------------------------------------------------- | | **Quick Update** | Updates all modules to the latest version and applies customizations | -| **Modify BMad Installation** | Full installation flow for adding or removing modules | +| **Modify BMad Installation** | Full installation flow for adding or removing modules | For customization-only changes, **Quick Update** is the fastest option. diff --git a/docs/how-to/established-projects.md b/docs/how-to/established-projects.md index ebe0e313c..c065458d6 100644 --- a/docs/how-to/established-projects.md +++ b/docs/how-to/established-projects.md @@ -1,8 +1,8 @@ --- -title: "Established Projects" +title: 'Established Projects' description: How to use BMad Method on existing codebases sidebar: - order: 6 + order: 7 --- Use BMad Method effectively when working on existing projects and legacy codebases. @@ -10,10 +10,11 @@ Use BMad Method effectively when working on existing projects and legacy codebas This guide covers the essential workflow for onboarding to existing projects with BMad Method. :::note[Prerequisites] + - BMad Method installed (`npx bmad-method install`) - An existing codebase you want to work on - Access to an AI-powered IDE (Claude Code or Cursor) -::: + ::: ## Step 1: Clean Up Completed Planning Artifacts @@ -36,6 +37,7 @@ bmad-generate-project-context ``` This scans your codebase to identify: + - Technology stack and versions - Code organization patterns - Naming conventions @@ -79,10 +81,10 @@ BMad-Help also **automatically runs at the end of every workflow**, providing cl You have two primary options depending on the scope of changes: -| Scope | Recommended Approach | -| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| Scope | Recommended Approach | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | **Small updates or additions** | Run `bmad-quick-dev` to clarify intent, plan, implement, and review in a single workflow. The full four-phase BMad Method is likely overkill. | -| **Major changes or additions** | Start with the BMad Method, applying as much or as little rigor as needed. | +| **Major changes or additions** | Start with the BMad Method, applying as much or as little rigor as needed. | ### During PRD Creation diff --git a/docs/how-to/get-answers-about-bmad.md b/docs/how-to/get-answers-about-bmad.md index 61766167a..77a554104 100644 --- a/docs/how-to/get-answers-about-bmad.md +++ b/docs/how-to/get-answers-about-bmad.md @@ -1,84 +1,31 @@ --- -title: "How to Get Answers About BMad" +title: 'How to Get Answers About BMad' description: Use an LLM to quickly answer your own BMad questions sidebar: - order: 4 + order: 5 --- -## Start Here: BMad-Help +Use BMad's built-in help, source docs, or the community to get answers — from quickest to most thorough. -**The fastest way to get answers about BMad is the `bmad-help` skill.** This intelligent guide will answer upwards of 80% of all questions and is available to you directly in your IDE as you work. +## 1. Ask BMad-Help -BMad-Help is more than a lookup tool — it: -- **Inspects your project** to see what's already been completed -- **Understands natural language** — ask questions in plain English -- **Varies based on your installed modules** — shows relevant options -- **Auto-runs after workflows** — tells you exactly what to do next -- **Recommends the first required task** — no guessing where to start - -### How to Use BMad-Help - -Call it by name in your AI session: +The fastest way to get answers. The `bmad-help` skill is available directly in your AI session and handles over 80% of questions — it inspects your project, sees what you've completed, and tells you what to do next. ``` -bmad-help +bmad-help I have a SaaS idea and know all the features. Where do I start? +bmad-help What are my options for UX design? +bmad-help I'm stuck on the PRD workflow ``` :::tip You can also use `/bmad-help` or `$bmad-help` depending on your platform, but just `bmad-help` should work everywhere. ::: -Combine it with a natural language query: +## 2. Go Deeper with Source -``` -bmad-help I have a SaaS idea and know all the features. Where do I start? -bmad-help What are my options for UX design? -bmad-help I'm stuck on the PRD workflow -bmad-help Show me what's been done so far -``` +BMad-Help draws on your installed configuration. For questions about BMad's internals, history, or architecture — or if you're researching BMad before installing — point your AI at the source directly. -BMad-Help responds with: -- What's recommended for your situation -- What the first required task is -- What the rest of the process looks like - -## When to Use This Guide - -Use this section when: -- You want to understand BMad's architecture or internals -- You need answers outside of what BMad-Help provides -- You're researching BMad before installing -- You want to explore the source code directly - -## Steps - -### 1. Choose Your Source - -| Source | Best For | Examples | -| -------------------- | ----------------------------------------- | ---------------------------- | -| **`_bmad` folder** | How BMad works—agents, workflows, prompts | "What does the PM agent do?" | -| **Full GitHub repo** | History, installer, architecture | "What changed in v6?" | -| **`llms-full.txt`** | Quick overview from docs | "Explain BMad's four phases" | - -The `_bmad` folder is created when you install BMad. If you don't have it yet, clone the repo instead. - -### 2. Point Your AI at the Source - -**If your AI can read files (Claude Code, Cursor, etc.):** - -- **BMad installed:** Point at the `_bmad` folder and ask directly -- **Want deeper context:** Clone the [full repo](https://github.com/bmad-code-org/BMAD-METHOD) - -**If you use ChatGPT or Claude.ai:** - -Fetch `llms-full.txt` into your session: - -```text -https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt -``` - - -### 3. Ask Your Question +Clone or open the [BMAD-METHOD repo](https://github.com/bmad-code-org/BMAD-METHOD) and ask your AI about it. Any agent-capable tool (Claude Code, Cursor, Windsurf, etc.) can read the source and answer questions directly. :::note[Example] **Q:** "Tell me the fastest way to build something with BMad" @@ -86,51 +33,48 @@ https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt **A:** Use Quick Flow: Run `bmad-quick-dev` — it clarifies your intent, plans, implements, reviews, and presents results in a single workflow, skipping the full planning phases. ::: -## What You Get +**Tips for better answers:** -Direct answers about BMad—how agents work, what workflows do, why things are structured the way they are—without waiting for someone else to respond. - -## Tips - -- **Verify surprising answers** — LLMs occasionally get things wrong. Check the source file or ask on Discord. - **Be specific** — "What does step 3 of the PRD workflow do?" beats "How does PRD work?" +- **Verify surprising claims** — LLMs occasionally get things wrong. Check the source file or ask on Discord. -## Still Stuck? +### Not using an agent? Use the docs site -Tried the LLM approach and still need help? You now have a much better question to ask. +If your AI can't read local files (ChatGPT, Claude.ai, etc.), fetch [llms-full.txt](https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt) into your session — it's a single-file snapshot of the BMad documentation. -| Channel | Use For | -| ------------------------- | ------------------------------------------- | -| `#bmad-method-help` | Quick questions (real-time chat) | -| `help-requests` forum | Detailed questions (searchable, persistent) | -| `#suggestions-feedback` | Ideas and feature requests | -| `#report-bugs-and-issues` | Bug reports | +## 3. Ask Someone + +If neither BMad-Help nor the source answered your question, you now have a much better question to ask. + +| Channel | Use For | +| ----------------------- | -------------------------- | +| `help-requests` forum | Questions | +| `#suggestions-feedback` | Ideas and feature requests | **Discord:** [discord.gg/gk8jAdXWmj](https://discord.gg/gk8jAdXWmj) -**GitHub Issues:** [github.com/bmad-code-org/BMAD-METHOD/issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) (for clear bugs) +**GitHub Issues:** [github.com/bmad-code-org/BMAD-METHOD/issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) +_You!_ +_Stuck_ +_in the queue—_ +_waiting_ +_for who?_ -*You!* - *Stuck* - *in the queue—* - *waiting* - *for who?* +_The source_ +_is there,_ +_plain to see!_ -*The source* - *is there,* - *plain to see!* +_Point_ +_your machine._ +_Set it free._ -*Point* - *your machine.* - *Set it free.* +_It reads._ +_It speaks._ +_Ask away—_ -*It reads.* - *It speaks.* - *Ask away—* +_Why wait_ +_for tomorrow_ +_when you have_ +_today?_ -*Why wait* - *for tomorrow* - *when you have* - *today?* - -*—Claude* +_—Claude_ diff --git a/docs/how-to/install-bmad.md b/docs/how-to/install-bmad.md index 3789c6fa9..e0d276d51 100644 --- a/docs/how-to/install-bmad.md +++ b/docs/how-to/install-bmad.md @@ -1,5 +1,5 @@ --- -title: "How to Install BMad" +title: 'How to Install BMad' description: Step-by-step guide to installing BMad in your project sidebar: order: 1 @@ -16,10 +16,11 @@ If you want to use a non interactive installer and provide all install options o - Update the existing BMad Installation :::note[Prerequisites] + - **Node.js** 20+ (required for the installer) - **Git** (recommended) - **AI tool** (Claude Code, Cursor, or similar) -::: + ::: ## Steps @@ -31,6 +32,7 @@ npx bmad-method install :::tip[Want the newest prerelease build?] Use the `next` dist-tag: + ```bash npx bmad-method@next install ``` @@ -40,9 +42,11 @@ This gets you newer changes earlier, with a higher chance of churn than the defa :::tip[Bleeding edge] To install the latest from the main branch (may be unstable): + ```bash npx github:bmad-code-org/BMAD-METHOD install ``` + ::: ### 2. Choose Installation Location @@ -72,7 +76,7 @@ The installer shows available modules. Select whichever ones you need — most u ### 5. Follow the Prompts -The installer guides you through the rest — custom content, settings, etc. +The installer guides you through the rest — settings, tool integrations, etc. ## What You Get @@ -99,11 +103,13 @@ your-project/ Run `bmad-help` to verify everything works and see what to do next. **BMad-Help is your intelligent guide** that will: + - Confirm your installation is working - Show what's available based on your installed modules - Recommend your first step You can also ask it questions: + ``` bmad-help I just installed, what should I do first? bmad-help What are my options for a SaaS project? diff --git a/docs/how-to/install-custom-modules.md b/docs/how-to/install-custom-modules.md new file mode 100644 index 000000000..288415afa --- /dev/null +++ b/docs/how-to/install-custom-modules.md @@ -0,0 +1,180 @@ +--- +title: 'Install Custom and Community Modules' +description: Install third-party modules from the community registry, Git repositories, or local paths +sidebar: + order: 3 +--- + +Use the BMad installer to add modules from the community registry, third-party Git repositories, or local file paths. + +## When to Use This + +- Installing a community-contributed module from the BMad registry +- Installing a module from a third-party Git repository (GitHub, GitLab, Bitbucket, self-hosted) +- Testing a module you are developing locally with BMad Builder +- Installing modules from a private or self-hosted Git server + +:::note[Prerequisites] +Requires [Node.js](https://nodejs.org) v20+ and `npx` (included with npm). Custom and community modules can be selected during a fresh install or added to an existing installation. +::: + +## Community Modules + +Community modules are curated in the [BMad plugins marketplace](https://github.com/bmad-code-org/bmad-plugins-marketplace). They are organized by category and are pinned to an approved commit for safety. + +### 1. Run the Installer + +```bash +npx bmad-method install +``` + +### 2. Browse the Community Catalog + +After selecting official modules, the installer asks: + +``` +Would you like to browse community modules? +``` + +Select **Yes** to enter the catalog browser. You can: + +- Browse by category +- View featured modules +- View all available modules +- Search by keyword + +### 3. Select Modules + +Pick modules from any category. The installer shows descriptions, versions, and trust tiers. Already-installed modules are pre-checked for update. + +### 4. Continue with Installation + +After selecting community modules, the installer proceeds to custom sources, then tool/IDE configuration and the rest of the install flow. + +## Custom Sources (Git URLs and Local Paths) + +Custom modules can come from any Git repository or a local directory on your machine. The installer resolves the source, analyzes the module structure, and installs it alongside your other modules. + +### Interactive Installation + +During installation, after the community module step, the installer asks: + +``` +Would you like to install from a custom source (Git URL or local path)? +``` + +Select **Yes**, then provide a source: + +| Input Type | Example | +| --------------------- | ------------------------------------------------- | +| HTTPS URL (any host) | `https://github.com/org/repo` | +| HTTPS URL with subdir | `https://github.com/org/repo/tree/main/my-module` | +| SSH URL | `git@github.com:org/repo.git` | +| Local path | `/Users/me/projects/my-module` | +| Local path with tilde | `~/projects/my-module` | + +The installer clones the repository (for URLs) or reads directly from disk (for local paths), then presents the discovered modules for selection. + +### Non-Interactive Installation + +Use the `--custom-source` flag to install custom modules from the command line: + +```bash +npx bmad-method install \ + --directory . \ + --custom-source /path/to/my-module \ + --tools claude-code \ + --yes +``` + +When `--custom-source` is provided without `--modules`, only core and the custom modules are installed. To include official modules as well, add `--modules`: + +```bash +npx bmad-method install \ + --directory . \ + --modules bmm \ + --custom-source https://gitlab.com/myorg/my-module \ + --tools claude-code \ + --yes +``` + +Multiple sources can be comma-separated: + +```bash +--custom-source /path/one,https://github.com/org/repo,/path/two +``` + +## How Module Discovery Works + +The installer uses two modes to find installable modules in a source: + +| Mode | Trigger | Behavior | +| --------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| Discovery | Source contains `.claude-plugin/marketplace.json` | Lists all plugins from the manifest; you pick which to install | +| Direct | No marketplace.json found | Scans the directory for skills (subdirectories with `SKILL.md`), resolves as a single module | + +Discovery mode is typical for published modules. Direct mode is convenient when pointing at a skills directory during local development. + +:::note[About `.claude-plugin/`] +The `.claude-plugin/marketplace.json` path is a standard convention adopted across multiple AI tool installers for plugin discoverability. It does not require Claude, does not use Claude APIs, and has no effect on which AI tool you use. Any module with this file can be discovered by any installer that follows the convention. +::: + +## Local Development Workflow + +If you are building a module with [BMad Builder](https://github.com/bmad-code-org/bmad-builder), you can install it directly from your working directory: + +```bash +npx bmad-method install \ + --directory ~/my-project \ + --custom-source ~/my-module-repo/skills \ + --tools claude-code \ + --yes +``` + +Local sources are referenced by path, not copied to a cache. When you update your module source and reinstall, the installer picks up the latest changes. + +:::caution[Source Removal] +If you delete the local source directory after installation, the installed module files in `_bmad/` are preserved. The module will be skipped during updates until the source path is restored. +::: + +## What You Get + +After installation, custom modules appear in `_bmad/` alongside official modules: + +``` +your-project/ +├── _bmad/ +│ ├── core/ # Built-in core module +│ ├── bmm/ # Official module (if selected) +│ ├── my-module/ # Your custom module +│ │ ├── my-skill/ +│ │ │ └── SKILL.md +│ │ └── module-help.csv +│ └── _config/ +│ └── manifest.yaml # Tracks all modules, versions, and sources +└── ... +``` + +The manifest records the source of each custom module (`repoUrl` for Git sources, `localPath` for local sources) so that quick updates can locate the source again. + +## Updating Custom Modules + +Custom modules participate in the normal update flow: + +- **Quick update** (`--action quick-update`): Refreshes all modules from their original sources. Git-based modules are re-fetched; local modules are re-read from their source path. +- **Full update**: Re-runs module selection so you can add or remove custom modules. + +## Creating Your Own Modules + +Use [BMad Builder](https://github.com/bmad-code-org/bmad-builder) to create modules that others can install: + +1. Run `bmad-module-builder` to scaffold your module structure +2. Add skills, agents, and workflows with the various bmad builder tools +3. Publish to a Git repository or share the folder collection +4. Others install with `--custom-source ` + +For modules to support discovery mode, include a `.claude-plugin/marketplace.json` in your repository root (this is a cross-tool convention, not Claude-specific). See the [BMad Builder documentation](https://github.com/bmad-code-org/bmad-builder) for the marketplace.json format. + +:::tip[Testing Locally First] +During development, install your module with a local path to iterate quickly before publishing to a Git repository. +::: diff --git a/docs/how-to/non-interactive-installation.md b/docs/how-to/non-interactive-installation.md index eb72dfef4..817c9120a 100644 --- a/docs/how-to/non-interactive-installation.md +++ b/docs/how-to/non-interactive-installation.md @@ -22,40 +22,40 @@ Requires [Node.js](https://nodejs.org) v20+ and `npx` (included with npm). ### Installation Options -| Flag | Description | Example | -|------|-------------|---------| -| `--directory ` | Installation directory | `--directory ~/projects/myapp` | -| `--modules ` | Comma-separated module IDs | `--modules bmm,bmb` | -| `--tools ` | Comma-separated tool/IDE IDs (use `none` to skip) | `--tools claude-code,cursor` or `--tools none` | -| `--custom-content ` | Comma-separated paths to custom modules | `--custom-content ~/my-module,~/another-module` | -| `--action ` | Action for existing installations: `install` (default), `update`, or `quick-update` | `--action quick-update` | +| Flag | Description | Example | +| --------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------- | +| `--directory ` | Installation directory | `--directory ~/projects/myapp` | +| `--modules ` | Comma-separated module IDs | `--modules bmm,bmb` | +| `--tools ` | Comma-separated tool/IDE IDs (use `none` to skip) | `--tools claude-code,cursor` or `--tools none` | +| `--action ` | Action for existing installations: `install` (default), `update`, or `quick-update` | `--action quick-update` | +| `--custom-source ` | Comma-separated Git URLs or local paths for custom modules | `--custom-source /path/to/module` | ### Core Configuration -| Flag | Description | Default | -|------|-------------|---------| -| `--user-name ` | Name for agents to use | System username | -| `--communication-language ` | Agent communication language | English | -| `--document-output-language ` | Document output language | English | -| `--output-folder ` | Output folder path (see resolution rules below) | `_bmad-output` | +| Flag | Description | Default | +| ----------------------------------- | ----------------------------------------------- | --------------- | +| `--user-name ` | Name for agents to use | System username | +| `--communication-language ` | Agent communication language | English | +| `--document-output-language ` | Document output language | English | +| `--output-folder ` | Output folder path (see resolution rules below) | `_bmad-output` | #### Output Folder Path Resolution The value passed to `--output-folder` (or entered interactively) is resolved according to these rules: -| Input type | Example | Resolved as | -|------------|---------|-------------| -| Relative path (default) | `_bmad-output` | `/_bmad-output` | -| Relative path with traversal | `../../shared-outputs` | Normalized absolute path — e.g. `/Users/me/shared-outputs` | -| Absolute path | `/Users/me/shared-outputs` | Used as-is — project root is **not** prepended | +| Input type | Example | Resolved as | +| ---------------------------- | -------------------------- | ---------------------------------------------------------- | +| Relative path (default) | `_bmad-output` | `/_bmad-output` | +| Relative path with traversal | `../../shared-outputs` | Normalized absolute path — e.g. `/Users/me/shared-outputs` | +| Absolute path | `/Users/me/shared-outputs` | Used as-is — project root is **not** prepended | The resolved path is what agents and workflows use at runtime when writing output files. Using an absolute path or a traversal-based relative path lets you direct all generated artifacts to a directory outside your project tree — useful for shared or monorepo setups. ### Other Options -| Flag | Description | -|------|-------------| -| `-y, --yes` | Accept all defaults and skip prompts | +| Flag | Description | +| ------------- | ------------------------------------------- | +| `-y, --yes` | Accept all defaults and skip prompts | | `-d, --debug` | Enable debug output for manifest generation | ## Module IDs @@ -73,16 +73,17 @@ Available tool IDs for the `--tools` flag: **Preferred:** `claude-code`, `cursor` -Run `npx bmad-method install` interactively once to see the full current list of supported tools, or check the [platform codes configuration](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/cli/installers/lib/ide/platform-codes.yaml). +Run `npx bmad-method install` interactively once to see the full current list of supported tools, or check the [platform codes configuration](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/installer/ide/platform-codes.yaml). ## Installation Modes -| Mode | Description | Example | -|------|-------------|---------| -| Fully non-interactive | Provide all flags to skip all prompts | `npx bmad-method install --directory . --modules bmm --tools claude-code --yes` | -| Semi-interactive | Provide some flags; BMad prompts for the rest | `npx bmad-method install --directory . --modules bmm` | -| Defaults only | Accept all defaults with `-y` | `npx bmad-method install --yes` | -| Without tools | Skip tool/IDE configuration | `npx bmad-method install --modules bmm --tools none` | +| Mode | Description | Example | +| --------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| Fully non-interactive | Provide all flags to skip all prompts | `npx bmad-method install --directory . --modules bmm --tools claude-code --yes` | +| Semi-interactive | Provide some flags; BMad prompts for the rest | `npx bmad-method install --directory . --modules bmm` | +| Defaults only | Accept all defaults with `-y` | `npx bmad-method install --yes` | +| Custom source only | Install core + custom module(s) | `npx bmad-method install --directory . --custom-source /path/to/module --tools claude-code --yes` | +| Without tools | Skip tool/IDE configuration | `npx bmad-method install --modules bmm --tools none` | ## Examples @@ -120,16 +121,33 @@ npx bmad-method install \ --action quick-update ``` -### Installation with Custom Content +### Install from Custom Source + +Install a module from a local path or any Git host: ```bash npx bmad-method install \ - --directory ~/projects/myapp \ - --modules bmm \ - --custom-content ~/my-custom-module,~/another-module \ - --tools claude-code + --directory . \ + --custom-source /path/to/my-module \ + --tools claude-code \ + --yes ``` +Combine with official modules: + +```bash +npx bmad-method install \ + --directory . \ + --modules bmm \ + --custom-source https://gitlab.com/myorg/my-module \ + --tools claude-code \ + --yes +``` + +:::note[Custom source behavior] +When `--custom-source` is used without `--modules`, only core and the custom modules are installed. Add `--modules` to include official modules as well. See [Install Custom and Community Modules](./install-custom-modules.md) for details. +::: + ## What You Get - A fully configured `_bmad/` directory in your project @@ -143,21 +161,22 @@ BMad validates all provided flags: - **Directory** — Must be a valid path with write permissions - **Modules** — Warns about invalid module IDs (but won't fail) - **Tools** — Warns about invalid tool IDs (but won't fail) -- **Custom Content** — Each path must contain a valid `module.yaml` file - **Action** — Must be one of: `install`, `update`, `quick-update` Invalid values will either: + 1. Show an error and exit (for critical options like directory) -2. Show a warning and skip (for optional items like custom content) +2. Show a warning and skip (for optional items) 3. Fall back to interactive prompts (for missing required values) :::tip[Best Practices] + - Use absolute paths for `--directory` to avoid ambiguity - Use an absolute path for `--output-folder` when you want artifacts written outside the project tree (e.g. a shared monorepo outputs directory) - Test flags locally before using in CI/CD pipelines - Combine with `-y` for truly unattended installations - Use `--debug` if you encounter issues during installation -::: + ::: ## Troubleshooting @@ -172,13 +191,6 @@ Invalid values will either: - Verify the module ID is correct - External modules must be available in the registry -### Custom content path invalid - -Ensure each custom content path: -- Points to a directory -- Contains a `module.yaml` file in the root -- Has a `code` field in the `module.yaml` - :::note[Still stuck?] Run with `--debug` for detailed output, try interactive mode to isolate the issue, or report at . ::: diff --git a/docs/how-to/project-context.md b/docs/how-to/project-context.md index 7cb3b3b04..51e59ac3f 100644 --- a/docs/how-to/project-context.md +++ b/docs/how-to/project-context.md @@ -1,16 +1,17 @@ --- -title: "Manage Project Context" +title: 'Manage Project Context' description: Create and maintain project-context.md to guide AI agents sidebar: - order: 8 + order: 9 --- Use the `project-context.md` file to ensure AI agents follow your project's technical preferences and implementation rules throughout all workflows. To make sure this is always available, you can also add the line `Important project context and conventions are located in [path to project context]/project-context.md` to your tools context or always rules file (such as `AGENTS.md`) :::note[Prerequisites] + - BMad Method installed - Understanding of your project's technology stack and conventions -::: + ::: ## When to Use This @@ -60,14 +61,17 @@ sections_completed: ['technology_stack', 'critical_rules'] ## Critical Implementation Rules **TypeScript:** + - Strict mode enabled, no `any` types - Use `interface` for public APIs, `type` for unions **Code Organization:** + - Components in `/src/components/` with co-located tests - API calls use `apiClient` singleton — never fetch directly **Testing:** + - Unit tests focus on business logic - Integration tests use MSW for API mocking ``` @@ -115,11 +119,12 @@ A `project-context.md` file that: ## Tips :::tip[Best Practices] + - **Focus on the unobvious** — Document patterns agents might miss (e.g., "Use JSDoc on every public class"), not universal practices like "use meaningful variable names." - **Keep it lean** — This file is loaded by every implementation workflow. Long files waste context. Exclude content that only applies to narrow scope or specific stories. - **Update as needed** — Edit manually when patterns change, or re-generate after significant architecture changes. - Works for Quick Flow and full BMad Method projects alike. -::: + ::: ## Next Steps diff --git a/docs/how-to/quick-fixes.md b/docs/how-to/quick-fixes.md index 3b695a52d..f6ca5369d 100644 --- a/docs/how-to/quick-fixes.md +++ b/docs/how-to/quick-fixes.md @@ -1,8 +1,8 @@ --- -title: "Quick Fixes" +title: 'Quick Fixes' description: How to make quick fixes and ad-hoc changes sidebar: - order: 5 + order: 6 --- Use **Quick Dev** for bug fixes, refactorings, or small targeted changes that don't require the full BMad Method. @@ -15,9 +15,10 @@ Use **Quick Dev** for bug fixes, refactorings, or small targeted changes that do - Dependency updates :::note[Prerequisites] + - BMad Method installed (`npx bmad-method install`) - An AI-powered IDE (Claude Code, Cursor, or similar) -::: + ::: ## Steps diff --git a/docs/how-to/shard-large-documents.md b/docs/how-to/shard-large-documents.md index 68cbbfc6b..8b8719f2b 100644 --- a/docs/how-to/shard-large-documents.md +++ b/docs/how-to/shard-large-documents.md @@ -1,8 +1,8 @@ --- -title: "Document Sharding Guide" +title: 'Document Sharding Guide' description: Split large markdown files into smaller organized files for better context management sidebar: - order: 9 + order: 10 --- Use the `bmad-shard-doc` tool if you need to split large markdown files into smaller, organized files for better context management. diff --git a/docs/how-to/upgrade-to-v6.md b/docs/how-to/upgrade-to-v6.md index e01d95f00..567dbe93c 100644 --- a/docs/how-to/upgrade-to-v6.md +++ b/docs/how-to/upgrade-to-v6.md @@ -1,8 +1,8 @@ --- -title: "How to Upgrade to v6" +title: 'How to Upgrade to v6' description: Migrate from BMad v4 to v6 sidebar: - order: 3 + order: 4 --- Use the BMad installer to upgrade from v4 to v6, which includes automatic detection of legacy installations and migration assistance. @@ -14,9 +14,10 @@ Use the BMad installer to upgrade from v4 to v6, which includes automatic detect - You have existing planning artifacts to preserve :::note[Prerequisites] + - Node.js 20+ - Existing BMad v4 installation -::: + ::: ## Steps @@ -61,8 +62,8 @@ If you have stories created or implemented: 1. Complete the v6 installation 2. Place `epics.md` or `epics/epic*.md` in `_bmad-output/planning-artifacts/` -3. Run the Scrum Master's `bmad-sprint-planning` workflow -4. Tell the SM which epics/stories are already complete +3. Run the Developer's `bmad-sprint-planning` workflow +4. Tell the agent which epics/stories are already complete ## What You Get diff --git a/docs/reference/agents.md b/docs/reference/agents.md index 764c52532..4e05cde1b 100644 --- a/docs/reference/agents.md +++ b/docs/reference/agents.md @@ -13,17 +13,14 @@ This page lists the default BMM (Agile suite) agents that install with BMad Meth - Each agent is available as a skill, generated by the installer. The skill ID (e.g., `bmad-dev`) is used to invoke the agent. - Triggers are the short menu codes (e.g., `CP`) and fuzzy matches shown in each agent menu. -- QA (Quinn) is the lightweight test automation agent in BMM. The full Test Architect (TEA) lives in its own module. +- QA test generation is handled by the `bmad-qa-generate-e2e-tests` workflow skill, available through the Developer agent. The full Test Architect (TEA) lives in its own module. | Agent | Skill ID | Triggers | Primary workflows | | --------------------------- | -------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------- | -| Analyst (Mary) | `bmad-analyst` | `BP`, `RS`, `CB`, `DP` | Brainstorm Project, Research, Create Brief, Document Project | +| Analyst (Mary) | `bmad-analyst` | `BP`, `MR`, `DR`, `TR`, `CB`, `WB`, `DP` | Brainstorm, Market Research, Domain Research, Technical Research, Create Brief, PRFAQ Challenge, Document Project | | Product Manager (John) | `bmad-pm` | `CP`, `VP`, `EP`, `CE`, `IR`, `CC` | Create/Validate/Edit PRD, Create Epics and Stories, Implementation Readiness, Correct Course | | Architect (Winston) | `bmad-architect` | `CA`, `IR` | Create Architecture, Implementation Readiness | -| Scrum Master (Bob) | `bmad-sm` | `SP`, `CS`, `ER`, `CC` | Sprint Planning, Create Story, Epic Retrospective, Correct Course | -| Developer (Amelia) | `bmad-dev` | `DS`, `CR` | Dev Story, Code Review | -| QA Engineer (Quinn) | `bmad-qa` | `QA` | Automate (generate tests for existing features) | -| Quick Flow Solo Dev (Barry) | `bmad-master` | `QD`, `CR` | Quick Dev, Code Review | +| Developer (Amelia) | `bmad-agent-dev` | `DS`, `QD`, `QA`, `CR`, `SP`, `CS`, `ER` | Dev Story, Quick Dev, QA Test Generation, Code Review, Sprint Planning, Create Story, Epic Retrospective | | UX Designer (Sally) | `bmad-ux-designer` | `CU` | Create UX Design | | Technical Writer (Paige) | `bmad-tech-writer` | `DP`, `WD`, `US`, `MG`, `VD`, `EC` | Document Project, Write Document, Update Standards, Mermaid Generate, Validate Doc, Explain Concept | diff --git a/docs/reference/commands.md b/docs/reference/commands.md index e070c864e..7776f94b6 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -54,12 +54,12 @@ Each skill is a directory containing a `SKILL.md` file. For example, a Claude Co │ └── SKILL.md ├── bmad-create-prd/ │ └── SKILL.md -├── bmad-dev/ +├── bmad-agent-dev/ │ └── SKILL.md └── ... ``` -The directory name determines the skill name in your IDE. For example, the directory `bmad-dev/` registers the skill `bmad-dev`. +The directory name determines the skill name in your IDE. For example, the directory `bmad-agent-dev/` registers the skill `bmad-agent-dev`. ## How to Discover Your Skills @@ -79,10 +79,9 @@ Agent skills load a specialized AI persona with a defined role, communication st | Example skill | Agent | Role | | --- | --- | --- | -| `bmad-dev` | Amelia (Developer) | Implements stories with strict adherence to specs | +| `bmad-agent-dev` | Amelia (Developer) | Implements stories with strict adherence to specs | | `bmad-pm` | John (Product Manager) | Creates and validates PRDs | | `bmad-architect` | Winston (Architect) | Designs system architecture | -| `bmad-sm` | Bob (Scrum Master) | Manages sprints and stories | See [Agents](./agents.md) for the full list of default agents and their triggers. @@ -92,6 +91,8 @@ Workflow skills run a structured, multi-step process without loading an agent pe | Example skill | Purpose | | --- | --- | +| `bmad-product-brief` | Create a product brief — guided discovery when your concept is clear | +| `bmad-prfaq` | [Working Backwards PRFAQ](../explanation/analysis-phase.md#prfaq-working-backwards) challenge to stress-test your product concept | | `bmad-create-prd` | Create a Product Requirements Document | | `bmad-create-architecture` | Design system architecture | | `bmad-create-epics-and-stories` | Create epics and stories | @@ -123,7 +124,7 @@ The core module includes 11 built-in tools — reviews, compression, brainstormi ## Naming Convention -All skills use the `bmad-` prefix followed by a descriptive name (e.g., `bmad-dev`, `bmad-create-prd`, `bmad-help`). See [Modules](./modules.md) for available modules. +All skills use the `bmad-` prefix followed by a descriptive name (e.g., `bmad-agent-dev`, `bmad-create-prd`, `bmad-help`). See [Modules](./modules.md) for available modules. ## Troubleshooting diff --git a/docs/reference/testing.md b/docs/reference/testing.md index f7832c2e6..d605e4932 100644 --- a/docs/reference/testing.md +++ b/docs/reference/testing.md @@ -1,15 +1,15 @@ --- title: Testing Options -description: Comparing the built-in QA agent (Quinn) with the Test Architect (TEA) module for test automation. +description: Comparing the built-in QA workflow with the Test Architect (TEA) module for test automation. sidebar: order: 5 --- -BMad provides two testing paths: a built-in QA agent for fast test generation and an installable Test Architect module for enterprise-grade test strategy. +BMad provides two testing paths: a built-in QA workflow for fast test generation and an installable Test Architect module for enterprise-grade test strategy. ## Which Should You Use? -| Factor | Quinn (Built-in QA) | TEA Module | +| Factor | Built-in QA | TEA Module | | --- | --- | --- | | **Best for** | Small-medium projects, quick coverage | Large projects, regulated or complex domains | | **Setup** | Nothing to install -- included in BMM | Install separately via `npx bmad-method install` | @@ -18,19 +18,19 @@ BMad provides two testing paths: a built-in QA agent for fast test generation an | **Strategy** | Happy path + critical edge cases | Risk-based prioritization (P0-P3) | | **Workflow count** | 1 (Automate) | 9 (design, ATDD, automate, review, trace, and others) | -:::tip[Start with Quinn] -Most projects should start with Quinn. If you later need test strategy, quality gates, or requirements traceability, install TEA alongside it. +:::tip[Start with built-in QA] +Most projects should start with the built-in QA workflow. If you later need test strategy, quality gates, or requirements traceability, install TEA alongside it. ::: -## Built-in QA Agent (Quinn) +## Built-in QA Workflow -Quinn is the built-in QA agent in the BMM (Agile suite) module. It generates working tests quickly using your project's existing test framework -- no configuration or additional installation required. +The built-in QA workflow (`bmad-qa-generate-e2e-tests`) is part of the BMM (Agile suite) module, available through the Developer agent. It generates working tests quickly using your project's existing test framework -- no configuration or additional installation required. -**Trigger:** `QA` or `bmad-qa-generate-e2e-tests` +**Trigger:** `QA` (via the Developer agent) or `bmad-qa-generate-e2e-tests` -### What Quinn Does +### What It Does -Quinn runs a single workflow (Automate) that walks through five steps: +The QA workflow (Automate) walks through five steps: 1. **Detect test framework** -- scans `package.json` and existing test files for your framework (Jest, Vitest, Playwright, Cypress, or any standard runner). If none exists, analyzes the project stack and suggests one. 2. **Identify features** -- asks what to test or auto-discovers features in the codebase. @@ -38,7 +38,7 @@ Quinn runs a single workflow (Automate) that walks through five steps: 4. **Generate E2E tests** -- covers user workflows with semantic locators and visible-outcome assertions. 5. **Run and verify** -- executes the generated tests and fixes failures immediately. -Quinn produces a test summary saved to your project's implementation artifacts folder. +The workflow produces a test summary saved to your project's implementation artifacts folder. ### Test Patterns @@ -51,10 +51,10 @@ Generated tests follow a "simple and maintainable" philosophy: - **Clear descriptions** that read as feature documentation :::note[Scope] -Quinn generates tests only. For code review and story validation, use the Code Review workflow (`CR`) instead. +The QA workflow generates tests only. For code review and story validation, use the Code Review workflow (`CR`) instead. ::: -### When to Use Quinn +### When to Use Built-in QA - Quick test coverage for a new or existing feature - Beginner-friendly test automation without advanced setup @@ -91,16 +91,16 @@ TEA also supports P0-P3 risk-based prioritization and optional integrations with - Teams that need risk-based test prioritization across many features - Enterprise environments with formal quality gates before release - Complex domains where test strategy must be planned before tests are written -- Projects that have outgrown Quinn's single-workflow approach +- Projects that have outgrown the built-in QA's single-workflow approach ## How Testing Fits into Workflows -Quinn's Automate workflow appears in Phase 4 (Implementation) of the BMad Method workflow map. It is designed to run **after a full epic is complete** — once all stories in an epic have been implemented and code-reviewed. A typical sequence: +The QA Automate workflow appears in Phase 4 (Implementation) of the BMad Method workflow map. It is designed to run **after a full epic is complete** — once all stories in an epic have been implemented and code-reviewed. A typical sequence: 1. For each story in the epic: implement with Dev (`DS`), then validate with Code Review (`CR`) -2. After the epic is complete: generate tests with Quinn (`QA`) or TEA's Automate workflow +2. After the epic is complete: generate tests with `QA` (via the Developer agent) or TEA's Automate workflow 3. Run retrospective (`bmad-retrospective`) to capture lessons learned -Quinn works directly from source code without loading planning documents (PRD, architecture). TEA workflows can integrate with upstream planning artifacts for traceability. +The built-in QA workflow works directly from source code without loading planning documents (PRD, architecture). TEA workflows can integrate with upstream planning artifacts for traceability. For more on where testing fits in the overall process, see the [Workflow Map](./workflow-map.md). diff --git a/docs/reference/workflow-map.md b/docs/reference/workflow-map.md index 9f5e7e7ed..0c088fa8b 100644 --- a/docs/reference/workflow-map.md +++ b/docs/reference/workflow-map.md @@ -21,13 +21,14 @@ Final important note: Every workflow below can be run directly with your tool of ## Phase 1: Analysis (Optional) -Explore the problem space and validate ideas before committing to planning. +Explore the problem space and validate ideas before committing to planning. [**Learn what each tool does and when to use it**](../explanation/analysis-phase.md). | Workflow | Purpose | Produces | | ------------------------------- | -------------------------------------------------------------------------- | ------------------------- | | `bmad-brainstorming` | Brainstorm Project Ideas with guided facilitation of a brainstorming coach | `brainstorming-report.md` | | `bmad-domain-research`, `bmad-market-research`, `bmad-technical-research` | Validate market, technical, or domain assumptions | Research findings | -| `bmad-create-product-brief` | Capture strategic vision | `product-brief.md` | +| `bmad-product-brief` | Capture strategic vision — best when your concept is clear | `product-brief.md` | +| `bmad-prfaq` | Working Backwards — stress-test and forge your product concept | `prfaq-{project}.md` | ## Phase 2: Planning diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index d6d1f08dd..94aaa521a 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -68,7 +68,7 @@ BMad helps you build software through guided workflows with specialized AI agent | Phase | Name | What Happens | | ----- | -------------- | --------------------------------------------------- | -| 1 | Analysis | Brainstorming, research, product brief *(optional)* | +| 1 | Analysis | Brainstorming, research, product brief or PRFAQ *(optional)* | | 2 | Planning | Create requirements (PRD or spec) | | 3 | Solutioning | Design architecture *(BMad Method/Enterprise only)* | | 4 | Implementation | Build epic by epic, story by story | @@ -133,10 +133,11 @@ Create it manually at `_bmad-output/project-context.md` or generate it after arc ### Phase 1: Analysis (Optional) -All workflows in this phase are optional: +All workflows in this phase are optional. [**Not sure which to use?**](../explanation/analysis-phase.md) - **brainstorming** (`bmad-brainstorming`) — Guided ideation - **research** (`bmad-market-research` / `bmad-domain-research` / `bmad-technical-research`) — Market, domain, and technical research -- **create-product-brief** (`bmad-create-product-brief`) — Recommended foundation document +- **product-brief** (`bmad-product-brief`) — Recommended foundation document when your concept is clear +- **prfaq** (`bmad-prfaq`) — Working Backwards challenge to stress-test and forge your product concept ### Phase 2: Planning (Required) @@ -180,7 +181,7 @@ Once planning is complete, move to implementation. **Each workflow should run in ### Initialize Sprint Planning -Invoke the **SM agent** (`bmad-agent-sm`) and run `bmad-sprint-planning` (`bmad-sprint-planning`). This creates `sprint-status.yaml` to track all epics and stories. +Invoke the **Developer agent** (`bmad-agent-dev`) and run `bmad-sprint-planning` (`bmad-sprint-planning`). This creates `sprint-status.yaml` to track all epics and stories. ### The Build Cycle @@ -188,11 +189,11 @@ For each story, repeat this cycle with fresh chats: | Step | Agent | Workflow | Command | Purpose | | ---- | ----- | -------------- | -------------------------- | ---------------------------------- | -| 1 | SM | `bmad-create-story` | `bmad-create-story` | Create story file from epic | +| 1 | DEV | `bmad-create-story` | `bmad-create-story` | Create story file from epic | | 2 | DEV | `bmad-dev-story` | `bmad-dev-story` | Implement the story | | 3 | DEV | `bmad-code-review` | `bmad-code-review` | Quality validation *(recommended)* | -After completing all stories in an epic, invoke the **SM agent** (`bmad-agent-sm`) and run `bmad-retrospective` (`bmad-retrospective`). +After completing all stories in an epic, invoke the **Developer agent** (`bmad-agent-dev`) and run `bmad-retrospective` (`bmad-retrospective`). ## What You've Accomplished @@ -229,8 +230,8 @@ your-project/ | `bmad-generate-project-context` | `bmad-generate-project-context` | Analyst | Create project context file | | `bmad-create-epics-and-stories` | `bmad-create-epics-and-stories` | PM | Break down PRD into epics | | `bmad-check-implementation-readiness` | `bmad-check-implementation-readiness` | Architect | Validate planning cohesion | -| `bmad-sprint-planning` | `bmad-sprint-planning` | SM | Initialize sprint tracking | -| `bmad-create-story` | `bmad-create-story` | SM | Create a story file | +| `bmad-sprint-planning` | `bmad-sprint-planning` | DEV | Initialize sprint tracking | +| `bmad-create-story` | `bmad-create-story` | DEV | Create a story file | | `bmad-dev-story` | `bmad-dev-story` | DEV | Implement a story | | `bmad-code-review` | `bmad-code-review` | DEV | Review implemented code | @@ -240,7 +241,7 @@ your-project/ Only for BMad Method and Enterprise tracks. Quick Flow skips from spec to implementation. **Can I change my plan later?** -Yes. The SM agent has a `bmad-correct-course` workflow (`bmad-correct-course`) for handling scope changes. +Yes. The `bmad-correct-course` workflow handles scope changes mid-implementation. **What if I want to brainstorm first?** Invoke the Analyst agent (`bmad-agent-analyst`) and run `bmad-brainstorming` (`bmad-brainstorming`) before starting your PRD. diff --git a/docs/vi-vn/404.md b/docs/vi-vn/404.md new file mode 100644 index 000000000..e51d5668b --- /dev/null +++ b/docs/vi-vn/404.md @@ -0,0 +1,8 @@ +--- +title: Không Tìm Thấy Trang +template: splash +--- + +Trang bạn đang tìm không tồn tại hoặc đã được chuyển đi. + +[Quay về trang chủ](./index.md) diff --git a/docs/vi-vn/_STYLE_GUIDE.md b/docs/vi-vn/_STYLE_GUIDE.md new file mode 100644 index 000000000..4cad7fda4 --- /dev/null +++ b/docs/vi-vn/_STYLE_GUIDE.md @@ -0,0 +1,370 @@ +--- +title: "Hướng Dẫn Phong Cách Tài Liệu" +description: Các quy ước tài liệu dành riêng cho dự án, dựa trên phong cách tài liệu của Google và cấu trúc Diataxis +--- + +Dự án này tuân theo [Google Developer Documentation Style Guide](https://developers.google.com/style) và dùng [Diataxis](https://diataxis.fr/) để tổ chức nội dung. Phần dưới đây chỉ nêu các quy ước dành riêng cho dự án. + +## Quy tắc riêng của dự án + +| Quy tắc | Quy định | +| --- | --- | +| Không dùng đường kẻ ngang (`---`) | Làm gián đoạn dòng đọc | +| Không dùng tiêu đề `####` | Dùng chữ in đậm hoặc admonition thay thế | +| Không có mục "Related" hoặc "Next:" | Sidebar đã xử lý điều hướng | +| Không dùng danh sách lồng quá sâu | Tách thành các mục riêng | +| Không dùng code block cho nội dung không phải code | Dùng admonition cho ví dụ hội thoại | +| Không dùng cả đoạn in đậm để làm callout | Dùng admonition thay thế | +| Mỗi mục tối đa 1-2 admonition | Tutorial có thể dùng 3-4 admonition cho mỗi phần lớn | +| Ô bảng / mục danh sách | Tối đa 1-2 câu | +| Ngân sách tiêu đề | 8-12 `##` cho mỗi tài liệu; 2-3 `###` cho mỗi phần | + +## Admonition (cú pháp Starlight) + +```md +:::tip[Tiêu đề] +Lối tắt, best practice +::: + +:::note[Tiêu đề] +Ngữ cảnh, định nghĩa, ví dụ, điều kiện tiên quyết +::: + +:::caution[Tiêu đề] +Lưu ý, vấn đề có thể xảy ra +::: + +:::danger[Tiêu đề] +Chỉ dùng cho cảnh báo nghiêm trọng — mất dữ liệu, vấn đề bảo mật +::: +``` + +### Cách dùng chuẩn + +| Admonition | Dùng cho | +| --- | --- | +| `:::note[Điều kiện tiên quyết]` | Các phụ thuộc trước khi bắt đầu | +| `:::tip[Lối đi nhanh]` | Tóm tắt TL;DR ở đầu tài liệu | +| `:::caution[Quan trọng]` | Cảnh báo quan trọng | +| `:::note[Ví dụ]` | Ví dụ lệnh / phản hồi | + +## Mẫu bảng chuẩn + +**Phase:** + +```md +| Phase | Tên | Điều xảy ra | +| ----- | --- | ------------ | +| 1 | Analysis | Brainstorm, nghiên cứu *(tùy chọn)* | +| 2 | Planning | Yêu cầu — PRD hoặc spec *(bắt buộc)* | +``` + +**Skill:** + +```md +| Skill | Agent | Mục đích | +| ----- | ----- | -------- | +| `bmad-brainstorming` | Analyst | Brainstorm cho dự án mới | +| `bmad-create-prd` | PM | Tạo tài liệu yêu cầu sản phẩm | +``` + +## Khối cấu trúc thư mục + +Hiển thị trong phần "Bạn đã hoàn thành những gì": + +````md +``` +your-project/ +├── _bmad/ # Cấu hình BMad +├── _bmad-output/ +│ ├── planning-artifacts/ +│ │ └── PRD.md # Tài liệu yêu cầu của bạn +│ ├── implementation-artifacts/ +│ └── project-context.md # Quy tắc triển khai (tùy chọn) +└── ... +``` +```` + +## Cấu trúc Tutorial + +```text +1. Tiêu đề + Hook (1-2 câu mô tả kết quả) +2. Thông báo phiên bản/module (admonition info hoặc warning) (tùy chọn) +3. Bạn sẽ học được gì (danh sách kết quả) +4. Điều kiện tiên quyết (admonition info) +5. Lối đi nhanh (admonition tip - tóm tắt TL;DR) +6. Hiểu về [Chủ đề] (ngữ cảnh trước các bước - bảng cho phase/agent) +7. Cài đặt (tùy chọn) +8. Bước 1: [Nhiệm vụ lớn đầu tiên] +9. Bước 2: [Nhiệm vụ lớn thứ hai] +10. Bước 3: [Nhiệm vụ lớn thứ ba] +11. Bạn đã hoàn thành những gì (tóm tắt + cấu trúc thư mục) +12. Tra cứu nhanh (bảng skill) +13. Câu hỏi thường gặp (định dạng FAQ) +14. Nhận hỗ trợ (liên kết cộng đồng) +15. Điểm chính cần nhớ (admonition tip) +``` + +### Checklist cho Tutorial + +- [ ] Hook mô tả kết quả trong 1-2 câu +- [ ] Có phần "Bạn sẽ học được gì" +- [ ] Điều kiện tiên quyết nằm trong admonition +- [ ] Có admonition TL;DR ở đầu trang +- [ ] Có bảng cho phase, skill, agent +- [ ] Có phần "Bạn đã hoàn thành những gì" +- [ ] Có bảng tra cứu nhanh +- [ ] Có phần câu hỏi thường gặp +- [ ] Có phần nhận hỗ trợ +- [ ] Có admonition điểm chính ở cuối + +## Cấu trúc How-To + +```text +1. Tiêu đề + Hook (một câu: "Sử dụng workflow `X` để...") +2. Khi nào nên dùng (danh sách kịch bản) +3. Khi nào nên bỏ qua (tùy chọn) +4. Điều kiện tiên quyết (admonition note) +5. Các bước (mục con `###` có đánh số) +6. Bạn sẽ nhận được gì (output / artifact) +7. Ví dụ (tùy chọn) +8. Mẹo (tùy chọn) +9. Bước tiếp theo (tùy chọn) +``` + +### Checklist cho How-To + +- [ ] Hook bắt đầu bằng "Sử dụng workflow `X` để..." +- [ ] Phần "Khi nào nên dùng" có 3-5 gạch đầu dòng +- [ ] Có liệt kê điều kiện tiên quyết +- [ ] Các bước là mục `###` có đánh số và bắt đầu bằng động từ +- [ ] Phần "Bạn sẽ nhận được gì" mô tả artifact đầu ra + +## Cấu trúc Explanation + +### Các loại + +| Loại | Ví dụ | +| --- | --- | +| **Trang chỉ mục / landing** | `core-concepts/index.md` | +| **Khái niệm** | `what-are-agents.md` | +| **Tính năng** | `quick-dev.md` | +| **Triết lý** | `why-solutioning-matters.md` | +| **FAQ** | `established-projects-faq.md` | + +### Mẫu tổng quát + +```text +1. Tiêu đề + Hook (1-2 câu) +2. Tổng quan / định nghĩa (nó là gì, vì sao quan trọng) +3. Khái niệm chính (các mục `###`) +4. Bảng so sánh (tùy chọn) +5. Khi nào nên dùng / không nên dùng (tùy chọn) +6. Sơ đồ (tùy chọn - mermaid, tối đa 1 sơ đồ mỗi tài liệu) +7. Bước tiếp theo (tùy chọn) +``` + +### Trang chỉ mục / landing + +```text +1. Tiêu đề + Hook (một câu) +2. Bảng nội dung (liên kết kèm mô tả) +3. Bắt đầu từ đâu (danh sách có đánh số) +4. Chọn hướng đi của bạn (tùy chọn - cây quyết định) +``` + +### Trang giải thích khái niệm + +```text +1. Tiêu đề + Hook (nó là gì) +2. Loại / nhóm (các mục `###`) (tùy chọn) +3. Bảng khác biệt chính +4. Thành phần / bộ phận +5. Nên chọn cái nào? +6. Cách tạo / tùy chỉnh (trỏ sang how-to) +``` + +### Trang giải thích tính năng + +```text +1. Tiêu đề + Hook (nó làm gì) +2. Thông tin nhanh (tùy chọn - "Phù hợp với:", "Mất bao lâu:") +3. Khi nào nên dùng / không nên dùng +4. Cách nó hoạt động (mermaid tùy chọn) +5. Lợi ích chính +6. Bảng so sánh (tùy chọn) +7. Khi nào nên nâng cấp / chuyển hướng (tùy chọn) +``` + +### Tài liệu về triết lý / lý do + +```text +1. Tiêu đề + Hook (nguyên tắc) +2. Vấn đề +3. Giải pháp +4. Nguyên tắc chính (các mục `###`) +5. Lợi ích +6. Khi nào áp dụng +``` + +### Checklist cho Explanation + +- [ ] Hook nêu rõ tài liệu giải thích điều gì +- [ ] Nội dung được chia thành các phần `##` dễ quét +- [ ] Có bảng so sánh khi có từ 3 lựa chọn trở lên +- [ ] Sơ đồ có nhãn rõ ràng +- [ ] Có liên kết sang how-to cho câu hỏi mang tính thủ tục +- [ ] Mỗi tài liệu tối đa 2-3 admonition + +## Cấu trúc Reference + +### Các loại + +| Loại | Ví dụ | +| --- | --- | +| **Trang chỉ mục / landing** | `workflows/index.md` | +| **Danh mục** | `agents/index.md` | +| **Đào sâu** | `document-project.md` | +| **Cấu hình** | `core-tasks.md` | +| **Bảng thuật ngữ** | `glossary/index.md` | +| **Tổng hợp đầy đủ** | `bmgd-workflows.md` | + +### Trang chỉ mục của Reference + +```text +1. Tiêu đề + Hook (một câu) +2. Các phần nội dung (`##` cho từng nhóm) + - Danh sách gạch đầu dòng với liên kết và mô tả +``` + +### Reference dạng danh mục + +```text +1. Tiêu đề + Hook +2. Các mục (`##` cho từng mục) + - Mô tả ngắn (một câu) + - **Skills:** hoặc **Thông tin chính:** ở dạng danh sách phẳng +3. Phần dùng chung / toàn cục (`##`) (tùy chọn) +``` + +### Reference đào sâu theo mục + +```text +1. Tiêu đề + Hook (một câu nêu mục đích) +2. Thông tin nhanh (admonition note, tùy chọn) + - Module, Skill, Input, Output dưới dạng danh sách +3. Mục đích / tổng quan (`##`) +4. Cách gọi (code block) +5. Các phần chính (`##` cho từng khía cạnh) + - Dùng `###` cho các tùy chọn con +6. Ghi chú / lưu ý (admonition tip hoặc caution) +``` + +### Reference về cấu hình + +```text +1. Tiêu đề + Hook +2. Mục lục (jump link nếu có từ 4 mục trở lên) +3. Các mục (`##` cho từng config / task) + - **Tóm tắt in đậm** — một câu + - **Dùng khi:** danh sách gạch đầu dòng + - **Cách hoạt động:** các bước đánh số (tối đa 3-5 bước) + - **Output:** kết quả mong đợi (tùy chọn) +``` + +### Hướng dẫn reference tổng hợp + +```text +1. Tiêu đề + Hook +2. Tổng quan (`##`) + - Sơ đồ hoặc bảng mô tả cách tổ chức +3. Các phần lớn (`##` cho từng phase / nhóm) + - Các mục (`###` cho từng mục) + - Các trường chuẩn hóa: Skill, Agent, Input, Output, Description +4. Bước tiếp theo (tùy chọn) +``` + +### Checklist cho Reference + +- [ ] Hook nêu rõ tài liệu đang tham chiếu điều gì +- [ ] Cấu trúc phù hợp với loại reference +- [ ] Các mục dùng cấu trúc nhất quán xuyên suốt +- [ ] Có bảng cho dữ liệu có cấu trúc / so sánh +- [ ] Có liên kết sang tài liệu explanation cho chiều sâu khái niệm +- [ ] Tối đa 1-2 admonition + +## Cấu trúc Glossary + +Starlight tạo phần điều hướng "On this page" từ các tiêu đề: + +- Dùng `##` cho các nhóm — sẽ hiện ở thanh điều hướng bên phải +- Đặt thuật ngữ trong bảng — gọn hơn so với tạo tiêu đề riêng cho từng thuật ngữ +- Không chèn TOC nội tuyến — sidebar bên phải đã xử lý điều hướng + +### Định dạng bảng + +```md +## Tên nhóm + +| Thuật ngữ | Định nghĩa | +| --------- | ---------- | +| **Agent** | AI persona chuyên biệt với chuyên môn cụ thể để dẫn dắt người dùng qua workflow. | +| **Workflow** | Quy trình nhiều bước có hướng dẫn, điều phối hoạt động của agent AI để tạo deliverable. | +``` + +### Quy tắc viết định nghĩa + +| Nên làm | Không nên làm | +| --- | --- | +| Bắt đầu bằng việc nó LÀ gì hoặc LÀM gì | Bắt đầu bằng "Đây là..." hoặc "Một [thuật ngữ] là..." | +| Giữ trong 1-2 câu | Viết thành nhiều đoạn dài | +| Bôi đậm tên thuật ngữ trong ô | Để thuật ngữ ở dạng chữ thường | + +### Dấu hiệu ngữ cảnh + +Thêm ngữ cảnh in nghiêng ở đầu định nghĩa với các thuật ngữ có phạm vi hẹp: + +- `*Chỉ dành cho Quick Flow.*` +- `*BMad Method/Enterprise.*` +- `*Phase N.*` +- `*BMGD.*` +- `*Dự án hiện có.*` + +### Checklist cho Glossary + +- [ ] Thuật ngữ nằm trong bảng, không dùng tiêu đề riêng +- [ ] Thuật ngữ được sắp theo thứ tự chữ cái trong từng nhóm +- [ ] Định nghĩa dài 1-2 câu +- [ ] Dấu hiệu ngữ cảnh được in nghiêng +- [ ] Tên thuật ngữ được bôi đậm trong ô +- [ ] Không dùng kiểu định nghĩa "Một [thuật ngữ] là..." + +## Phần FAQ + +```md +## Các câu hỏi + +- [Lúc nào cũng cần kiến trúc à?](#luc-nao-cung-can-kien-truc-a) +- [Tôi có thể đổi kế hoạch về sau không?](#toi-co-the-doi-ke-hoach-ve-sau-khong) + +### Lúc nào cũng cần kiến trúc à? + +Chỉ với nhánh BMad Method và Enterprise. Quick Flow bỏ qua để đi thẳng vào triển khai. + +### Tôi có thể đổi kế hoạch về sau không? + +Có. Workflow `bmad-correct-course` xử lý thay đổi phạm vi giữa chừng. + +**Có câu hỏi chưa được trả lời ở đây?** [Mở issue](...) hoặc hỏi trên [Discord](...). +``` + +## Các Lệnh Kiểm Tra + +Trước khi gửi thay đổi tài liệu: + +```bash +npm run docs:fix-links # Xem trước các sửa định dạng link +npm run docs:fix-links -- --write # Áp dụng các sửa +npm run docs:validate-links # Kiểm tra link tồn tại +npm run docs:build # Xác minh không có lỗi build +``` \ No newline at end of file diff --git a/docs/vi-vn/explanation/advanced-elicitation.md b/docs/vi-vn/explanation/advanced-elicitation.md new file mode 100644 index 000000000..37b8fbd08 --- /dev/null +++ b/docs/vi-vn/explanation/advanced-elicitation.md @@ -0,0 +1,49 @@ +--- +title: "Khai thác nâng cao" +description: Buộc LLM xem xét lại kết quả của nó bằng các phương pháp lập luận có cấu trúc +sidebar: + order: 6 +--- + +Buộc LLM xem xét lại những gì nó vừa tạo ra. Bạn chọn một phương pháp lập luận, nó áp dụng phương pháp đó lên chính output của mình, rồi bạn quyết định có giữ các cải tiến hay không. + +## Khai thác nâng cao là gì? + +Đây là một lần xem xét lại có cấu trúc. Thay vì bảo AI "thử lại" hoặc "làm cho nó tốt hơn", bạn chọn một phương pháp lập luận cụ thể và AI sẽ xem lại output của chính nó dưới góc đó. + +Khác biệt này rất quan trọng. Yêu cầu mơ hồ sẽ tạo ra bản sửa đổi mơ hồ. Một phương pháp được gọi tên buộc AI tấn công vấn đề theo một hướng cụ thể, qua đó phát hiện những ý tưởng mà một lần thử lại chung chung sẽ bỏ lỡ. + +## Khi nào nên dùng + +- Sau khi workflow tạo nội dung và bạn muốn có phương án thay thế +- Khi output có vẻ ổn nhưng bạn nghi vẫn còn có thể đào sâu hơn +- Để stress-test các giả định hoặc tìm điểm yếu +- Với nội dung quan trọng, nơi mà việc nghĩ lại sẽ có giá trị + +Các workflow sẽ đưa ra tùy chọn khai thác nâng cao tại các điểm quyết định - sau khi LLM tạo một kết quả, bạn sẽ được hỏi có muốn chạy nó hay không. + +## Nó hoạt động như thế nào + +1. LLM đề xuất 5 phương pháp phù hợp với nội dung của bạn +2. Bạn chọn một phương pháp (hoặc đảo lại để xem lựa chọn khác) +3. Phương pháp được áp dụng, các cải tiến được hiện ra +4. Chấp nhận hoặc bỏ đi, lặp lại hoặc tiếp tục + +## Các phương pháp tích hợp sẵn + +Có hàng chục phương pháp lập luận có sẵn. Một vài ví dụ: + +- **Pre-mortem Analysis** - Giả sử dự án đã thất bại rồi lần ngược lại để tìm lý do +- **First Principles Thinking** - Loại bỏ giả định, xây lại từ sự thật nền tảng +- **Inversion** - Hỏi cách nào chắc chắn dẫn đến thất bại, rồi tránh những điều đó +- **Red Team vs Blue Team** - Tự tấn công công việc của chính mình, rồi tự bảo vệ nó +- **Socratic Questioning** - Chất vấn mọi khẳng định bằng "tại sao?" và "làm sao bạn biết?" +- **Constraint Removal** - Bỏ hết ràng buộc, xem điều gì thay đổi, rồi thêm lại có chọn lọc +- **Stakeholder Mapping** - Đánh giá lại từ góc nhìn của từng bên liên quan +- **Analogical Reasoning** - Tìm điểm tương đồng ở lĩnh vực khác và áp dụng bài học của chúng + +Và còn nhiều nữa. AI sẽ chọn những lựa chọn phù hợp nhất với nội dung của bạn - bạn quyết định chạy cái nào. + +:::tip[Bắt đầu từ đây] +Pre-mortem Analysis là lựa chọn đầu tiên tốt cho bất kỳ bản spec hoặc kế hoạch nào. Nó thường xuyên tìm ra các lỗ hổng mà một lần review thông thường bỏ qua. +::: diff --git a/docs/vi-vn/explanation/adversarial-review.md b/docs/vi-vn/explanation/adversarial-review.md new file mode 100644 index 000000000..3a4bb64f6 --- /dev/null +++ b/docs/vi-vn/explanation/adversarial-review.md @@ -0,0 +1,59 @@ +--- +title: "Đánh giá đối kháng" +description: Kỹ thuật lập luận ép buộc giúp tránh các bản review lười kiểu "nhìn ổn" +sidebar: + order: 5 +--- + +Buộc quá trình phân tích đi sâu hơn bằng cách ép phải tìm ra vấn đề. + +## Đánh giá đối kháng là gì? + +Đây là một kỹ thuật review mà người review *bắt buộc* phải tìm thấy vấn đề. Không có chuyện "nhìn ổn". Người review chọn lập trường hoài nghi - giả sử vấn đề có tồn tại và đi tìm chúng. + +Đây không phải là việc cố tình tiêu cực. Đây là cách ép buộc phân tích thật sự, thay vì chỉ liếc qua và đóng dấu chấp nhận những gì vừa được nộp lên. + +**Quy tắc cốt lõi:** Bạn phải tìm ra vấn đề. Nếu không có phát hiện nào, quy trình sẽ dừng lại - cần phân tích lại hoặc giải thích tại sao. + +## Vì sao nó hiệu quả + +Những lần review thông thường dễ bị confirmation bias. Bạn lướt qua công việc, không có gì đập vào mắt, rồi phê duyệt. Yêu cầu "tìm vấn đề" phá vỡ mẫu này: + +- **Ép buộc sự kỹ lưỡng** - Không thể phê duyệt cho đến khi bạn đã đào đủ sâu để tìm thấy vấn đề +- **Bắt được những thứ đang thiếu** - "Còn gì chưa có ở đây?" trở thành câu hỏi tự nhiên +- **Tăng chất lượng tín hiệu** - Các phát hiện cụ thể và có thể hành động được, không phải các lo ngại mơ hồ +- **Bất đối xứng thông tin** - Chạy review với bối cảnh mới (không có lý do gốc) để đánh giá artifact, không phải ý định + +## Nó được dùng ở đâu + +Đánh giá đối kháng xuất hiện xuyên suốt các workflow của BMad - code review, kiểm tra sẵn sàng triển khai, xác thực spec, và nhiều nơi khác. Đôi khi là bước bắt buộc, đôi khi là tùy chọn (như khai thác nâng cao hoặc party mode). Mẫu này được điều chỉnh theo artifact cần bị soi kỹ. + +## Vẫn cần bộ lọc của con người + +Vì AI *được lệnh* phải tìm vấn đề, nó sẽ tìm vấn đề - ngay cả khi chúng không tồn tại. Hãy kỳ vọng false positive: bắt bẻ những lỗi vặt, hiểu sai ý định, hoặc thậm chí tưởng tượng ra vấn đề. + +**Bạn là người quyết định cái nào là thật.** Xem từng phát hiện, bỏ qua nhiễu, sửa những gì quan trọng. + +## Ví dụ + +Thay vì: + +> "Phần triển khai xác thực có vẻ hợp lý. Đã duyệt." + +Một lần đánh giá đối kháng sẽ cho ra: + +> 1. **HIGH** - `login.ts:47` - Không có giới hạn tốc độ cho các lần đăng nhập thất bại +> 2. **HIGH** - Session token được lưu trong localStorage (dễ bị XSS) +> 3. **MEDIUM** - Kiểm tra mật khẩu chỉ diễn ra ở client +> 4. **MEDIUM** - Không có audit log cho các lần đăng nhập thất bại +> 5. **LOW** - Số magic `3600` nên được đổi thành `SESSION_TIMEOUT_SECONDS` + +Bản review thứ nhất có thể bỏ sót một lỗi bảo mật. Bản review thứ hai đã bắt được bốn vấn đề. + +## Lặp lại và lợi ích giảm dần + +Sau khi đã xử lý các phát hiện, hãy cân nhắc chạy lại. Lần thứ hai thường sẽ bắt thêm được vấn đề. Lần thứ ba cũng không phải lúc nào cũng vô ích. Nhưng mỗi lần đều tốn thời gian, và đến một mức nào đó bạn sẽ gặp lợi ích giảm dần - chỉ còn các bắt bẻ nhỏ và false positive. + +:::tip[Review tốt hơn] +Giả sử vấn đề có tồn tại. Tìm những gì còn thiếu, không chỉ những gì sai. +::: diff --git a/docs/vi-vn/explanation/analysis-phase.md b/docs/vi-vn/explanation/analysis-phase.md new file mode 100644 index 000000000..d35f9f65d --- /dev/null +++ b/docs/vi-vn/explanation/analysis-phase.md @@ -0,0 +1,70 @@ +--- +title: "Giai đoạn phân tích: từ ý tưởng đến nền tảng" +description: Động não, nghiên cứu, product brief và PRFAQ là gì, và nên dùng từng công cụ khi nào +sidebar: + order: 1 +--- + +Giai đoạn phân tích (giai đoạn 1) giúp bạn suy nghĩ rõ ràng về sản phẩm trước khi cam kết bắt tay vào xây dựng. Mọi công cụ trong giai đoạn này đều là tùy chọn, nhưng nếu bỏ qua toàn bộ phần phân tích thì PRD của bạn sẽ được dựng trên giả định thay vì hiểu biết thực chất. + +## Vì sao cần phân tích trước khi lập kế hoạch? + +PRD trả lời câu hỏi "chúng ta nên xây gì và vì sao?". Nếu đầu vào của nó là những suy nghĩ mơ hồ, bạn sẽ nhận lại một PRD mơ hồ, và mọi tài liệu phía sau đều kế thừa chính sự mơ hồ đó. Kiến trúc dựng trên một PRD yếu sẽ đặt cược sai về mặt kỹ thuật. Các story sinh ra từ một kiến trúc yếu sẽ bỏ sót trường hợp biên. Chi phí sẽ dồn lên theo từng tầng. + +Các công cụ phân tích tồn tại để làm PRD của bạn sắc bén hơn. Chúng tiếp cận vấn đề từ nhiều góc độ khác nhau: khám phá sáng tạo, thực tế thị trường, độ rõ ràng về khách hàng, tính khả thi. Nhờ vậy, đến khi bạn ngồi xuống làm việc với agent PM, bạn đã biết mình đang xây cái gì và cho ai. + +## Các công cụ + +### Động não + +**Nó là gì.** Một phiên sáng tạo có điều phối, sử dụng các kỹ thuật phát ý tưởng đã được kiểm chứng. AI đóng vai trò như người huấn luyện, kéo ý tưởng ra từ bạn thông qua các bài tập có cấu trúc, chứ không nghĩ thay cho bạn. + +**Vì sao nó có mặt ở đây.** Ý tưởng thô cần không gian để phát triển trước khi bị khóa cứng thành yêu cầu. Động não tạo ra khoảng không đó. Nó đặc biệt có giá trị khi bạn có một miền vấn đề nhưng chưa có lời giải rõ ràng, hoặc khi bạn muốn khám phá nhiều hướng trước khi cam kết. + +**Khi nào nên dùng.** Bạn có một hình dung mơ hồ về thứ mình muốn xây nhưng chưa kết tinh được thành khái niệm rõ ràng. Hoặc bạn đã có ý tưởng ban đầu nhưng muốn kiểm chứng độ vững của nó bằng các phương án thay thế. + +Xem [Brainstorming](./brainstorming.md) để hiểu sâu hơn về cách một phiên làm việc diễn ra. + +### Nghiên cứu (thị trường, miền nghiệp vụ, kỹ thuật) + +**Nó là gì.** Ba quy trình nghiên cứu tập trung vào các chiều khác nhau của ý tưởng. Nghiên cứu thị trường xem xét đối thủ, xu hướng và cảm nhận của người dùng. Nghiên cứu miền nghiệp vụ xây dựng hiểu biết về lĩnh vực và thuật ngữ. Nghiên cứu kỹ thuật đánh giá tính khả thi, các lựa chọn kiến trúc và hướng triển khai. + +**Vì sao nó có mặt ở đây.** Xây dựng dựa trên giả định là con đường nhanh nhất để tạo ra thứ chẳng ai cần. Nghiên cứu đặt ý tưởng của bạn xuống mặt đất: đối thủ nào đã tồn tại, người dùng thực sự đang vật lộn với điều gì, điều gì khả thi về kỹ thuật, và bạn sẽ phải đối mặt với những ràng buộc đặc thù ngành nào. + +**Khi nào nên dùng.** Bạn đang bước vào một miền mới, nghi ngờ có đối thủ nhưng chưa lập bản đồ được, hoặc ý tưởng của bạn phụ thuộc vào những năng lực kỹ thuật mà bạn chưa kiểm chứng. Có thể chạy một, hai, hoặc cả ba; mỗi quy trình đều đứng độc lập. + +### Product Brief + +**Nó là gì.** Một phiên discovery có hướng dẫn, tạo ra bản tóm tắt điều hành 1-2 trang cho concept sản phẩm của bạn. AI đóng vai trò Business Analyst cộng tác, giúp bạn diễn đạt tầm nhìn, đối tượng mục tiêu, giá trị cốt lõi và phạm vi. + +**Vì sao nó có mặt ở đây.** Product brief là con đường nhẹ nhàng hơn để đi vào giai đoạn lập kế hoạch. Nó ghi lại tầm nhìn chiến lược của bạn theo định dạng có cấu trúc và đưa thẳng vào quá trình tạo PRD. Nó hoạt động tốt nhất khi bạn đã có niềm tin tương đối chắc vào ý tưởng của mình: bạn biết khách hàng là ai, vấn đề là gì, và đại khái muốn xây gì. Brief sẽ tổ chức lại và làm sắc nét lối suy nghĩ đó. + +**Khi nào nên dùng.** Ý tưởng của bạn đã tương đối rõ và bạn muốn ghi lại nó một cách hiệu quả trước khi tạo PRD. Bạn tin vào hướng đi hiện tại và không cần bị thách thức giả định một cách quá quyết liệt. + +### PRFAQ (Working Backwards) + +**Nó là gì.** Phương pháp Working Backwards của Amazon được chuyển thành một thử thách tương tác. Bạn viết thông cáo báo chí công bố sản phẩm hoàn thiện trước khi tồn tại dù chỉ một dòng code, rồi trả lời những câu hỏi khó nhất mà khách hàng và stakeholder sẽ đặt ra. AI đóng vai trò product coach dai dẳng nhưng mang tính xây dựng. + +**Vì sao nó có mặt ở đây.** PRFAQ là con đường nghiêm ngặt hơn để đi vào giai đoạn lập kế hoạch. Nó buộc bạn đạt đến sự rõ ràng theo hướng lấy khách hàng làm trung tâm bằng cách bắt bạn bảo vệ từng phát biểu. Nếu bạn không viết nổi một thông cáo báo chí đủ thuyết phục, sản phẩm đó chưa sẵn sàng. Nếu phần FAQ lộ ra những khoảng trống, đó chính là những khoảng trống mà bạn sẽ phát hiện muộn hơn rất nhiều, và với chi phí lớn hơn nhiều, trong lúc triển khai. Bài kiểm tra này bóc tách lối suy nghĩ yếu ngay từ sớm, khi chi phí sửa còn rẻ nhất. + +**Khi nào nên dùng.** Bạn muốn kiểm tra độ vững của ý tưởng trước khi cam kết tài nguyên. Bạn chưa chắc người dùng có thực sự quan tâm hay không. Bạn muốn xác nhận rằng mình có thể diễn đạt một giá trị cốt lõi rõ ràng và có thể bảo vệ được. Hoặc đơn giản là bạn muốn dùng sự kỷ luật của Working Backwards để làm suy nghĩ của mình sắc bén hơn. + +## Tôi nên dùng cái nào? + +| Tình huống | Công cụ được khuyến nghị | +| --------- | ------------------------ | +| "Tôi có một ý tưởng mơ hồ, chưa biết bắt đầu từ đâu" | Brainstorming | +| "Tôi cần hiểu thị trường trước khi quyết định" | Research | +| "Tôi biết mình muốn xây gì rồi, chỉ cần ghi lại" | Product Brief | +| "Tôi muốn chắc rằng ý tưởng này thực sự đáng để xây" | PRFAQ | +| "Tôi muốn khám phá, rồi kiểm chứng, rồi ghi lại" | Brainstorming → Research → PRFAQ hoặc Brief | + +Product Brief và PRFAQ đều tạo ra đầu vào cho PRD. Hãy chọn một trong hai tùy vào mức độ thách thức bạn muốn. Brief là discovery mang tính cộng tác. PRFAQ là một bài kiểm tra khắc nghiệt. Cả hai đều đưa bạn tới cùng một đích; PRFAQ chỉ kiểm tra xem concept của bạn có thật sự xứng đáng để đến đó hay không. + +:::tip[Chưa chắc nên bắt đầu ở đâu?] +Hãy chạy `bmad-help` và mô tả tình huống của bạn. Nó sẽ gợi ý điểm bắt đầu phù hợp dựa trên những gì bạn đã làm và điều bạn đang muốn đạt được. +::: + +## Sau giai đoạn phân tích thì chuyện gì xảy ra? + +Đầu ra từ giai đoạn phân tích đi thẳng vào giai đoạn 2, lập kế hoạch. Quy trình tạo PRD chấp nhận product brief, tài liệu PRFAQ, kết quả nghiên cứu và báo cáo động não làm đầu vào. Nó sẽ tổng hợp bất cứ thứ gì bạn đã tạo thành các yêu cầu có cấu trúc. Bạn làm phân tích càng kỹ, PRD của bạn càng sắc. \ No newline at end of file diff --git a/docs/vi-vn/explanation/brainstorming.md b/docs/vi-vn/explanation/brainstorming.md new file mode 100644 index 000000000..8c269a675 --- /dev/null +++ b/docs/vi-vn/explanation/brainstorming.md @@ -0,0 +1,33 @@ +--- +title: "Động não ý tưởng" +description: Các phiên sáng tạo tương tác sử dụng hơn 60 kỹ thuật khơi ý đã được kiểm chứng +sidebar: + order: 2 +--- + +Mở khóa sự sáng tạo của bạn thông qua quá trình khám phá có hướng dẫn. + +## Động não ý tưởng là gì? + +Chạy `bmad-brainstorming` và bạn sẽ có một người điều phối sáng tạo giúp rút ý tưởng từ chính bạn - không phải phát sinh thay bạn. AI đóng vai trò huấn luyện viên và người dẫn đường, sử dụng các kỹ thuật đã được kiểm chứng để tạo điều kiện cho những ý tưởng tốt nhất của bạn xuất hiện. + +**Phù hợp cho:** + +- Phá vỡ thế bí ý tưởng +- Tạo ý tưởng sản phẩm hoặc tính năng +- Xem xét vấn đề từ góc nhìn mới +- Biến các khái niệm thô thành kế hoạch hành động + +## Nó hoạt động như thế nào + +1. **Thiết lập** - Xác định chủ đề, mục tiêu, ràng buộc +2. **Chọn cách tiếp cận** - Tự chọn kỹ thuật, để AI đề xuất, chọn ngẫu nhiên, hoặc đi theo một luồng tiến trình +3. **Điều phối** - Làm việc qua từng kỹ thuật bằng các câu hỏi gợi mở và huấn luyện cộng tác +4. **Sắp xếp** - Gom ý tưởng theo chủ đề và ưu tiên hóa +5. **Hành động** - Các ý tưởng tốt nhất sẽ được gán bước tiếp theo và chỉ số thành công + +Mọi thứ đều được ghi lại trong tài liệu phiên làm việc để bạn có thể xem lại sau này hoặc chia sẻ với stakeholder. + +:::note[Ý tưởng của bạn] +Mọi ý tưởng đều đến từ bạn. Workflow chỉ tạo điều kiện cho insight xuất hiện - nguồn gốc vẫn là bạn. +::: diff --git a/docs/vi-vn/explanation/established-projects-faq.md b/docs/vi-vn/explanation/established-projects-faq.md new file mode 100644 index 000000000..920f10748 --- /dev/null +++ b/docs/vi-vn/explanation/established-projects-faq.md @@ -0,0 +1,51 @@ +--- +title: "FAQ cho dự án đã tồn tại" +description: Các câu hỏi phổ biến khi dùng BMad Method trên dự án đã tồn tại +sidebar: + order: 8 +--- + +Các câu trả lời nhanh cho những câu hỏi thường gặp khi làm việc với dự án đã tồn tại bằng BMad Method (BMM). + +## Các câu hỏi + +- [Tôi có phải chạy document-project trước không?](#toi-co-phai-chay-document-project-truoc-khong) +- [Nếu tôi quên chạy document-project thì sao?](#neu-toi-quen-chay-document-project-thi-sao) +- [Tôi có thể dùng Quick Flow cho dự án đã tồn tại không?](#toi-co-the-dung-quick-flow-cho-du-an-da-ton-tai-khong) +- [Nếu code hiện tại của tôi không theo best practices thì sao?](#neu-code-hien-tai-cua-toi-khong-theo-best-practices-thi-sao) + +### Tôi có phải chạy document-project trước không? + +Rất nên chạy, nhất là khi: + +- Không có tài liệu sẵn có +- Tài liệu đã lỗi thời +- Agent AI cần context về code hiện có + +Bạn có thể bỏ qua nếu đã có tài liệu đầy đủ, mới, bao gồm `docs/index.md`, hoặc bạn sẽ dùng công cụ/kỹ thuật khác để giúp agent khám phá hệ thống hiện có. + +### Nếu tôi quên chạy document-project thì sao? + +Không sao - bạn có thể chạy nó bất cứ lúc nào. Bạn thậm chí có thể chạy trong khi dự án đang diễn ra hoặc sau đó để giữ tài liệu luôn mới. + +### Tôi có thể dùng Quick Flow cho dự án đã tồn tại không? + +Có. Quick Flow hoạt động rất tốt với dự án đã tồn tại. Nó sẽ: + +- Tự động nhận diện stack hiện có +- Phân tích pattern code hiện có +- Phát hiện quy ước và hỏi bạn để xác nhận +- Tạo spec giàu ngữ cảnh, tôn trọng code hiện có + +Rất hợp với sửa lỗi và tính năng nhỏ trong codebase sẵn có. + +### Nếu code hiện tại của tôi không theo best practices thì sao? + +Quick Flow sẽ nhận diện quy ước hiện có và hỏi: "Tôi có nên tuân theo những quy ước hiện tại này không?" Bạn là người quyết định: + +- **Có** → Giữ tính nhất quán với codebase hiện tại +- **Không** → Đặt ra chuẩn mới, đồng thời ghi rõ lý do trong spec + +BMM tôn trọng lựa chọn của bạn - nó không ép buộc hiện đại hóa, nhưng sẽ đưa ra lựa chọn đó. + +**Có câu hỏi chưa được trả lời ở đây?** Hãy [mở issue](https://github.com/bmad-code-org/BMAD-METHOD/issues) hoặc hỏi trên [Discord](https://discord.gg/gk8jAdXWmj) để chúng tôi bổ sung! diff --git a/docs/vi-vn/explanation/party-mode.md b/docs/vi-vn/explanation/party-mode.md new file mode 100644 index 000000000..c244b595e --- /dev/null +++ b/docs/vi-vn/explanation/party-mode.md @@ -0,0 +1,59 @@ +--- +title: "Chế độ Party" +description: Cộng tác đa agent - đưa tất cả agent AI vào cùng một cuộc trò chuyện +sidebar: + order: 7 +--- + +Đưa tất cả agent AI của bạn vào cùng một cuộc trò chuyện. + +## Party Mode là gì? + +Chạy `bmad-party-mode` và bạn sẽ có cả đội AI trong cùng một phòng - PM, Architect, Dev, UX Designer, bất kỳ ai bạn cần. BMad Master điều phối, chọn các agent liên quan cho từng tin nhắn. Các agent trả lời đúng vai, đồng ý, phản biện, và bổ sung ý tưởng cho nhau. + +Cuộc trò chuyện tiếp tục lâu đến mức bạn muốn. Bạn có thể hỏi tiếp, phản biện câu trả lời, đổi hướng thảo luận - đó là một cuộc qua lại thật sự với các agent của bạn cho đến khi xong. + +**Phù hợp cho:** + +- Các quyết định lớn có đánh đổi +- Các phiên động não ý tưởng +- Post-mortem khi mọi thứ đi sai +- Retrospective và lập kế hoạch sprint + +## Ví dụ + +### Gọi tên kiến trúc tệ + +**Bạn:** "Được rồi cả đội, sprint vừa rồi là một thảm họa. Dịch vụ xác thực sập ba lần. Ai đã làm hỏng chuyện này?" + +**Architect:** "Thiết kế vẫn ổn - xác thực phân tán với cơ chế fallback hợp lý. Nếu phần triển khai lệch khỏi spec..." + +**Dev:** "Tôi đã làm đúng theo tài liệu kiến trúc. Spec không tính đến race condition khi vô hiệu hóa session đồng thời." + +**PM:** "Cả hai người đều bỏ sót vấn đề lớn hơn - chúng ta không xác thực đúng yêu cầu quản lý session trong PRD. **Lỗi này là do tôi** không bắt được sớm hơn." + +**TEA:** "Và tôi đáng ra phải bắt được nó trong integration test. Các kịch bản test đã không bao phủ trường hợp vô hiệu hóa đồng thời." + +### Động não sáng tạo + +**Bạn:** "Làm sao để quá trình onboarding có cảm giác kỳ diệu thay vì nhàm chán?" + +**UX Designer:** "Bắt đầu bằng progressive disclosure - hiện tính năng khi người dùng cần, thay vì tung một tutorial dày đặc." + +**Storyteller:** "Nếu onboarding là một câu chuyện thì sao? Mỗi bước mở ra hành trình của một nhân vật - người dùng CHÍNH là người hùng." + +**Game Designer:** "Nối tiếp ý đó - nếu 'nhiệm vụ' đầu tiên thực chất giải quyết một vấn đề thật của người dùng thì sao? Họ học bằng cách làm ra giá trị ngay." + +### Quyết định kỹ thuật + +**Bạn:** "MVP nên dùng monolith hay microservices?" + +**Architect:** "Bắt đầu bằng monolith. Microservices thêm độ phức tạp mà bạn chưa cần ở mức 1000 người dùng." + +**PM:** "Đồng ý. Tốc độ ra thị trường quan trọng hơn khả năng mở rộng lý thuyết." + +**Dev:** "Monolith nhưng có ranh giới module rõ ràng. Nếu cần, mình có thể tách service sau." + +:::tip[Quyết định tốt hơn] +Quyết định tốt hơn nhờ nhiều góc nhìn đa dạng. Chào mừng đến với party mode. +::: diff --git a/docs/vi-vn/explanation/preventing-agent-conflicts.md b/docs/vi-vn/explanation/preventing-agent-conflicts.md new file mode 100644 index 000000000..ef77c8cf1 --- /dev/null +++ b/docs/vi-vn/explanation/preventing-agent-conflicts.md @@ -0,0 +1,112 @@ +--- +title: "Ngăn xung đột giữa các agent" +description: Cách kiến trúc ngăn xung đột khi nhiều agent cùng triển khai một hệ thống +sidebar: + order: 4 +--- + +Khi nhiều agent AI cùng triển khai các phần khác nhau của hệ thống, chúng có thể đưa ra các quyết định kỹ thuật mâu thuẫn nhau. Tài liệu kiến trúc ngăn điều đó bằng cách thiết lập các tiêu chuẩn dùng chung. + +## Các kiểu xung đột phổ biến + +### Xung đột về phong cách API + +Không có kiến trúc: +- Agent A dùng REST với `/users/{id}` +- Agent B dùng GraphQL mutations +- Kết quả: pattern API không nhất quán, người dùng API bị rối + +Có kiến trúc: +- ADR quy định: "Dùng GraphQL cho mọi giao tiếp client-server" +- Tất cả agent theo cùng một mẫu + +### Xung đột về thiết kế cơ sở dữ liệu + +Không có kiến trúc: +- Agent A dùng tên cột theo snake_case +- Agent B dùng camelCase +- Kết quả: schema không nhất quán, truy vấn khó hiểu + +Có kiến trúc: +- Tài liệu standards quy định quy ước đặt tên +- Tất cả agent theo cùng một pattern + +### Xung đột về quản lý state + +Không có kiến trúc: +- Agent A dùng Redux cho global state +- Agent B dùng React Context +- Kết quả: nhiều cách quản lý state song song, độ phức tạp tăng cao + +Có kiến trúc: +- ADR quy định cách quản lý state +- Tất cả agent triển khai thống nhất + +## Kiến trúc ngăn xung đột bằng cách nào + +### 1. Quyết định rõ ràng thông qua ADR + +Mỗi lựa chọn công nghệ quan trọng đều được ghi lại với: +- Context (vì sao quyết định này quan trọng) +- Các lựa chọn đã cân nhắc (có những phương án nào) +- Quyết định (ta đã chọn gì) +- Lý do (tại sao lại chọn như vậy) +- Hệ quả (các đánh đổi được chấp nhận) + +### 2. Hướng dẫn riêng cho FR/NFR + +Kiến trúc ánh xạ mỗi functional requirement sang cách tiếp cận kỹ thuật: +- FR-001: User Management → GraphQL mutations +- FR-002: Mobile App → Truy vấn tối ưu + +### 3. Tiêu chuẩn và quy ước + +Tài liệu hóa rõ ràng về: +- Cấu trúc thư mục +- Quy ước đặt tên +- Cách tổ chức code +- Pattern kiểm thử + +## Kiến trúc như một bối cảnh dùng chung + +Hãy xem kiến trúc là bối cảnh dùng chung mà tất cả agent đều đọc trước khi triển khai: + +```text +PRD: "Cần xây gì" + ↓ +Kiến trúc: "Xây như thế nào" + ↓ +Agent A đọc kiến trúc → triển khai Epic 1 +Agent B đọc kiến trúc → triển khai Epic 2 +Agent C đọc kiến trúc → triển khai Epic 3 + ↓ +Kết quả: Triển khai nhất quán +``` + +## Các chủ đề ADR quan trọng + +Những quyết định phổ biến giúp tránh xung đột: + +| Chủ đề | Ví dụ quyết định | +| ---------------- | -------------------------------------------- | +| API Style | GraphQL hay REST hay gRPC | +| Database | PostgreSQL hay MongoDB | +| Auth | JWT hay Session | +| State Management | Redux hay Context hay Zustand | +| Styling | CSS Modules hay Tailwind hay Styled Components | +| Testing | Jest + Playwright hay Vitest + Cypress | + +## Anti-pattern cần tránh + +:::caution[Những lỗi thường gặp] +- **Quyết định ngầm** - "Cứ để đó rồi tính phong cách API sau" sẽ dẫn đến không nhất quán +- **Tài liệu hóa quá mức** - Ghi lại mọi lựa chọn nhỏ gây tê liệt phân tích +- **Kiến trúc lỗi thời** - Tài liệu viết một lần rồi không cập nhật khiến agent đi theo pattern cũ +::: + +:::tip[Cách tiếp cận đúng] +- Tài liệu hóa những quyết định cắt ngang nhiều epic +- Tập trung vào những khu vực dễ phát sinh xung đột +- Cập nhật kiến trúc khi bạn học thêm +- Dùng `bmad-correct-course` cho các thay đổi đáng kể +::: diff --git a/docs/vi-vn/explanation/project-context.md b/docs/vi-vn/explanation/project-context.md new file mode 100644 index 000000000..534824377 --- /dev/null +++ b/docs/vi-vn/explanation/project-context.md @@ -0,0 +1,157 @@ +--- +title: "Bối cảnh dự án" +description: Cách project-context.md định hướng các agent AI theo quy tắc và ưu tiên của dự án +sidebar: + order: 7 +--- + +Tệp `project-context.md` là kim chỉ nam cho việc triển khai của các agent AI trong dự án của bạn. Tương tự như một "bản hiến pháp" trong các hệ thống phát triển khác, nó ghi lại các quy tắc, pattern và ưu tiên giúp việc sinh mã được nhất quán trong mọi workflow. + +## Nó làm gì + +Các agent AI liên tục đưa ra quyết định triển khai - theo pattern nào, tổ chức code ra sao, dùng quy ước gì. Nếu không có hướng dẫn rõ ràng, chúng có thể: +- Làm theo best practice chung chung không khớp với codebase của bạn +- Đưa ra quyết định không nhất quán giữa các story +- Bỏ sót yêu cầu hoặc ràng buộc đặc thù của dự án + +Tệp `project-context.md` giải quyết vấn đề này bằng cách tài liệu hóa những gì agent cần biết trong định dạng ngắn gọn, tối ưu cho LLM. + +## Nó hoạt động như thế nào + +Mỗi workflow triển khai đều tự động nạp `project-context.md` nếu tệp tồn tại. Workflow architect cũng nạp tệp này để tôn trọng các ưu tiên kỹ thuật của bạn khi thiết kế kiến trúc. + +**Được nạp bởi các workflow sau:** +- `bmad-create-architecture` - tôn trọng ưu tiên kỹ thuật trong giai đoạn solutioning +- `bmad-create-story` - đưa pattern của dự án vào quá trình tạo story +- `bmad-dev-story` - định hướng các quyết định triển khai +- `bmad-code-review` - đối chiếu với tiêu chuẩn của dự án +- `bmad-quick-dev` - áp dụng pattern khi triển khai các spec +- `bmad-sprint-planning`, `bmad-retrospective`, `bmad-correct-course` - cung cấp bối cảnh cấp dự án + +## Khi nào nên tạo + +Tệp `project-context.md` hữu ích ở bất kỳ giai đoạn nào của dự án: + +| Tình huống | Khi nào nên tạo | Mục đích | +|----------|----------------|---------| +| **Dự án mới, trước kiến trúc** | Tạo thủ công, trước `bmad-create-architecture` | Ghi lại ưu tiên kỹ thuật để architect tôn trọng | +| **Dự án mới, sau kiến trúc** | Qua `bmad-generate-project-context` hoặc tạo thủ công | Ghi lại quyết định kiến trúc cho các agent triển khai | +| **Dự án hiện có** | Qua `bmad-generate-project-context` | Khám phá pattern hiện có để agent theo đúng quy ước | +| **Dự án Quick Flow** | Trước hoặc trong `bmad-quick-dev` | Đảm bảo triển khai nhanh vẫn tôn trọng pattern của bạn | + +:::tip[Khuyến nghị] +Với dự án mới, hãy tạo thủ công trước giai đoạn kiến trúc nếu bạn có ưu tiên kỹ thuật rõ ràng. Nếu không, hãy tạo nó sau kiến trúc để ghi lại các quyết định đã được đưa ra. +::: + +## Nội dung cần có trong tệp + +Tệp này có hai phần chính: + +### Technology Stack & Versions + +Ghi lại framework, ngôn ngữ và công cụ dự án đang dùng, kèm phiên bản cụ thể: + +```markdown +## Technology Stack & Versions + +- Node.js 20.x, TypeScript 5.3, React 18.2 +- State: Zustand (không dùng Redux) +- Testing: Vitest, Playwright, MSW +- Styling: Tailwind CSS với custom design tokens +``` + +### Critical Implementation Rules + +Ghi lại những pattern và quy ước mà agent dễ bỏ sót nếu chỉ đọc qua code: + +```markdown +## Critical Implementation Rules + +**TypeScript Configuration:** +- Bật strict mode - không dùng `any` nếu chưa có phê duyệt rõ ràng +- Dùng `interface` cho public API, `type` cho union/intersection + +**Code Organization:** +- Components đặt trong `/src/components/` và để `.test.tsx` cùng chỗ +- Utilities đặt trong `/src/lib/` cho các hàm pure có thể tái sử dụng +- Lời gọi API phải dùng `apiClient` singleton - không fetch trực tiếp + +**Testing Patterns:** +- Unit test tập trung vào business logic, không soi chi tiết implementation +- Integration test dùng MSW để mock API responses +- E2E test chỉ bao phủ các user journey quan trọng + +**Framework-Specific:** +- Mọi thao tác async dùng wrapper `handleError` để xử lý lỗi nhất quán +- Feature flags được truy cập qua `featureFlag()` từ `@/lib/flags` +- Route mới theo file-based routing pattern trong `/src/app/` +``` + +Hãy tập trung vào những gì **không hiển nhiên** - những điều agent khó suy ra chỉ từ một vài đoạn code. Không cần ghi lại các thực hành tiêu chuẩn áp dụng mọi nơi. + +## Tạo tệp + +Bạn có ba lựa chọn: + +### Tạo thủ công + +Tạo tệp tại `_bmad-output/project-context.md` và thêm các quy tắc của bạn: + +```bash +# Trong thư mục gốc của dự án +mkdir -p _bmad-output +touch _bmad-output/project-context.md +``` + +Sửa tệp để thêm stack công nghệ và quy tắc triển khai. Workflow architect và implementation sẽ tự động tìm và nạp nó. + +### Tạo sau khi hoàn thành kiến trúc + +Chạy workflow `bmad-generate-project-context` sau khi bạn hoàn tất kiến trúc: + +```bash +bmad-generate-project-context +``` + +Nó sẽ quét tài liệu kiến trúc và tệp dự án để tạo tệp context ghi lại các quyết định đã được đưa ra. + +### Tạo cho dự án hiện có + +Với dự án hiện có, chạy `bmad-generate-project-context` để khám phá pattern sẵn có: + +```bash +bmad-generate-project-context +``` + +Workflow sẽ phân tích codebase để nhận diện quy ước, sau đó tạo tệp context cho bạn xem lại và tinh chỉnh. + +## Vì sao nó quan trọng + +Nếu không có `project-context.md`, các agent sẽ tự đưa ra giả định có thể không phù hợp với dự án: + +| Không có context | Có context | +|----------------|--------------| +| Dùng pattern chung chung | Theo đúng quy ước đã được xác lập | +| Phong cách không nhất quán giữa các story | Triển khai nhất quán | +| Có thể bỏ sót ràng buộc đặc thù | Tôn trọng đầy đủ yêu cầu kỹ thuật | +| Mỗi agent tự quyết định | Tất cả agent canh hàng theo cùng quy tắc | + +Điều này đặc biệt quan trọng với: +- **Quick Flow** - bỏ qua PRD và kiến trúc, nên tệp context lấp đầy khoảng trống +- **Dự án theo nhóm** - đảm bảo tất cả agent theo cùng tiêu chuẩn +- **Dự án hiện có** - tránh phá vỡ các pattern đã ổn định + +## Chỉnh sửa và cập nhật + +Tệp `project-context.md` là tài liệu sống. Hãy cập nhật khi: + +- Quyết định kiến trúc thay đổi +- Có quy ước mới được thiết lập +- Pattern tiến hóa trong quá trình triển khai +- Bạn nhận ra lỗ hổng qua hành vi của agent + +Bạn có thể sửa thủ công bất kỳ lúc nào, hoặc chạy lại `bmad-generate-project-context` để cập nhật sau các thay đổi lớn. + +:::note[Vị trí tệp] +Vị trí mặc định là `_bmad-output/project-context.md`. Các workflow tìm tệp ở đó, đồng thời cũng kiểm tra `**/project-context.md` ở bất kỳ đâu trong dự án. +::: diff --git a/docs/vi-vn/explanation/quick-dev.md b/docs/vi-vn/explanation/quick-dev.md new file mode 100644 index 000000000..cd75e7c8a --- /dev/null +++ b/docs/vi-vn/explanation/quick-dev.md @@ -0,0 +1,73 @@ +--- +title: "Phát triển nhanh" +description: Giảm ma sát có người trong vòng lặp mà vẫn giữ các điểm kiểm tra bảo vệ chất lượng đầu ra +sidebar: + order: 2 +--- + +Đưa ý định vào, nhận thay đổi mã nguồn ra, với số lần cần con người nhảy vào giữa quy trình ít nhất có thể - nhưng không đánh đổi chất lượng. + +Nó cho phép mô hình tự vận hành lâu hơn giữa các điểm kiểm tra, rồi chỉ đưa con người quay lại khi tác vụ không thể tiếp tục an toàn nếu thiếu phán đoán của con người, hoặc khi đã đến lúc rà soát kết quả cuối. + +![Quick Dev workflow diagram](/diagrams/quick-dev-diagram.png) + +## Vì sao nó tồn tại + +Các lượt có người trong vòng lặp vừa cần thiết vừa tốn kém. + +LLM hiện tại vẫn thất bại theo những cách dễ đoán: hiểu sai ý định, tự điền vào khoảng trống bằng những phán đoán tự tin, lệch sang công việc không liên quan, và tạo ra các bản review nhiễu. Đồng thời, việc cần con người nhảy vào liên tục làm giảm tốc độ phát triển. Sự chú ý của con người là nút thắt. + +`bmad-quick-dev` cân bằng lại đánh đổi đó. Nó tin mô hình có thể chạy tự chủ lâu hơn, nhưng chỉ sau khi quy trình đã tạo được một ranh giới đủ mạnh để làm điều đó an toàn. + +## Thiết kế cốt lõi + +### 1. Nén ý định trước + +Quy trình bắt đầu bằng việc để con người và mô hình nén yêu cầu thành một mục tiêu thống nhất. Đầu vào có thể bắt đầu như một ý định thô, nhưng trước khi quy trình tự vận hành thì nó phải đủ nhỏ, đủ rõ ràng, và đủ ít mâu thuẫn để có thể thực thi. + +Ý định có thể đến từ nhiều dạng: vài cụm từ, liên kết trình theo dõi lỗi, đầu ra từ chế độ lập kế hoạch, đoạn văn bản sao chép từ phiên chat, hoặc thậm chí một số story trong `epics.md` của chính BMAD. Ở trường hợp cuối, quy trình không hiểu được ngữ nghĩa theo dõi story của BMAD, nhưng vẫn có thể lấy chính story đó và tiếp tục. + +Quy trình này không loại bỏ quyền kiểm soát của con người. Nó chuyển nó về một số thời điểm có giá trị cao: + +- **Làm rõ ý định** - biến một yêu cầu lộn xộn thành một mục tiêu thống nhất, không mâu thuẫn ngầm +- **Phê duyệt đặc tả** - xác nhận rằng cách hiểu đã được chốt là đúng thứ cần xây +- **Rà soát sản phẩm cuối** - điểm kiểm tra chính, nơi con người quyết định kết quả cuối có chấp nhận được hay không + +### 2. Định tuyến theo con đường an toàn nhỏ nhất + +Khi mục tiêu đã rõ, quy trình sẽ quyết định đây có phải thay đổi thực hiện một lần là xong hay cần đi theo đường đầy đủ hơn. Những thay đổi nhỏ, phạm vi ảnh hưởng gần như bằng 0 có thể đi thẳng vào triển khai. Còn lại sẽ đi qua lập kế hoạch để mô hình có được một ranh giới mạnh hơn trước khi tự chạy lâu hơn. + +### 3. Chạy lâu hơn với ít giám sát hơn + +Sau quyết định định tuyến đó, mô hình có thể tự gánh thêm công việc. Trên con đường đầy đủ, đặc tả đã được phê duyệt trở thành ranh giới mà mô hình sẽ thực thi với ít giám sát hơn, và đó chính là mục tiêu của thiết kế này. + +### 4. Chẩn đoán lỗi ở đúng tầng + +Nếu triển khai sai vì ý định sai, vậy sửa code không phải cách sửa đúng. Nếu code sai vì đặc tả yếu, thì vá diff cũng không phải cách sửa đúng. Quy trình được thiết kế để chẩn đoán lỗi đã đi vào hệ thống từ tầng nào, quay lại đúng tầng đó, rồi sinh lại từ đấy. + +Các phát hiện từ bước rà soát được dùng để xác định vấn đề đến từ ý định, quá trình tạo đặc tả, hay triển khai cục bộ. Chỉ những lỗi thật sự cục bộ mới được sửa tại chỗ. + +### 5. Chỉ đưa con người quay lại khi cần + +Bước phỏng vấn ý định có người trong vòng lặp, nhưng nó không giống một điểm kiểm tra lặp đi lặp lại. Quy trình cố gắng giảm thiểu những điểm kiểm tra lặp lại đó. Sau bước định hình ý định ban đầu, con người chủ yếu quay lại khi quy trình không thể tiếp tục an toàn nếu thiếu phán đoán, và ở cuối quy trình để rà soát kết quả. + +- **Xử lý khoảng trống của ý định** - quay lại khi review cho thấy workflow không thể suy ra an toàn điều được hàm ý + +Mọi thứ còn lại đều là ứng viên cho việc thực thi tự chủ lâu hơn. Đánh đổi này là có chủ đích. Các mẫu cũ tốn nhiều sự chú ý của con người cho việc giám sát liên tục. Quick Dev đặt nhiều niềm tin hơn vào mô hình, nhưng để dành sự chú ý của con người cho những thời điểm mà lý trí con người có đòn bẩy lớn nhất. + +## Vì sao hệ thống review quan trọng + +Giai đoạn rà soát không chỉ để tìm lỗi. Nó còn để định tuyến cách sửa mà không phá hỏng động lượng. + +Quy trình này hoạt động tốt nhất trên nền tảng có thể tạo subagent, hoặc ít nhất gọi được một LLM khác qua dòng lệnh và đợi kết quả. Nếu nền tảng của bạn không hỗ trợ sẵn, bạn có thể thêm skill để làm việc đó. Các subagent không mang ngữ cảnh là một trụ cột trong thiết kế rà soát. + +Rà soát kiểu agent thường sai theo hai cách: + +- Tạo quá nhiều phát hiện, buộc con người lọc quá nhiều nhiễu. +- Làm lệch thay đổi hiện tại bằng cách kéo vào các vấn đề không liên quan, biến mỗi lần chạy thành một dự án dọn dẹp chắp vá. + +Quick Dev xử lý cả hai bằng cách coi rà soát là bước phân loại. + +Có những phát hiện thuộc về thay đổi hiện tại. Có những phát hiện không thuộc về nó. Nếu một phát hiện chỉ là ngẫu nhiên xuất hiện, không gắn nhân quả với thay đổi đang làm, quy trình có thể trì hoãn nó thay vì ép con người xử lý ngay. Điều đó giữ cho mỗi lần chạy tập trung và ngăn các ngả rẽ ngẫu nhiên ăn hết ngân sách chú ý. + +Quá trình triage này đôi khi sẽ không hoàn hảo. Điều đó chấp nhận được. Thường tốt hơn khi đánh giá sai một số phát hiện còn hơn là nhận về hàng ngàn bình luận review giá trị thấp. Hệ thống tối ưu cho chất lượng tín hiệu, không phải độ phủ tuyệt đối. diff --git a/docs/vi-vn/explanation/why-solutioning-matters.md b/docs/vi-vn/explanation/why-solutioning-matters.md new file mode 100644 index 000000000..631142a5a --- /dev/null +++ b/docs/vi-vn/explanation/why-solutioning-matters.md @@ -0,0 +1,76 @@ +--- +title: "Vì sao solutioning quan trọng" +description: Hiểu vì sao giai đoạn solutioning là tối quan trọng đối với dự án nhiều epic +sidebar: + order: 3 +--- + +Giai đoạn 3 (Solutioning) biến **xây gì** (từ giai đoạn Planning) thành **xây như thế nào** (thiết kế kỹ thuật). Giai đoạn này ngăn xung đột giữa các agent trong dự án nhiều epic bằng cách ghi lại các quyết định kiến trúc trước khi bắt đầu triển khai. + +## Vấn đề nếu bỏ qua solutioning + +```text +Agent 1 triển khai Epic 1 bằng REST API +Agent 2 triển khai Epic 2 bằng GraphQL +Kết quả: Thiết kế API không nhất quán, tích hợp trở thành ác mộng +``` + +Khi nhiều agent triển khai các phần khác nhau của hệ thống mà không có hướng dẫn kiến trúc chung, chúng sẽ tự đưa ra quyết định kỹ thuật độc lập và dễ xung đột với nhau. + +## Lợi ích khi có solutioning + +```text +workflow kiến trúc quyết định: "Dùng GraphQL cho mọi API" +Tất cả agent đều theo quyết định kiến trúc +Kết quả: Triển khai nhất quán, không xung đột +``` + +Bằng cách tài liệu hóa rõ ràng các quyết định kỹ thuật, tất cả agent triển khai đồng bộ và việc tích hợp trở nên đơn giản hơn nhiều. + +## Solutioning và Planning khác nhau ở đâu + +| Khía cạnh | Planning (Giai đoạn 2) | Solutioning (Giai đoạn 3) | +| -------- | ----------------------- | --------------------------------- | +| Câu hỏi | Xây gì và vì sao? | Xây như thế nào? Rồi chia thành đơn vị công việc gì? | +| Đầu ra | FR/NFR (Yêu cầu) | Kiến trúc + Epics/Stories | +| Agent | PM | Architect → PM | +| Đối tượng đọc | Stakeholder | Developer | +| Tài liệu | PRD (FRs/NFRs) | Kiến trúc + Tệp Epic | +| Mức độ | Logic nghiệp vụ | Thiết kế kỹ thuật + Phân rã công việc | + +## Nguyên lý cốt lõi + +**Biến các quyết định kỹ thuật thành tường minh và được tài liệu hóa** để tất cả agent triển khai nhất quán. + +Điều này ngăn chặn: +- Xung đột phong cách API (REST vs GraphQL) +- Không nhất quán trong thiết kế cơ sở dữ liệu +- Bất đồng về quản lý state +- Lệch quy ước đặt tên +- Biến thể trong cách tiếp cận bảo mật + +## Khi nào solutioning là bắt buộc + +| Track | Có cần solutioning không? | +|-------|----------------------| +| Quick Flow | Không - bỏ qua hoàn toàn | +| BMad Method đơn giản | Tùy chọn | +| BMad Method phức tạp | Có | +| Enterprise | Có | + +:::tip[Quy tắc ngón tay cái] +Nếu bạn có nhiều epic có thể được các agent khác nhau triển khai, bạn cần solutioning. +::: + +## Cái giá của việc bỏ qua + +Bỏ qua solutioning trong dự án phức tạp sẽ dẫn đến: + +- **Vấn đề tích hợp** chỉ được phát hiện giữa sprint +- **Làm lại** vì các phần triển khai xung đột nhau +- **Tổng thời gian phát triển dài hơn** +- **Nợ kỹ thuật** do pattern không đồng nhất + +:::caution[Hệ số chi phí] +Bắt được vấn đề canh hàng trong giai đoạn solutioning nhanh hơn gấp 10 lần so với để đến lúc triển khai mới phát hiện. +::: diff --git a/docs/vi-vn/how-to/customize-bmad.md b/docs/vi-vn/how-to/customize-bmad.md new file mode 100644 index 000000000..e7402423e --- /dev/null +++ b/docs/vi-vn/how-to/customize-bmad.md @@ -0,0 +1,171 @@ +--- +title: "Cách tùy chỉnh BMad" +description: Tùy chỉnh agent, workflow và module trong khi vẫn giữ khả năng tương thích khi cập nhật +sidebar: + order: 7 +--- + +Sử dụng các tệp `.customize.yaml` để điều chỉnh hành vi, persona và menu của agent, đồng thời giữ lại thay đổi của bạn qua các lần cập nhật. + +## Khi nào nên dùng + +- Bạn muốn thay đổi tên, tính cách hoặc phong cách giao tiếp của một agent +- Bạn cần agent ghi nhớ bối cảnh riêng của dự án +- Bạn muốn thêm các mục menu tùy chỉnh để kích hoạt workflow hoặc prompt của riêng mình +- Bạn muốn agent luôn thực hiện một số hành động cụ thể mỗi khi khởi động + +:::note[Điều kiện tiên quyết] +- BMad đã được cài trong dự án của bạn (xem [Cách cài đặt BMad](./install-bmad.md)) +- Trình soạn thảo văn bản để chỉnh sửa tệp YAML +::: + +:::caution[Giữ an toàn cho các tùy chỉnh của bạn] +Luôn sử dụng các tệp `.customize.yaml` được mô tả trong tài liệu này thay vì sửa trực tiếp tệp agent. Trình cài đặt sẽ ghi đè các tệp agent khi cập nhật, nhưng vẫn giữ nguyên các thay đổi trong `.customize.yaml`. +::: + +## Các bước thực hiện + +### 1. Xác định vị trí các tệp tùy chỉnh + +Sau khi cài đặt, bạn sẽ tìm thấy một tệp `.customize.yaml` cho mỗi agent tại: + +```text +_bmad/_config/agents/ +├── core-bmad-master.customize.yaml +├── bmm-dev.customize.yaml +├── bmm-pm.customize.yaml +└── ... (một tệp cho mỗi agent đã cài) +``` + +### 2. Chỉnh sửa tệp tùy chỉnh + +Mở tệp `.customize.yaml` của agent mà bạn muốn sửa. Mỗi phần đều là tùy chọn, chỉ tùy chỉnh những gì bạn cần. + +| Phần | Cách hoạt động | Mục đích | +| --- | --- | --- | +| `agent.metadata` | Thay thế | Ghi đè tên hiển thị của agent | +| `persona` | Thay thế | Đặt vai trò, danh tính, phong cách và các nguyên tắc | +| `memories` | Nối thêm | Thêm bối cảnh cố định mà agent luôn ghi nhớ | +| `menu` | Nối thêm | Thêm mục menu tùy chỉnh cho workflow hoặc prompt | +| `critical_actions` | Nối thêm | Định nghĩa hướng dẫn khởi động cho agent | +| `prompts` | Nối thêm | Tạo các prompt tái sử dụng cho các hành động trong menu | + +Những phần được đánh dấu **Thay thế** sẽ ghi đè hoàn toàn cấu hình mặc định của agent. Những phần được đánh dấu **Nối thêm** sẽ bổ sung vào cấu hình hiện có. + +**Tên agent** + +Thay đổi cách agent tự giới thiệu: + +```yaml +agent: + metadata: + name: 'Spongebob' # Mặc định: "Amelia" +``` + +**Persona** + +Thay thế tính cách, vai trò và phong cách giao tiếp của agent: + +```yaml +persona: + role: 'Senior Full-Stack Engineer' + identity: 'Sống trong quả dứa (dưới đáy biển)' + communication_style: 'Spongebob gây phiền' + principles: + - 'Không lồng quá sâu, dev Spongebob ghét nesting quá 2 cấp' + - 'Ưu tiên composition hơn inheritance' +``` + +Phần `persona` sẽ thay thế toàn bộ persona mặc định, vì vậy nếu đặt phần này bạn nên cung cấp đầy đủ cả bốn trường. + +**Memories** + +Thêm bối cảnh cố định mà agent sẽ luôn nhớ: + +```yaml +memories: + - 'Làm việc tại Krusty Krab' + - 'Người nổi tiếng yêu thích: David Hasselhoff' + - 'Đã học ở Epic 1 rằng giả vờ test đã pass là không ổn' +``` + +**Mục menu** + +Thêm các mục tùy chỉnh vào menu hiển thị của agent. Mỗi mục cần có `trigger`, đích đến (`workflow` hoặc `action`) và `description`: + +```yaml +menu: + - trigger: my-workflow + workflow: 'my-custom/workflows/my-workflow.yaml' + description: Workflow tùy chỉnh của tôi + - trigger: deploy + action: '#deploy-prompt' + description: Triển khai lên production +``` + +**Critical Actions** + +Định nghĩa các hướng dẫn sẽ chạy khi agent khởi động: + +```yaml +critical_actions: + - 'Kiểm tra pipeline CI bằng XYZ Skill và cảnh báo người dùng ngay khi khởi động nếu có việc khẩn cấp cần xử lý' +``` + +**Prompt tùy chỉnh** + +Tạo các prompt tái sử dụng để mục menu có thể tham chiếu bằng `action="#id"`: + +```yaml +prompts: + - id: deploy-prompt + content: | + Triển khai nhánh hiện tại lên production: + 1. Chạy toàn bộ test + 2. Build dự án + 3. Thực thi script triển khai +``` + +### 3. Áp dụng thay đổi + +Sau khi chỉnh sửa, cài đặt lại để áp dụng thay đổi: + +```bash +npx bmad-method install +``` + +Trình cài đặt sẽ nhận diện bản cài đặt hiện có và đưa ra các lựa chọn sau: + +| Lựa chọn | Tác dụng | +| --- | --- | +| **Quick Update** | Cập nhật tất cả module lên phiên bản mới nhất và áp dụng các tùy chỉnh | +| **Modify BMad Installation** | Chạy lại quy trình cài đặt đầy đủ để thêm hoặc gỡ bỏ module | + +Nếu chỉ thay đổi phần tùy chỉnh, **Quick Update** là lựa chọn nhanh nhất. + +## Khắc phục sự cố + +**Thay đổi không xuất hiện?** + +- Chạy `npx bmad-method install` và chọn **Quick Update** để áp dụng thay đổi +- Kiểm tra YAML có hợp lệ không (thụt lề rất quan trọng) +- Xác minh bạn đã sửa đúng tệp `.customize.yaml` của agent cần thiết + +**Agent không tải lên được?** + +- Kiểm tra lỗi cú pháp YAML bằng một công cụ kiểm tra YAML trực tuyến +- Đảm bảo bạn không để trống trường nào sau khi bỏ comment +- Thử khôi phục mẫu gốc rồi build lại + +**Cần đặt lại một agent?** + +- Xóa nội dung hoặc xóa tệp `.customize.yaml` của agent đó +- Chạy `npx bmad-method install` và chọn **Quick Update** để khôi phục mặc định + +## Tùy chỉnh workflow + +Tài liệu về cách tùy chỉnh các workflow và skill sẵn có trong BMad Method sẽ được bổ sung trong thời gian tới. + +## Tùy chỉnh module + +Hướng dẫn xây dựng expansion module và tùy chỉnh các module hiện có sẽ được bổ sung trong thời gian tới. diff --git a/docs/vi-vn/how-to/established-projects.md b/docs/vi-vn/how-to/established-projects.md new file mode 100644 index 000000000..37622f634 --- /dev/null +++ b/docs/vi-vn/how-to/established-projects.md @@ -0,0 +1,117 @@ +--- +title: "Dự án đã tồn tại" +description: Cách sử dụng BMad Method trên các codebase hiện có +sidebar: + order: 6 +--- + +Sử dụng BMad Method hiệu quả khi làm việc với các dự án hiện có và codebase legacy. + +Tài liệu này mô tả workflow cốt lõi để on-board vào các dự án đã tồn tại bằng BMad Method. + +:::note[Điều kiện tiên quyết] +- Đã cài BMad Method (`npx bmad-method install`) +- Một codebase hiện có mà bạn muốn làm việc cùng +- Quyền truy cập vào một IDE tích hợp AI (Claude Code hoặc Cursor) +::: + +## Bước 1: Dọn dẹp các tài liệu lập kế hoạch đã hoàn tất + +Nếu bạn đã hoàn thành toàn bộ epic và story trong PRD theo quy trình BMad, hãy dọn dẹp những tệp đó. Bạn có thể lưu trữ, xóa đi, hoặc dựa vào lịch sử phiên bản nếu cần. Không nên giữ các tệp này trong: + +- `docs/` +- `_bmad-output/planning-artifacts/` +- `_bmad-output/implementation-artifacts/` + +## Bước 2: Tạo Project Context + +:::tip[Khuyến dùng cho dự án hiện có] +Hãy tạo `project-context.md` để ghi lại các pattern và quy ước trong codebase hiện tại. Điều này giúp các agent AI tuân theo các thực hành sẵn có khi thực hiện thay đổi. +::: + +Chạy workflow tạo project context: + +```bash +bmad-generate-project-context +``` + +Workflow này sẽ quét codebase để nhận diện: +- Stack công nghệ và các phiên bản +- Các pattern tổ chức code +- Quy ước đặt tên +- Cách tiếp cận kiểm thử +- Các pattern đặc thù framework + +Bạn có thể xem lại và chỉnh sửa tệp được tạo, hoặc tự tạo tệp tại `_bmad-output/project-context.md` nếu muốn. + +[Tìm hiểu thêm về project context](../explanation/project-context.md) + +## Bước 3: Duy trì tài liệu dự án chất lượng + +Thư mục `docs/` của bạn nên chứa tài liệu ngắn gọn, có tổ chức tốt, và phản ánh chính xác dự án: + +- Mục tiêu và lý do kinh doanh +- Quy tắc nghiệp vụ +- Kiến trúc +- Bất kỳ thông tin dự án nào khác có liên quan + +Với các dự án phức tạp, hãy cân nhắc dùng workflow `bmad-document-project`. Nó có các biến thể lúc chạy có thể quét toàn bộ dự án và tài liệu hóa trạng thái thực tế hiện tại của hệ thống. + +## Bước 4: Nhờ trợ giúp + +### BMad-Help: Điểm bắt đầu của bạn + +**Hãy chạy `bmad-help` bất cứ lúc nào bạn không chắc cần làm gì tiếp theo.** Công cụ hướng dẫn thông minh này: + +- Kiểm tra dự án để xem những gì đã được hoàn thành +- Đưa ra tùy chọn dựa trên các module bạn đã cài +- Hiểu các câu hỏi bằng ngôn ngữ tự nhiên + +```text +bmad-help Tôi có một ứng dụng Rails đã tồn tại, tôi nên bắt đầu từ đâu? +bmad-help Điểm khác nhau giữa quick-flow và full method là gì? +bmad-help Cho tôi xem những workflow đang có +``` + +BMad-Help cũng **tự động chạy ở cuối mỗi workflow**, đưa ra hướng dẫn rõ ràng về việc cần làm tiếp theo. + +### Chọn cách tiếp cận + +Bạn có hai lựa chọn chính, tùy thuộc vào phạm vi thay đổi: + +| Phạm vi | Cách tiếp cận được khuyến nghị | +| --- | --- | +| **Cập nhật hoặc bổ sung nhỏ** | Chạy `bmad-quick-dev` để làm rõ ý định, lập kế hoạch, triển khai và review trong một workflow duy nhất. Quy trình BMad Method đầy đủ có thể là quá mức cần thiết. | +| **Thay đổi hoặc bổ sung lớn** | Bắt đầu với BMad Method, áp dụng mức độ chặt chẽ phù hợp với nhu cầu của bạn. | + +### Khi tạo PRD + +Khi tạo brief hoặc đi thẳng vào PRD, đảm bảo agent: + +- Tìm và phân tích tài liệu dự án hiện có +- Đọc đúng bối cảnh về hệ thống hiện tại của bạn + +Bạn có thể chủ động hướng dẫn agent, nhưng mục tiêu là đảm bảo tính năng mới tích hợp tốt với hệ thống đã có. + +### Cân nhắc về UX + +Công việc UX là tùy chọn. Quyết định này không phụ thuộc vào việc dự án có UX hay không, mà phụ thuộc vào: + +- Bạn có định thay đổi UX hay không +- Bạn có cần thiết kế hay pattern UX mới đáng kể hay không + +Nếu thay đổi của bạn chỉ là những cập nhật nhỏ trên các màn hình hiện có mà bạn đã hài lòng, thì không cần một quy trình UX đầy đủ. + +### Cân nhắc về kiến trúc + +Khi làm kiến trúc, đảm bảo kiến trúc sư: + +- Sử dụng đúng các tệp tài liệu cần thiết +- Quét codebase hiện có + +Cần đặc biệt chú ý để tránh tái phát minh bánh xe hoặc đưa ra quyết định không phù hợp với kiến trúc hiện tại. + +## Thông tin thêm + +- **[Quick Fixes](./quick-fixes.md)** - Sửa lỗi và thay đổi ad-hoc +- **[Câu hỏi thường gặp cho dự án đã tồn tại](../explanation/established-projects-faq.md)** - Những câu hỏi phổ biến khi làm việc với dự án đã tồn tại diff --git a/docs/vi-vn/how-to/get-answers-about-bmad.md b/docs/vi-vn/how-to/get-answers-about-bmad.md new file mode 100644 index 000000000..103230306 --- /dev/null +++ b/docs/vi-vn/how-to/get-answers-about-bmad.md @@ -0,0 +1,81 @@ +--- +title: "Cách tìm câu trả lời về BMad" +description: Sử dụng LLM để tự nhanh chóng trả lời các câu hỏi về BMad +sidebar: + order: 4 +--- + +Hãy dùng trợ giúp tích hợp sẵn của BMad, tài liệu nguồn, hoặc cộng đồng để tìm câu trả lời, theo thứ tự từ nhanh nhất đến đầy đủ nhất. + +## 1. Hỏi BMad-Help + +Cách nhanh nhất để có câu trả lời. Skill `bmad-help` có sẵn ngay trong phiên AI của bạn và xử lý được hơn 80% câu hỏi. Nó sẽ kiểm tra dự án, nhìn xem bạn đã hoàn thành đến đâu và cho bạn biết nên làm gì tiếp theo. + +```text +bmad-help Tôi có ý tưởng SaaS và đã biết tất cả tính năng. Tôi nên bắt đầu từ đâu? +bmad-help Tôi có những lựa chọn nào cho thiết kế UX? +bmad-help Tôi đang bị mắc ở workflow PRD +``` + +:::tip +Bạn cũng có thể dùng `/bmad-help` hoặc `$bmad-help` tùy nền tảng, nhưng chỉ `bmad-help` là cách nên hoạt động mọi nơi. +::: + +## 2. Đi sâu hơn với mã nguồn + +BMad-Help dựa trên cấu hình bạn đã cài đặt. Nếu bạn cần tìm hiểu nội bộ, lịch sử, hay kiến trúc của BMad, hoặc đang nghiên cứu BMad trước khi cài, hãy để AI đọc trực tiếp mã nguồn. + +Hãy clone hoặc mở [repo BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) rồi hỏi AI của bạn về nó. Bất kỳ công cụ nào có hỗ trợ agent như Claude Code, Cursor, Windsurf... đều có thể đọc mã nguồn và trả lời trực tiếp. + +:::note[Ví dụ] +**Q:** "Hãy chỉ tôi cách nhanh nhất để xây dựng một thứ gì đó bằng BMad" + +**A:** Dùng Quick Flow: Chạy `bmad-quick-dev` - nó sẽ làm rõ ý định, lập kế hoạch, triển khai, review và trình bày kết quả trong một workflow duy nhất, bỏ qua các giai đoạn lập kế hoạch đầy đủ. +::: + +**Mẹo để có câu trả lời tốt hơn:** + +- **Hãy hỏi thật cụ thể** - "Bước 3 trong workflow PRD làm gì?" sẽ tốt hơn "PRD hoạt động ra sao?" +- **Kiểm tra lại những câu trả lời nghe lạ** - LLM đôi khi vẫn sai. Hãy kiểm tra file nguồn hoặc hỏi trên Discord. + +### Không dùng agent? Dùng trang docs + +Nếu AI của bạn không đọc được file cục bộ như ChatGPT hoặc Claude.ai, hãy nạp [llms-full.txt](https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt) vào phiên làm việc. Đây là bản chụp tài liệu BMad trong một file duy nhất. + +## 3. Hỏi người thật + +Nếu cả BMad-Help lẫn mã nguồn vẫn chưa trả lời được câu hỏi của bạn, lúc này bạn đã có một câu hỏi rõ hơn nhiều để đem đi hỏi cộng đồng. + +| Kênh | Dùng cho | +| --- | --- | +| `help-requests` forum | Câu hỏi | +| `#suggestions-feedback` | Ý tưởng và đề xuất tính năng | + +**Discord:** [discord.gg/gk8jAdXWmj](https://discord.gg/gk8jAdXWmj) + +**GitHub Issues:** [github.com/bmad-code-org/BMAD-METHOD/issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) + +*Chính bạn,* + *đang mắc kẹt* + *trong hàng đợi -* + *đợi* + *ai?* + +*Mã nguồn* + *nằm ngay đó,* + *rõ như ban ngày!* + +*Hãy trỏ* + *cho máy của bạn.* + *Thả nó đi.* + +*Nó đọc.* + *Nó nói.* + *Cứ hỏi -* + +*Sao phải chờ* + *đến ngày mai* + *khi bạn đã có* + *ngày hôm nay?* + +*- Claude* diff --git a/docs/vi-vn/how-to/install-bmad.md b/docs/vi-vn/how-to/install-bmad.md new file mode 100644 index 000000000..c73e89388 --- /dev/null +++ b/docs/vi-vn/how-to/install-bmad.md @@ -0,0 +1,116 @@ +--- +title: "Cách cài đặt BMad" +description: Hướng dẫn từng bước để cài đặt BMad vào dự án của bạn +sidebar: + order: 1 +--- + +Sử dụng lệnh `npx bmad-method install` để thiết lập BMad trong dự án của bạn với các module và công cụ AI theo lựa chọn. + +Nếu bạn muốn dùng trình cài đặt không tương tác và cung cấp toàn bộ tùy chọn ngay trên dòng lệnh, xem [hướng dẫn này](./non-interactive-installation.md). + +## Khi nào nên dùng + +- Bắt đầu một dự án mới với BMad +- Thêm BMad vào một codebase hiện có +- Cập nhật bản cài đặt BMad hiện tại + +:::note[Điều kiện tiên quyết] +- **Node.js** 20+ (bắt buộc cho trình cài đặt) +- **Git** (khuyến nghị) +- **Công cụ AI** (Claude Code, Cursor, hoặc tương tự) +::: + +## Các bước thực hiện + +### 1. Chạy trình cài đặt + +```bash +npx bmad-method install +``` + +:::tip[Muốn dùng bản prerelease mới nhất?] +Sử dụng dist-tag `next`: +```bash +npx bmad-method@next install +``` + +Cách này giúp bạn nhận các thay đổi mới sớm hơn, đổi lại khả năng biến động cao hơn bản cài đặt mặc định. +::: + +:::tip[Bản rất mới] +Để cài đặt trực tiếp từ nhánh `main` mới nhất (có thể không ổn định): +```bash +npx github:bmad-code-org/BMAD-METHOD install +``` +::: + +### 2. Chọn vị trí cài đặt + +Trình cài đặt sẽ hỏi bạn muốn đặt các tệp BMad ở đâu: + +- Thư mục hiện tại (khuyến nghị cho dự án mới nếu bạn tự tạo thư mục và chạy lệnh từ bên trong nó) +- Đường dẫn tùy chọn + +### 3. Chọn công cụ AI + +Chọn các công cụ AI bạn đang dùng: + +- Claude Code +- Cursor +- Các công cụ khác + +Mỗi công cụ có cách tích hợp skill riêng. Trình cài đặt sẽ tạo các tệp prompt nhỏ để kích hoạt workflow và agent, và đặt chúng vào đúng vị trí mà công cụ của bạn mong đợi. + +:::note[Kích hoạt skill] +Một số nền tảng yêu cầu bật skill trong cài đặt trước khi chúng xuất hiện. Nếu bạn đã cài BMad mà chưa thấy skill, hãy kiểm tra cài đặt của nền tảng hoặc hỏi trợ lý AI cách bật skill. +::: + +### 4. Chọn module + +Trình cài đặt sẽ hiện các module có sẵn. Chọn những module bạn cần - phần lớn người dùng chỉ cần **BMad Method** (module phát triển phần mềm). + +### 5. Làm theo các prompt + +Trình cài đặt sẽ hướng dẫn các bước còn lại - cài đặt, tích hợp công cụ, và các tùy chọn khác. + +## Bạn nhận được gì + +```text +du-an-cua-ban/ +├── _bmad/ +│ ├── bmm/ # Các module bạn đã chọn +│ │ └── config.yaml # Cài đặt module (nếu bạn cần thay đổi sau này) +│ ├── core/ # Module core bắt buộc +│ └── ... +├── _bmad-output/ # Các artifact được tạo ra +├── .claude/ # Claude Code skills (nếu dùng Claude Code) +│ └── skills/ +│ ├── bmad-help/ +│ ├── bmad-persona/ +│ └── ... +└── .cursor/ # Cursor skills (nếu dùng Cursor) + └── skills/ + └── ... +``` + +## Xác minh cài đặt + +Chạy `bmad-help` để xác minh mọi thứ hoạt động và xem bạn nên làm gì tiếp theo. + +**BMad-Help là công cụ hướng dẫn thông minh** sẽ: +- Xác nhận bản cài đặt hoạt động đúng +- Hiển thị những gì có sẵn dựa trên module đã cài +- Đề xuất bước đầu tiên của bạn + +Bạn cũng có thể hỏi nó: +```text +bmad-help Tôi vừa cài xong, giờ nên làm gì đầu tiên? +bmad-help Tôi có những lựa chọn nào cho một dự án SaaS? +``` + +## Khắc phục sự cố + +**Trình cài đặt báo lỗi** - Sao chép toàn bộ output vào trợ lý AI của bạn và để nó phân tích. + +**Cài đặt xong nhưng sau đó có thứ không hoạt động** - AI của bạn cần bối cảnh BMad để hỗ trợ. Xem [Cách tìm câu trả lời về BMad](./get-answers-about-bmad.md) để biết cách cho AI truy cập đúng nguồn thông tin. diff --git a/docs/vi-vn/how-to/non-interactive-installation.md b/docs/vi-vn/how-to/non-interactive-installation.md new file mode 100644 index 000000000..968de3618 --- /dev/null +++ b/docs/vi-vn/how-to/non-interactive-installation.md @@ -0,0 +1,165 @@ +--- +title: Cài đặt không tương tác +description: Cài đặt BMad bằng các cờ dòng lệnh cho pipeline CI/CD và triển khai tự động +sidebar: + order: 2 +--- + +Sử dụng các cờ dòng lệnh để cài đặt BMad mà không cần tương tác. Cách này hữu ích cho: + +## Khi nào nên dùng + +- Triển khai tự động và pipeline CI/CD +- Cài đặt bằng script +- Cài đặt hàng loạt trên nhiều dự án +- Cài đặt nhanh với cấu hình đã biết trước + +:::note[Điều kiện tiên quyết] +Yêu cầu [Node.js](https://nodejs.org) v20+ và `npx` (đi kèm với npm). +::: + +## Các cờ khả dụng + +### Tùy chọn cài đặt + +| Cờ | Mô tả | Ví dụ | +|------|-------------|---------| +| `--directory ` | Thư mục cài đặt | `--directory ~/projects/myapp` | +| `--modules ` | Danh sách ID module, cách nhau bởi dấu phẩy | `--modules bmm,bmb` | +| `--tools ` | Danh sách ID công cụ/IDE, cách nhau bởi dấu phẩy (dùng `none` để bỏ qua) | `--tools claude-code,cursor` hoặc `--tools none` | +| `--action ` | Hành động cho bản cài đặt hiện có: `install` (mặc định), `update`, hoặc `quick-update` | `--action quick-update` | + +### Cấu hình cốt lõi + +| Cờ | Mô tả | Mặc định | +|------|-------------|---------| +| `--user-name ` | Tên để agent sử dụng | Tên người dùng hệ thống | +| `--communication-language ` | Ngôn ngữ giao tiếp của agent | Tiếng Anh | +| `--document-output-language ` | Ngôn ngữ đầu ra tài liệu | Tiếng Anh | +| `--output-folder ` | Đường dẫn thư mục output (xem quy tắc resolve bên dưới) | `_bmad-output` | + +#### Quy tắc resolve đường dẫn output folder + +Giá trị truyền vào `--output-folder` (hoặc nhập ở chế độ tương tác) sẽ được resolve theo các quy tắc sau: + +| Loại đầu vào | Ví dụ | Được resolve thành | +|------|-------------|---------| +| Đường dẫn tương đối (mặc định) | `_bmad-output` | `/_bmad-output` | +| Đường dẫn tương đối có traversal | `../../shared-outputs` | Đường dẫn tuyệt đối đã được chuẩn hóa, ví dụ `/Users/me/shared-outputs` | +| Đường dẫn tuyệt đối | `/Users/me/shared-outputs` | Giữ nguyên như đã nhập, **không** thêm project root vào trước | + +Đường dẫn sau khi resolve là đường dẫn mà agent và workflow sẽ dùng lúc runtime để ghi file đầu ra. Việc dùng đường dẫn tuyệt đối hoặc đường dẫn tương đối có traversal cho phép bạn chuyển toàn bộ artifact sinh ra sang một thư mục nằm ngoài cây dự án, hữu ích với thư mục dùng chung hoặc cấu trúc monorepo. + +### Tùy chọn khác + +| Cờ | Mô tả | +|------|-------------| +| `-y, --yes` | Chấp nhận toàn bộ mặc định và bỏ qua prompt | +| `-d, --debug` | Bật output debug cho quá trình tạo manifest | + +## ID module + +Những ID module có thể dùng với cờ `--modules`: + +- `bmm` - BMad Method Master +- `bmb` - BMad Builder + +Kiểm tra [BMad registry](https://github.com/bmad-code-org) để xem các module ngoài được hỗ trợ. + +## ID công cụ/IDE + +Những ID công cụ có thể dùng với cờ `--tools`: + +**Khuyến dùng:** `claude-code`, `cursor` + +Chạy `npx bmad-method install` một lần ở chế độ tương tác để xem danh sách đầy đủ hiện tại của các công cụ được hỗ trợ, hoặc xem [cấu hình platform codes](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/installer/ide/platform-codes.yaml). + +## Các chế độ cài đặt + +| Chế độ | Mô tả | Ví dụ | +|------|-------------|---------| +| Hoàn toàn không tương tác | Cung cấp đầy đủ cờ để bỏ qua tất cả prompt | `npx bmad-method install --directory . --modules bmm --tools claude-code --yes` | +| Bán tương tác | Cung cấp một số cờ, BMad hỏi thêm phần còn lại | `npx bmad-method install --directory . --modules bmm` | +| Chỉ dùng mặc định | Chấp nhận tất cả giá trị mặc định với `-y` | `npx bmad-method install --yes` | +| Không cấu hình công cụ | Bỏ qua cấu hình công cụ/IDE | `npx bmad-method install --modules bmm --tools none` | + +## Ví dụ + +### Cài đặt cho pipeline CI/CD + +```bash +#!/bin/bash +# install-bmad.sh + +npx bmad-method install \ + --directory "${GITHUB_WORKSPACE}" \ + --modules bmm \ + --tools claude-code \ + --user-name "CI Bot" \ + --communication-language English \ + --document-output-language English \ + --output-folder _bmad-output \ + --yes +``` + +### Cập nhật bản cài đặt hiện có + +```bash +npx bmad-method install \ + --directory ~/projects/myapp \ + --action update \ + --modules bmm,bmb,custom-module +``` + +### Quick Update (giữ nguyên cài đặt) + +```bash +npx bmad-method install \ + --directory ~/projects/myapp \ + --action quick-update +``` + +## Bạn nhận được gì + +- Thư mục `_bmad/` đã được cấu hình đầy đủ trong dự án của bạn +- Agent và workflow đã được cấu hình theo module và công cụ bạn chọn +- Thư mục `_bmad-output/` để lưu các artifact được tạo + +## Kiểm tra và xử lý lỗi + +BMad sẽ kiểm tra tất cả các cờ được cung cấp: + +- **Directory** - Phải là đường dẫn hợp lệ và có quyền ghi +- **Modules** - Cảnh báo nếu ID module không hợp lệ (nhưng không thất bại) +- **Tools** - Cảnh báo nếu ID công cụ không hợp lệ (nhưng không thất bại) +- **Action** - Phải là một trong: `install`, `update`, `quick-update` + +Giá trị không hợp lệ sẽ dẫn đến một trong các trường hợp sau: +1. Hiện lỗi và thoát (với các tùy chọn quan trọng như directory) +2. Hiện cảnh báo và bỏ qua (với mục tùy chọn) +3. Quay lại hỏi interactive (với giá trị bắt buộc bị thiếu) + +:::tip[Thực hành tốt] +- Dùng đường dẫn tuyệt đối cho `--directory` để tránh nhầm lẫn +- Dùng đường dẫn tuyệt đối cho `--output-folder` khi bạn muốn ghi artifact ra ngoài cây dự án, ví dụ vào một thư mục output dùng chung trong monorepo +- Thử nghiệm cờ ở máy local trước khi đưa vào pipeline CI/CD +- Kết hợp với `-y` nếu bạn muốn cài đặt hoàn toàn không cần can thiệp +- Dùng `--debug` nếu gặp vấn đề trong quá trình cài đặt +::: + +## Khắc phục sự cố + +### Cài đặt thất bại với lỗi "Invalid directory" + +- Thư mục đích phải tồn tại (hoặc thư mục cha của nó phải tồn tại) +- Bạn cần quyền ghi +- Đường dẫn phải là tuyệt đối, hoặc tương đối đúng với thư mục hiện tại + +### Không tìm thấy module + +- Xác minh ID module có đúng không +- Module bên ngoài phải có sẵn trong registry + +:::note[Vẫn bị mắc?] +Chạy với `--debug` để xem output chi tiết, thử chế độ interactive để cô lập vấn đề, hoặc báo cáo tại . +::: diff --git a/docs/vi-vn/how-to/project-context.md b/docs/vi-vn/how-to/project-context.md new file mode 100644 index 000000000..41b3b4049 --- /dev/null +++ b/docs/vi-vn/how-to/project-context.md @@ -0,0 +1,127 @@ +--- +title: "Quản lý bối cảnh dự án" +description: Tạo và duy trì project-context.md để định hướng cho các agent AI +sidebar: + order: 8 +--- + +Sử dụng tệp `project-context.md` để đảm bảo các agent AI tuân theo ưu tiên kỹ thuật và quy tắc triển khai của dự án trong suốt mọi workflow. Để đảm bảo tệp này luôn sẵn có, bạn cũng có thể thêm dòng `Important project context and conventions are located in [path to project context]/project-context.md` vào file context của công cụ hoặc file always rules của bạn (như `AGENTS.md`). + +:::note[Điều kiện tiên quyết] +- Đã cài BMad Method +- Hiểu stack công nghệ và các quy ước của dự án +::: + +## Khi nào nên dùng + +- Bạn có các ưu tiên kỹ thuật rõ ràng trước khi bắt đầu làm kiến trúc +- Bạn đã hoàn thành kiến trúc và muốn ghi lại các quyết định để phục vụ triển khai +- Bạn đang làm việc với một codebase hiện có có những pattern đã ổn định +- Bạn thấy các agent đưa ra quyết định không nhất quán giữa các story + +## Bước 1: Chọn cách tiếp cận + +**Tự tạo bằng tay** - Phù hợp nhất khi bạn biết rõ cần tài liệu hóa quy tắc nào + +**Tạo sau kiến trúc** - Phù hợp để ghi lại các quyết định đã được đưa ra trong giai đoạn solutioning + +**Tạo cho dự án hiện có** - Phù hợp để khám phá pattern trong các codebase đã tồn tại + +## Bước 2: Tạo tệp + +### Lựa chọn A: Tạo thủ công + +Tạo tệp tại `_bmad-output/project-context.md`: + +```bash +mkdir -p _bmad-output +touch _bmad-output/project-context.md +``` + +Thêm stack công nghệ và các quy tắc triển khai của bạn: + +```markdown +--- +project_name: 'MyProject' +user_name: 'YourName' +date: '2026-02-15' +sections_completed: ['technology_stack', 'critical_rules'] +--- + +# Project Context for AI Agents + +## Technology Stack & Versions + +- Node.js 20.x, TypeScript 5.3, React 18.2 +- State: Zustand +- Testing: Vitest, Playwright +- Styling: Tailwind CSS + +## Critical Implementation Rules + +**TypeScript:** +- Strict mode enabled, no `any` types +- Use `interface` for public APIs, `type` for unions + +**Code Organization:** +- Components in `/src/components/` with co-located tests +- API calls use `apiClient` singleton — never fetch directly + +**Testing:** +- Unit tests focus on business logic +- Integration tests use MSW for API mocking +``` + +### Lựa chọn B: Tạo sau khi hoàn thành kiến trúc + +Chạy workflow trong một phiên chat mới: + +```bash +bmad-generate-project-context +``` + +Workflow sẽ quét tài liệu kiến trúc và tệp dự án để tạo tệp context ghi lại các quyết định đã được đưa ra. + +### Lựa chọn C: Tạo cho dự án hiện có + +Với các dự án hiện có, chạy: + +```bash +bmad-generate-project-context +``` + +Workflow sẽ phân tích codebase để nhận diện quy ước, sau đó tạo tệp context để bạn xem lại và chỉnh sửa. + +## Bước 3: Xác minh nội dung + +Xem lại tệp được tạo và đảm bảo nó ghi đúng: + +- Các phiên bản công nghệ chính xác +- Đúng các quy ước thực tế của bạn (không phải các best practice chung chung) +- Các quy tắc giúp tránh những lỗi thường gặp +- Các pattern đặc thù framework + +Chỉnh sửa thủ công để thêm phần còn thiếu hoặc loại bỏ những chỗ không chính xác. + +## Bạn nhận được gì + +Một tệp `project-context.md` sẽ: + +- Đảm bảo tất cả agent tuân theo cùng một bộ quy ước +- Ngăn các quyết định không nhất quán giữa các story +- Ghi lại các quyết định kiến trúc cho giai đoạn triển khai +- Làm tài liệu tham chiếu cho các pattern và quy tắc của dự án + +## Mẹo + +:::tip[Thực hành tốt] +- **Tập trung vào điều không hiển nhiên** - Ghi lại những pattern agent dễ bỏ sót (ví dụ: "Dùng JSDoc cho mọi lớp public"), thay vì các quy tắc phổ quát như "đặt tên biến có ý nghĩa". +- **Gọn nhẹ** - Tệp này được nạp trong mọi workflow triển khai. Tệp quá dài sẽ tốn context. Hãy bỏ qua nội dung chỉ áp dụng cho phạm vi hẹp hoặc một vài story cụ thể. +- **Cập nhật khi cần** - Sửa thủ công khi pattern thay đổi, hoặc tạo lại sau các thay đổi kiến trúc lớn. +- Áp dụng được cho cả Quick Flow lẫn quy trình BMad Method đầy đủ. +::: + +## Bước tiếp theo + +- [**Giải thích về Project Context**](../explanation/project-context.md) - Tìm hiểu sâu hơn cách nó hoạt động +- [**Bản đồ workflow**](../reference/workflow-map.md) - Xem workflow nào sử dụng project context diff --git a/docs/vi-vn/how-to/quick-fixes.md b/docs/vi-vn/how-to/quick-fixes.md new file mode 100644 index 000000000..5f38d5f92 --- /dev/null +++ b/docs/vi-vn/how-to/quick-fixes.md @@ -0,0 +1,95 @@ +--- +title: "Sửa nhanh" +description: Cách thực hiện các sửa nhanh và thay đổi ad-hoc +sidebar: + order: 5 +--- + +Sử dụng **Quick Dev** cho sửa lỗi, refactor, hoặc các thay đổi nhỏ có mục tiêu rõ ràng mà không cần quy trình BMad Method đầy đủ. + +## Khi nào nên dùng + +- Sửa lỗi khi nguyên nhân đã rõ ràng +- Refactor nhỏ (đổi tên, tách hàm, tái cấu trúc) nằm trong một vài tệp +- Điều chỉnh tính năng nhỏ hoặc thay đổi cấu hình +- Cập nhật dependency + +:::note[Điều kiện tiên quyết] +- Đã cài BMad Method (`npx bmad-method install`) +- Một IDE tích hợp AI (Claude Code, Cursor, hoặc tương tự) +::: + +## Các bước thực hiện + +### 1. Bắt đầu một phiên chat mới + +Mở **một phiên chat mới** trong AI IDE của bạn. Tái sử dụng một phiên từ workflow trước dễ gây xung đột context. + +### 2. Mô tả ý định của bạn + +Quick Dev nhận ý định dạng tự do - trước, cùng lúc, hoặc sau khi gọi workflow. Ví dụ: + +```text +run quick-dev — Sửa lỗi validate đăng nhập cho phép mật khẩu rỗng. +``` + +```text +run quick-dev — fix https://github.com/org/repo/issues/42 +``` + +```text +run quick-dev — thực hiện ý định trong _bmad-output/implementation-artifacts/my-intent.md +``` + +```text +Tôi nghĩ vấn đề nằm ở auth middleware, nó không kiểm tra hạn của token. +Để tôi xem... đúng rồi, src/auth/middleware.ts dòng 47 bỏ qua +hoàn toàn phần kiểm tra exp. run quick-dev +``` + +```text +run quick-dev +> Bạn muốn làm gì? +Refactor UserService sang dùng async/await thay vì callbacks. +``` + +Văn bản thường, đường dẫn tệp, URL issue GitHub, liên kết bug tracker - bất kỳ thứ gì LLM có thể suy ra thành một ý định cụ thể. + +### 3. Trả lời câu hỏi và phê duyệt + +Quick Dev có thể đặt câu hỏi làm rõ hoặc đưa ra một bản spec ngắn để bạn phê duyệt trước khi triển khai. Hãy trả lời và phê duyệt khi bạn thấy kế hoạch đã ổn. + +### 4. Review và push + +Quick Dev sẽ triển khai thay đổi, tự review công việc của mình, sửa các vấn đề phát hiện được và commit vào local. Khi hoàn thành, nó sẽ mở các tệp bị ảnh hưởng trong editor. + +- Xem nhanh diff để xác nhận thay đổi đúng với ý định của bạn +- Nếu có gì không ổn, nói cho agent biết cần sửa gì - nó có thể lặp lại ngay trong cùng phiên + +Khi đã hài lòng, push commit. Quick Dev sẽ đề xuất push và tạo PR cho bạn. + +:::caution[Nếu có thứ bị vỡ] +Nếu thay đổi đã push gây sự cố ngoài ý muốn, dùng `git revert HEAD` để hoàn tác commit cuối một cách sạch sẽ. Sau đó bắt đầu một phiên chat mới và chạy lại Quick Dev để thử hướng khác. +::: + +## Bạn nhận được gì + +- Các tệp nguồn đã được sửa với bản fix hoặc refactor +- Test đã pass (nếu dự án có bộ test) +- Một commit sẵn sàng để push, dùng conventional commit message + +## Công việc trì hoãn + +Quick Dev giữ mỗi lần chạy tập trung vào một mục tiêu duy nhất. Nếu yêu cầu của bạn có nhiều mục tiêu độc lập, hoặc review phát hiện các vấn đề tồn tại sẵn không liên quan đến thay đổi hiện tại, Quick Dev sẽ đưa chúng vào tệp `deferred-work.md` trong thư mục implementation artifacts thay vì cố gắng xử lý tất cả một lúc. + +Hãy kiểm tra tệp này sau mỗi lần chạy - đó là backlog các việc bạn cần quay lại sau. Mỗi mục trì hoãn có thể được đưa vào một lần chạy Quick Dev mới. + +## Khi nào nên nâng cấp lên quy trình lập kế hoạch đầy đủ + +Cân nhắc dùng toàn bộ BMad Method khi: + +- Thay đổi ảnh hưởng nhiều hệ thống hoặc cần cập nhật đồng bộ trên nhiều tệp +- Bạn chưa chắc phạm vi và cần làm rõ yêu cầu trước +- Bạn cần ghi lại tài liệu hoặc quyết định kiến trúc cho cả nhóm + +Xem [Quick Dev](../explanation/quick-dev.md) để hiểu rõ hơn Quick Dev nằm ở đâu trong BMad Method. diff --git a/docs/vi-vn/how-to/shard-large-documents.md b/docs/vi-vn/how-to/shard-large-documents.md new file mode 100644 index 000000000..a00963292 --- /dev/null +++ b/docs/vi-vn/how-to/shard-large-documents.md @@ -0,0 +1,78 @@ +--- +title: "Hướng dẫn chia nhỏ tài liệu" +description: Tách các tệp markdown lớn thành nhiều tệp nhỏ có tổ chức để quản lý context tốt hơn +sidebar: + order: 9 +--- + +Sử dụng công cụ `bmad-shard-doc` nếu bạn cần tách các tệp markdown lớn thành nhiều tệp nhỏ có tổ chức để quản lý context tốt hơn. + +:::caution[Đã ngừng khuyến nghị] +Đây không còn là cách được khuyến nghị, và trong thời gian tới khi workflow được cập nhật và đa số LLM/công cụ lớn hỗ trợ subprocesses, việc này sẽ không còn cần thiết. +::: + +## Khi nào nên dùng + +Chỉ dùng cách này nếu bạn nhận thấy tổ hợp công cụ / model bạn đang dùng không thể nạp và đọc đầy đủ tất cả tài liệu đầu vào khi cần. + +## Chia nhỏ tài liệu là gì? + +Chia nhỏ tài liệu là việc tách các tệp markdown lớn thành nhiều tệp nhỏ có tổ chức dựa trên các tiêu đề cấp 2 (`## Tiêu đề`). + +### Kiến trúc + +```text +Trước khi chia nhỏ: +_bmad-output/planning-artifacts/ +└── PRD.md (tệp lớn 50k token) + +Sau khi chia nhỏ: +_bmad-output/planning-artifacts/ +└── prd/ + ├── index.md # Mục lục kèm mô tả + ├── overview.md # Phần 1 + ├── user-requirements.md # Phần 2 + ├── technical-requirements.md # Phần 3 + └── ... # Các phần bổ sung +``` + +## Các bước thực hiện + +### 1. Chạy công cụ Shard-Doc + +```bash +/bmad-shard-doc +``` + +### 2. Làm theo quy trình tương tác + +```text +Agent: Bạn muốn chia nhỏ tài liệu nào? +User: docs/PRD.md + +Agent: Thư mục đích mặc định: docs/prd/ + Chấp nhận mặc định? [y/n] +User: y + +Agent: Đang chia nhỏ PRD.md... + ✓ Đã tạo 12 tệp theo từng phần + ✓ Đã tạo index.md + ✓ Hoàn tất! +``` + +## Cơ chế workflow tìm tài liệu + +Workflow của BMad dùng **hệ thống phát hiện kép**: + +1. **Thử tài liệu nguyên khối trước** - Tìm `document-name.md` +2. **Kiểm tra bản đã chia nhỏ** - Tìm `document-name/index.md` +3. **Quy tắc ưu tiên** - Bản nguyên khối được ưu tiên nếu cả hai cùng tồn tại; hãy xóa bản nguyên khối nếu bạn muốn workflow dùng bản đã chia nhỏ + +## Hỗ trợ trong workflow + +Tất cả workflow BMM đều hỗ trợ cả hai định dạng: + +- Tài liệu nguyên khối +- Tài liệu đã chia nhỏ +- Tự động nhận diện +- Trong suốt với người dùng diff --git a/docs/vi-vn/how-to/upgrade-to-v6.md b/docs/vi-vn/how-to/upgrade-to-v6.md new file mode 100644 index 000000000..bab3fe5a2 --- /dev/null +++ b/docs/vi-vn/how-to/upgrade-to-v6.md @@ -0,0 +1,100 @@ +--- +title: "Cách nâng cấp lên v6" +description: Di chuyển từ BMad v4 sang v6 +sidebar: + order: 3 +--- + +Sử dụng trình cài đặt BMad để nâng cấp từ v4 lên v6, bao gồm khả năng tự động phát hiện bản cài đặt cũ và hỗ trợ di chuyển. + +## Khi nào nên dùng + +- Bạn đang dùng BMad v4 (thư mục `.bmad-method`) +- Bạn muốn chuyển sang kiến trúc v6 mới +- Bạn có các planning artifact hiện có cần giữ lại + +:::note[Điều kiện tiên quyết] +- Node.js 20+ +- Bản cài đặt BMad v4 hiện có +::: + +## Các bước thực hiện + +### 1. Chạy trình cài đặt + +Làm theo [Hướng dẫn cài đặt](./install-bmad.md). + +### 2. Xử lý bản cài đặt cũ + +Khi v4 được phát hiện, bạn có thể: + +- Cho phép trình cài đặt sao lưu và xóa `.bmad-method` +- Thoát và tự xử lý dọn dẹp thủ công + +Nếu trước đây bạn đặt tên thư mục BMad khác - bạn sẽ phải tự xóa thư mục đó. + +### 3. Dọn dẹp skill IDE cũ + +Tự xóa các command/skill IDE cũ của v4 - ví dụ nếu bạn dùng Claude Code, hãy tìm các thư mục lồng nhau bắt đầu bằng `bmad` và xóa chúng: + +- `.claude/commands/` + +Các skill v6 mới sẽ được cài tại: + +- `.claude/skills/` + +### 4. Di chuyển planning artifacts + +**Nếu bạn có tài liệu lập kế hoạch (Brief/PRD/UX/Architecture):** + +Di chuyển chúng vào `_bmad-output/planning-artifacts/` với tên mô tả rõ ràng: + +- Tên tệp PRD nên chứa `PRD` +- Tên tệp tương ứng nên chứa `brief`, `architecture`, hoặc `ux-design` +- Tài liệu đã chia nhỏ có thể đặt trong các thư mục con đặt tên phù hợp + +**Nếu bạn đang lập kế hoạch dở dang:** Hãy cân nhắc bắt đầu lại với workflow v6. Bạn vẫn có thể dùng các tài liệu hiện có làm input - các workflow discovery tiên tiến trong v6, kết hợp web search và chế độ plan trong IDE, cho kết quả tốt hơn. + +### 5. Di chuyển công việc phát triển đang dở dang + +Nếu bạn đã có các story được tạo hoặc đã triển khai: + +1. Hoàn thành cài đặt v6 +2. Đặt `epics.md` hoặc `epics/epic*.md` vào `_bmad-output/planning-artifacts/` +3. Chạy workflow `bmad-sprint-planning` của Scrum Master +4. Nói rõ với SM những epic/story nào đã hoàn thành + +## Bạn nhận được gì + +**Cấu trúc thống nhất của v6:** + +```text +du-an-cua-ban/ +├── _bmad/ # Thư mục cài đặt duy nhất +│ ├── _config/ # Các tùy chỉnh của bạn +│ │ └── agents/ # Tệp tùy chỉnh agent +│ ├── core/ # Framework core dùng chung +│ ├── bmm/ # Module BMad Method +│ ├── bmb/ # BMad Builder +│ └── cis/ # Creative Intelligence Suite +└── _bmad-output/ # Thư mục output (là thư mục docs trong v4) +``` + +## Di chuyển module + +| Module v4 | Trạng thái trong v6 | +| --- | --- | +| `.bmad-2d-phaser-game-dev` | Đã được tích hợp vào module BMGD | +| `.bmad-2d-unity-game-dev` | Đã được tích hợp vào module BMGD | +| `.bmad-godot-game-dev` | Đã được tích hợp vào module BMGD | +| `.bmad-infrastructure-devops` | Đã bị ngừng hỗ trợ - agent DevOps mới sắp ra mắt | +| `.bmad-creative-writing` | Chưa được điều chỉnh - module v6 mới sắp ra mắt | + +## Các thay đổi chính + +| Khái niệm | v4 | v6 | +| --- | --- | --- | +| **Core** | `_bmad-core` thực chất là BMad Method | `_bmad/core/` là framework dùng chung | +| **Method** | `_bmad-method` | `_bmad/bmm/` | +| **Config** | Sửa trực tiếp các tệp | `config.yaml` theo từng module | +| **Documents** | Cần thiết lập trước cho bản chia nhỏ hoặc nguyên khối | Linh hoạt hoàn toàn, tự động quét | diff --git a/docs/vi-vn/index.md b/docs/vi-vn/index.md new file mode 100644 index 000000000..97afa4d49 --- /dev/null +++ b/docs/vi-vn/index.md @@ -0,0 +1,60 @@ +--- +title: Chào mừng đến với BMad Method +description: Framework phát triển phần mềm dựa trên AI với các agent chuyên biệt, workflow có hướng dẫn và khả năng lập kế hoạch thông minh +--- + +BMad Method (**B**uild **M**ore **A**rchitect **D**reams) là một framework phát triển phần mềm dựa trên AI trong hệ sinh thái BMad Method, giúp bạn xây dựng phần mềm xuyên suốt toàn bộ quy trình, từ hình thành ý tưởng và lập kế hoạch cho tới triển khai với agent. Framework này cung cấp các AI agent chuyên biệt, workflow có hướng dẫn, và khả năng lập kế hoạch thông minh thích ứng với độ phức tạp của dự án, dù bạn đang sửa một lỗi nhỏ hay xây dựng một nền tảng doanh nghiệp. + +Nếu bạn đã quen làm việc với các trợ lý AI cho lập trình như Claude, Cursor, hoặc GitHub Copilot, bạn có thể bắt đầu ngay. + +:::note[🚀 V6 đã ra mắt và chúng tôi mới chỉ bắt đầu!] +Kiến trúc Skills, BMad Builder v1, Dev Loop Automation, và nhiều thứ khác nữa đang được phát triển. **[Xem Roadmap →](/vi-vn/roadmap/)** +::: + +## Mới bắt đầu? Hãy xem một Tutorial trước + +Cách nhanh nhất để hiểu BMad là dùng thử nó. + +- **[Bắt đầu với BMad](./tutorials/getting-started.md)** — Cài đặt và hiểu cách BMad hoạt động +- **[Sơ đồ Workflow](./reference/workflow-map.md)** — Tổng quan trực quan về các phase của BMM, workflow, và cách quản lý context + +:::tip[Muốn vào việc ngay?] +Cài BMad và dùng skill `bmad-help` — nó sẽ hướng dẫn bạn mọi thứ dựa trên dự án và các module đã cài. +::: + +## Cách dùng bộ tài liệu này + +Bộ tài liệu này được chia thành bốn phần, dựa trên mục tiêu của bạn: + +| Phần | Mục đích | +| ----------------- | ---------------------------------------------------------------------------------------------------------- | +| **Tutorials** | Thiên về học theo từng bước. Đây là các hướng dẫn tuần tự giúp bạn xây dựng một thứ gì đó. Nếu bạn mới làm quen, hãy bắt đầu ở đây. | +| **How-To Guides** | Thiên về tác vụ. Đây là các hướng dẫn thực tế để giải quyết một vấn đề cụ thể. Câu hỏi kiểu “Làm sao để tùy chỉnh một agent?” nằm ở phần này. | +| **Explanation** | Thiên về hiểu bản chất. Đây là các bài phân tích sâu về khái niệm và kiến trúc. Hãy đọc khi bạn muốn hiểu *vì sao*. | +| **Reference** | Thiên về tra cứu thông tin. Đây là đặc tả kỹ thuật cho agent, workflow, và cấu hình. | + +## Mở rộng và tùy chỉnh + +Bạn muốn mở rộng BMad bằng các agent, workflow, hoặc module của riêng mình? **[BMad Builder](https://bmad-builder-docs.bmad-method.org/)** cung cấp framework và công cụ để tạo các phần mở rộng tùy chỉnh, dù bạn chỉ bổ sung khả năng mới cho BMad hay xây dựng hẳn một module mới từ đầu. + +## Bạn cần gì để bắt đầu + +BMad hoạt động với bất kỳ trợ lý AI cho lập trình nào hỗ trợ custom system prompt hoặc project context. Một số lựa chọn phổ biến: + +- **[Claude Code](https://code.claude.com)** — Công cụ CLI của Anthropic (khuyến nghị) +- **[Cursor](https://cursor.sh)** — Trình soạn thảo mã lấy AI làm trung tâm +- **[Codex CLI](https://github.com/openai/codex)** — Agent lập trình trên terminal của OpenAI + +Bạn nên quen với các khái niệm phát triển phần mềm cơ bản như quản lý phiên bản, cấu trúc dự án, và workflow Agile. Không cần có kinh nghiệm trước với các hệ thống agent kiểu BMad, vì bộ tài liệu này được viết ra chính để hỗ trợ việc đó. + +## Tham gia cộng đồng + +Nhận trợ giúp, chia sẻ những gì bạn đang xây dựng, hoặc đóng góp cho BMad: + +- **[Discord](https://discord.gg/gk8jAdXWmj)** — Trao đổi với những người dùng BMad khác, đặt câu hỏi, chia sẻ ý tưởng +- **[GitHub](https://github.com/bmad-code-org/BMAD-METHOD)** — Mã nguồn, issues, và đóng góp +- **[YouTube](https://www.youtube.com/@BMadCode)** — Video hướng dẫn và walkthrough + +## Bước tiếp theo + +Sẵn sàng bắt đầu? **[Bắt đầu với BMad](./tutorials/getting-started.md)** và xây dựng dự án đầu tiên của bạn. diff --git a/docs/vi-vn/reference/agents.md b/docs/vi-vn/reference/agents.md new file mode 100644 index 000000000..ca57900ed --- /dev/null +++ b/docs/vi-vn/reference/agents.md @@ -0,0 +1,55 @@ +--- +title: Các agent +description: Các agent mặc định của BMM cùng skill ID, trigger menu và workflow chính +sidebar: + order: 2 +--- + +## Các Agent Mặc Định + +Trang này liệt kê các agent mặc định của BMM (bộ Agile suite) được cài cùng với BMad Method, bao gồm skill ID, trigger menu và workflow chính của chúng. Mỗi agent được gọi dưới dạng một skill. + +## Ghi Chú + +- Mỗi agent đều có sẵn dưới dạng một skill do trình cài đặt tạo ra. Skill ID, ví dụ `bmad-dev`, được dùng để gọi agent. +- Trigger là các mã menu ngắn, ví dụ `CP`, cùng với các fuzzy match hiển thị trong menu của từng agent. +- Việc tạo test QA do workflow skill `bmad-qa-generate-e2e-tests` đảm nhận, khả dụng thông qua Developer agent. Module Test Architect (TEA) đầy đủ nằm trong một module riêng. + +| Agent | Skill ID | Trigger | Workflow chính | +| --------------------------- | -------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------- | +| Analyst (Mary) | `bmad-analyst` | `BP`, `MR`, `DR`, `TR`, `CB`, `WB`, `DP` | Brainstorm, Market Research, Domain Research, Technical Research, Create Brief, PRFAQ Challenge, Document Project | +| Product Manager (John) | `bmad-pm` | `CP`, `VP`, `EP`, `CE`, `IR`, `CC` | Create/Validate/Edit PRD, Create Epics and Stories, Implementation Readiness, Correct Course | +| Architect (Winston) | `bmad-architect` | `CA`, `IR` | Create Architecture, Implementation Readiness | +| Developer (Amelia) | `bmad-agent-dev` | `DS`, `QD`, `QA`, `CR`, `SP`, `CS`, `ER` | Dev Story, Quick Dev, QA Test Generation, Code Review, Sprint Planning, Create Story, Epic Retrospective | +| UX Designer (Sally) | `bmad-ux-designer` | `CU` | Create UX Design | +| Technical Writer (Paige) | `bmad-tech-writer` | `DP`, `WD`, `US`, `MG`, `VD`, `EC` | Document Project, Write Document, Update Standards, Mermaid Generate, Validate Doc, Explain Concept | + +## Các Loại Trigger + +Trigger trong menu agent dùng hai kiểu gọi khác nhau. Biết trigger thuộc kiểu nào sẽ giúp bạn cung cấp đúng đầu vào. + +### Trigger workflow (không cần tham số) + +Phần lớn trigger sẽ nạp một file workflow có cấu trúc. Bạn gõ mã trigger, agent sẽ bắt đầu workflow và nhắc bạn nhập thông tin ở từng bước. + +Ví dụ: `CP` (Create PRD), `DS` (Dev Story), `CA` (Create Architecture), `QD` (Quick Dev) + +### Trigger hội thoại (cần tham số) + +Một số trigger sẽ mở cuộc hội thoại tự do thay vì chạy workflow có cấu trúc. Khi đó bạn cần mô tả yêu cầu của mình cùng với mã trigger. + +| Agent | Trigger | Nội dung cần cung cấp | +| --- | --- | --- | +| Technical Writer (Paige) | `WD` | Mô tả tài liệu cần viết | +| Technical Writer (Paige) | `US` | Sở thích hoặc quy ước muốn thêm vào standards | +| Technical Writer (Paige) | `MG` | Mô tả sơ đồ và loại sơ đồ (sequence, flowchart, v.v.) | +| Technical Writer (Paige) | `VD` | Tài liệu cần kiểm tra và các vùng trọng tâm | +| Technical Writer (Paige) | `EC` | Tên khái niệm cần giải thích | + +**Ví dụ:** + +```text +WD Write a deployment guide for our Docker setup +MG Create a sequence diagram showing the auth flow +EC Explain how the module system works +``` diff --git a/docs/vi-vn/reference/commands.md b/docs/vi-vn/reference/commands.md new file mode 100644 index 000000000..539956de1 --- /dev/null +++ b/docs/vi-vn/reference/commands.md @@ -0,0 +1,135 @@ +--- +title: Các skill +description: Tài liệu tham chiếu cho skill của BMad — skill là gì, hoạt động ra sao và tìm ở đâu. +sidebar: + order: 3 +--- + +Skills là các prompt dựng sẵn để nạp agent, chạy workflow hoặc thực thi task bên trong IDE của bạn. Trình cài đặt BMad sinh chúng từ các module bạn đã chọn tại thời điểm cài đặt. Nếu sau này bạn thêm, xóa hoặc thay đổi module, hãy chạy lại trình cài đặt để đồng bộ skills (xem [Khắc phục sự cố](#khắc-phục-sự-cố)). + +## Skill So Với Trigger Trong Menu Agent + +BMad cung cấp hai cách để bắt đầu công việc, và chúng phục vụ những mục đích khác nhau. + +| Cơ chế | Cách gọi | Điều xảy ra | +| --- | --- | --- | +| **Skill** | Gõ tên skill, ví dụ `bmad-help`, trong IDE | Nạp trực tiếp agent, chạy workflow hoặc thực thi task | +| **Trigger menu agent** | Nạp agent trước, sau đó gõ mã ngắn như `DS` | Agent diễn giải mã đó và bắt đầu workflow tương ứng trong khi vẫn giữ đúng persona | + +Trigger trong menu agent yêu cầu bạn đang ở trong một phiên agent đang hoạt động. Dùng skill khi bạn đã biết mình muốn workflow nào. Dùng trigger khi bạn đang làm việc với một agent và muốn đổi tác vụ mà không rời khỏi cuộc hội thoại. + +## Skills Được Tạo Ra Như Thế Nào + +Khi bạn chạy `npx bmad-method install`, trình cài đặt sẽ đọc manifest của mọi module được chọn rồi tạo một skill cho mỗi agent, workflow, task và tool. Mỗi skill là một thư mục chứa file `SKILL.md`, hướng dẫn AI nạp file nguồn tương ứng và làm theo chỉ dẫn trong đó. + +Trình cài đặt dùng template cho từng loại skill: + +| Loại skill | File được tạo sẽ làm gì | +| --- | --- | +| **Agent launcher** | Nạp file persona của agent, kích hoạt menu của nó và giữ nguyên vai trò | +| **Workflow skill** | Nạp cấu hình workflow và làm theo các bước | +| **Task skill** | Nạp một file task độc lập và làm theo hướng dẫn | +| **Tool skill** | Nạp một file tool độc lập và làm theo hướng dẫn | + +:::note[Chạy lại trình cài đặt] +Nếu bạn thêm hoặc bớt module, hãy chạy lại trình cài đặt. Nó sẽ tạo lại toàn bộ file skill khớp với tập module hiện tại. +::: + +## File Skill Nằm Ở Đâu + +Trình cài đặt sẽ ghi file skill vào một thư mục dành riêng cho IDE bên trong dự án. Đường dẫn chính xác phụ thuộc vào IDE bạn chọn khi cài. + +| IDE / CLI | Thư mục skill | +| --- | --- | +| Claude Code | `.claude/skills/` | +| Cursor | `.cursor/skills/` | +| Windsurf | `.windsurf/skills/` | +| IDE khác | Xem output của trình cài đặt để biết đường dẫn đích | + +Mỗi skill là một thư mục chứa file `SKILL.md`. Ví dụ với Claude Code, cấu trúc sẽ như sau: + +```text +.claude/skills/ +├── bmad-help/ +│ └── SKILL.md +├── bmad-create-prd/ +│ └── SKILL.md +├── bmad-agent-dev/ +│ └── SKILL.md +└── ... +``` + +Tên thư mục quyết định tên skill trong IDE. Ví dụ thư mục `bmad-agent-dev/` sẽ đăng ký skill `bmad-agent-dev`. + +## Cách Tìm Danh Sách Skill Của Bạn + +Gõ tên skill trong IDE để gọi nó. Một số nền tảng yêu cầu bạn bật skills trong phần cài đặt trước khi chúng xuất hiện. + +Chạy `bmad-help` để nhận hướng dẫn có ngữ cảnh về bước tiếp theo. + +:::tip[Khám phá nhanh] +Các thư mục skill được tạo trong dự án chính là danh sách chuẩn nhất. Mở chúng trong trình quản lý file để xem toàn bộ skill cùng mô tả. +::: + +## Các Nhóm Skill + +### Agent Skills + +Agent skills nạp một persona AI chuyên biệt với vai trò, phong cách giao tiếp và menu workflow xác định sẵn. Sau khi được nạp, agent sẽ giữ đúng vai trò và phản hồi qua các trigger trong menu. + +| Ví dụ skill | Agent | Vai trò | +| --- | --- | --- | +| `bmad-agent-dev` | Amelia (Developer) | Triển khai story với mức tuân thủ đặc tả nghiêm ngặt | +| `bmad-pm` | John (Product Manager) | Tạo và kiểm tra PRD | +| `bmad-architect` | Winston (Architect) | Thiết kế kiến trúc hệ thống | + +Xem [Agents](./agents.md) để biết danh sách đầy đủ các agent mặc định và trigger của chúng. + +### Workflow Skills + +Workflow skills chạy một quy trình có cấu trúc, nhiều bước mà không cần nạp persona agent trước. Chúng nạp cấu hình workflow rồi thực hiện theo từng bước. + +| Ví dụ skill | Mục đích | +| --- | --- | +| `bmad-product-brief` | Tạo product brief — phiên discovery có hướng dẫn khi concept của bạn đã rõ | +| `bmad-prfaq` | Bài kiểm tra [Working Backwards PRFAQ](../explanation/analysis-phase.md#prfaq-working-backwards) để stress-test concept sản phẩm | +| `bmad-create-prd` | Tạo Product Requirements Document | +| `bmad-create-architecture` | Thiết kế kiến trúc hệ thống | +| `bmad-create-epics-and-stories` | Tạo epics và stories | +| `bmad-dev-story` | Triển khai một story | +| `bmad-code-review` | Chạy code review | +| `bmad-quick-dev` | Luồng nhanh hợp nhất — làm rõ yêu cầu, lập kế hoạch, triển khai, review và trình bày | + +Xem [Workflow Map](./workflow-map.md) để có tài liệu workflow đầy đủ theo từng phase. + +### Task Skills Và Tool Skills + +Tasks và tools là các thao tác độc lập, không yêu cầu ngữ cảnh agent hay workflow. + +**BMad-Help: người dẫn đường thông minh của bạn** + +`bmad-help` là giao diện chính để bạn khám phá nên làm gì tiếp theo. Nó kiểm tra dự án, hiểu truy vấn ngôn ngữ tự nhiên và đề xuất bước bắt buộc hoặc tùy chọn tiếp theo dựa trên các module đã cài. + +:::note[Ví dụ] +```text +bmad-help +bmad-help I have a SaaS idea and know all the features. Where do I start? +bmad-help What are my options for UX design? +``` +::: + +**Các task và tool lõi khác** + +Module lõi có 11 công cụ tích hợp sẵn — review, nén tài liệu, brainstorming, quản lý tài liệu và nhiều hơn nữa. Xem [Core Tools](./core-tools.md) để có tài liệu tham chiếu đầy đủ. + +## Quy Ước Đặt Tên + +Mọi skill đều dùng tiền tố `bmad-` theo sau là tên mô tả, ví dụ `bmad-agent-dev`, `bmad-create-prd`, `bmad-help`. Xem [Modules](./modules.md) để biết các module hiện có. + +## Khắc Phục Sự Cố + +**Skills không xuất hiện sau khi cài đặt.** Một số nền tảng yêu cầu bật skills thủ công trong phần cài đặt. Hãy kiểm tra tài liệu IDE của bạn hoặc hỏi trợ lý AI cách bật skills. Bạn cũng có thể cần khởi động lại IDE hoặc reload cửa sổ. + +**Thiếu skill mà bạn mong đợi.** Trình cài đặt chỉ tạo skill cho những module bạn đã chọn. Hãy chạy lại `npx bmad-method install` và kiểm tra lại phần chọn module. Đồng thời xác nhận rằng file skill thực sự tồn tại trong thư mục dự kiến. + +**Skill từ module đã bỏ vẫn còn xuất hiện.** Trình cài đặt không tự xóa các file skill cũ. Hãy xóa các thư mục lỗi thời trong thư mục skills của IDE, hoặc xóa toàn bộ thư mục skills rồi chạy lại trình cài đặt để có tập skill sạch. diff --git a/docs/vi-vn/reference/core-tools.md b/docs/vi-vn/reference/core-tools.md new file mode 100644 index 000000000..4d15e3969 --- /dev/null +++ b/docs/vi-vn/reference/core-tools.md @@ -0,0 +1,293 @@ +--- +title: Công cụ cốt lõi +description: Tài liệu tham chiếu cho mọi tác vụ và quy trình tích hợp sẵn có trong mọi bản cài BMad mà không cần module bổ sung. +sidebar: + order: 2 +--- + +Mọi bản cài BMad đều bao gồm một tập skill cốt lõi có thể dùng cùng với bất cứ việc gì bạn đang làm, các tác vụ và quy trình độc lập hoạt động xuyên suốt mọi dự án, mọi module và mọi giai đoạn. Chúng luôn có sẵn bất kể bạn cài những module tùy chọn nào. + +:::tip[Lối đi nhanh] +Chạy bất kỳ công cụ cốt lõi nào bằng cách gõ tên skill của nó, ví dụ `bmad-help`, trong IDE của bạn. Không cần mở phiên agent trước. +::: + +## Tổng Quan + +| Công cụ | Loại | Mục đích | +| --- | --- | --- | +| [`bmad-help`](#bmad-help) | Tác vụ | Nhận hướng dẫn có ngữ cảnh về việc nên làm gì tiếp theo | +| [`bmad-brainstorming`](#bmad-brainstorming) | Quy trình | Tổ chức các phiên brainstorming có tương tác | +| [`bmad-party-mode`](#bmad-party-mode) | Quy trình | Điều phối thảo luận nhóm nhiều agent | +| [`bmad-distillator`](#bmad-distillator) | Tác vụ | Nén tài liệu tối ưu cho LLM mà không mất thông tin | +| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Tác vụ | Đẩy đầu ra của LLM qua các vòng tinh luyện lặp | +| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Tác vụ | Rà soát hoài nghi để tìm chỗ thiếu và chỗ sai | +| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Tác vụ | Phân tích toàn bộ nhánh rẽ để tìm trường hợp biên chưa được xử lý | +| [`bmad-editorial-review-prose`](#bmad-editorial-review-prose) | Tác vụ | Biên tập câu chữ nhằm tăng độ rõ ràng khi giao tiếp | +| [`bmad-editorial-review-structure`](#bmad-editorial-review-structure) | Tác vụ | Biên tập cấu trúc — cắt, gộp và tổ chức lại | +| [`bmad-shard-doc`](#bmad-shard-doc) | Tác vụ | Tách file markdown lớn thành các phần có tổ chức | +| [`bmad-index-docs`](#bmad-index-docs) | Tác vụ | Tạo hoặc cập nhật mục lục cho toàn bộ tài liệu trong một thư mục | + +## bmad-help + +**Người dẫn đường thông minh cho bước tiếp theo của bạn.** Công cụ này kiểm tra trạng thái dự án, phát hiện những gì đã hoàn thành và đề xuất bước bắt buộc hoặc tùy chọn tiếp theo. + +**Dùng khi:** + +- Bạn vừa hoàn tất một quy trình và muốn biết tiếp theo là gì +- Bạn mới làm quen với BMad và cần định hướng +- Bạn đang mắc kẹt và muốn lời khuyên có ngữ cảnh +- Bạn vừa cài module mới và muốn xem có gì khả dụng + +**Cách hoạt động:** + +1. Quét dự án để tìm các artifact hiện có như PRD, architecture, stories, v.v. +2. Phát hiện các module đã cài và workflow khả dụng của chúng +3. Đề xuất bước tiếp theo theo thứ tự ưu tiên — bước bắt buộc trước, tùy chọn sau +4. Trình bày từng đề xuất cùng lệnh skill và mô tả ngắn + +**Đầu vào:** Truy vấn ngôn ngữ tự nhiên tùy chọn, ví dụ `bmad-help I have a SaaS idea, where do I start?` + +**Đầu ra:** Danh sách ưu tiên các bước tiếp theo được khuyến nghị kèm lệnh skill + +## bmad-brainstorming + +**Tạo ra nhiều ý tưởng đa dạng bằng các kỹ thuật sáng tạo có tương tác.** Đây là một phiên động não có điều phối, nạp các phương pháp phát ý tưởng đã được kiểm chứng từ thư viện kỹ thuật và dẫn bạn đến 100+ ý tưởng trước khi bắt đầu sắp xếp. + +**Dùng khi:** + +- Bạn đang bắt đầu một dự án mới và cần khám phá không gian vấn đề +- Bạn đang bí ý tưởng và cần một quy trình sáng tạo có cấu trúc +- Bạn muốn dùng các framework tạo ý tưởng đã được kiểm chứng như SCAMPER, reverse brainstorming, v.v. + +**Cách hoạt động:** + +1. Thiết lập phiên brainstorming theo chủ đề của bạn +2. Nạp các kỹ thuật sáng tạo từ thư viện phương pháp +3. Dẫn bạn đi qua từng kỹ thuật để tạo ý tưởng +4. Áp dụng giao thức chống thiên lệch — cứ mỗi 10 ý tưởng lại đổi miền sáng tạo để tránh gom cụm +5. Tạo một tài liệu phiên làm việc chỉ thêm vào, trong đó mọi ý tưởng được tổ chức theo kỹ thuật + +**Đầu vào:** Chủ đề brainstorming hoặc phát biểu vấn đề, cùng file context tùy chọn + +**Đầu ra:** `brainstorming-session-{date}.md` chứa toàn bộ ý tưởng được tạo ra + +:::note[Mục tiêu về số lượng] +Điểm bứt phá thường nằm ở vùng ý tưởng thứ 50-100. Workflow này khuyến khích bạn tạo 100+ ý tưởng trước khi sắp xếp. +::: + +## bmad-party-mode + +**Điều phối thảo luận nhóm nhiều agent.** Công cụ này nạp toàn bộ agent BMad đã cài và tạo một cuộc trao đổi tự nhiên, nơi mỗi agent đóng góp từ góc nhìn chuyên môn và cá tính riêng. + +**Dùng khi:** + +- Bạn cần nhiều góc nhìn chuyên gia cho một quyết định +- Bạn muốn các agent phản biện giả định của nhau +- Bạn đang khám phá một chủ đề phức tạp trải qua nhiều miền khác nhau + +**Cách hoạt động:** + +1. Nạp manifest agent chứa toàn bộ persona đã cài +2. Phân tích chủ đề của bạn để chọn ra 2-3 agent phù hợp nhất +3. Các agent lần lượt tham gia, có tương tác chéo và bất đồng tự nhiên +4. Luân phiên agent để đảm bảo góc nhìn đa dạng theo thời gian +5. Kết thúc bằng `goodbye`, `end party` hoặc `quit` + +**Đầu vào:** Chủ đề hoặc câu hỏi thảo luận, cùng thông tin về các persona bạn muốn tham gia nếu có + +**Đầu ra:** Cuộc hội thoại nhiều agent theo thời gian thực, vẫn giữ nguyên cá tính từng agent + +## bmad-distillator + +**Nén tài liệu nguồn tối ưu cho LLM mà không mất thông tin.** Công cụ này tạo ra các bản chưng cất dày đặc, tiết kiệm token nhưng vẫn giữ nguyên toàn bộ thông tin cho LLM dùng về sau. Có thể xác minh bằng tái dựng hai chiều. + +**Dùng khi:** + +- Một tài liệu quá lớn so với context window của LLM +- Bạn cần phiên bản tiết kiệm token của tài liệu nghiên cứu, đặc tả hoặc artifact lập kế hoạch +- Bạn muốn xác minh rằng không có thông tin nào bị mất trong quá trình nén +- Các agent sẽ cần tham chiếu và tìm thông tin trong đó thường xuyên + +**Cách hoạt động:** + +1. **Analyze** — Đọc tài liệu nguồn, nhận diện mật độ thông tin và cấu trúc +2. **Compress** — Chuyển văn xuôi thành dạng bullet dày đặc, bỏ trang trí không cần thiết +3. **Verify** — Kiểm tra tính đầy đủ để đảm bảo mọi thông tin gốc còn nguyên +4. **Validate** *(tùy chọn)* — Tái dựng hai chiều để chứng minh nén không mất mát + +**Đầu vào:** + +- `source_documents` *(bắt buộc)* — Đường dẫn file, thư mục hoặc mẫu glob +- `downstream_consumer` *(tùy chọn)* — Thành phần sẽ dùng đầu ra này, ví dụ "PRD creation" +- `token_budget` *(tùy chọn)* — Kích thước mục tiêu gần đúng +- `--validate` *(cờ)* — Chạy kiểm tra tái dựng hai chiều + +**Đầu ra:** Một hoặc nhiều file markdown distillate kèm báo cáo tỷ lệ nén, ví dụ `3.2:1` + +## bmad-advanced-elicitation + +**Đẩy đầu ra của LLM qua các phương pháp tinh luyện lặp.** Công cụ này chọn từ thư viện kỹ thuật elicitation để cải thiện nội dung một cách có hệ thống qua nhiều lượt. + +**Dùng khi:** + +- Đầu ra của LLM còn nông hoặc quá chung chung +- Bạn muốn khám phá một chủ đề từ nhiều góc phân tích khác nhau +- Bạn đang tinh chỉnh một tài liệu quan trọng và cần chiều sâu hơn + +**Cách hoạt động:** + +1. Nạp registry phương pháp với hơn 5 kỹ thuật elicitation +2. Chọn ra 5 phương pháp phù hợp nhất dựa trên loại nội dung và độ phức tạp +3. Hiển thị menu tương tác — chọn một phương pháp, xáo lại, hoặc liệt kê tất cả +4. Áp dụng phương pháp đã chọn để nâng cấp nội dung +5. Tiếp tục đưa ra lựa chọn cho các vòng cải thiện tiếp theo cho đến khi bạn chọn "Proceed" + +**Đầu vào:** Phần nội dung cần cải thiện + +**Đầu ra:** Phiên bản nội dung đã được nâng cấp + +## bmad-review-adversarial-general + +**Kiểu review hoài nghi, mặc định cho rằng vấn đề luôn tồn tại và phải đi tìm chúng.** Công cụ này đứng ở góc nhìn của một reviewer khó tính, thiếu kiên nhẫn với sản phẩm cẩu thả. Nó tìm xem còn thiếu gì, không chỉ tìm cái gì sai. + +**Dùng khi:** + +- Bạn cần bảo đảm chất lượng trước khi chốt một deliverable +- Bạn muốn stress-test một spec, story hoặc tài liệu +- Bạn muốn tìm lỗ hổng bao phủ mà các review lạc quan thường bỏ sót + +**Cách hoạt động:** + +1. Đọc nội dung với góc nhìn hoài nghi và khắt khe +2. Xác định vấn đề về độ đầy đủ, độ đúng và chất lượng +3. Chủ động tìm phần còn thiếu chứ không chỉ phần hiện diện nhưng sai +4. Phải tìm được tối thiểu 10 vấn đề, nếu không sẽ phân tích sâu hơn + +**Đầu vào:** + +- `content` *(bắt buộc)* — Diff, spec, story, tài liệu hoặc bất kỳ artifact nào +- `also_consider` *(tùy chọn)* — Các vùng bổ sung cần để ý + +**Đầu ra:** Danh sách markdown gồm 10+ phát hiện kèm mô tả + +## bmad-review-edge-case-hunter + +**Đi qua mọi nhánh rẽ và điều kiện biên, chỉ báo cáo những trường hợp chưa được xử lý.** Đây là phương pháp thuần túy dựa trên truy vết đường đi, suy ra các lớp edge case một cách cơ học. Nó trực giao với adversarial review — khác phương pháp, không khác thái độ. + +**Dùng khi:** + +- Bạn muốn bao phủ edge case toàn diện cho code hoặc logic +- Bạn cần một phương pháp bổ sung cho adversarial review +- Bạn đang review diff hoặc function để tìm điều kiện biên + +**Cách hoạt động:** + +1. Liệt kê toàn bộ nhánh rẽ trong nội dung +2. Suy ra cơ học các lớp edge case: thiếu else/default, input không được gác, off-by-one, tràn số học, ép kiểu ngầm, race condition, lỗ hổng timeout +3. Đối chiếu từng đường đi với các guard hiện có +4. Chỉ báo cáo các đường đi chưa được xử lý, âm thầm bỏ qua những trường hợp đã được che chắn + +**Đầu vào:** + +- `content` *(bắt buộc)* — Diff, toàn file hoặc function +- `also_consider` *(tùy chọn)* — Các vùng bổ sung cần lưu ý + +**Đầu ra:** Mảng JSON các phát hiện, mỗi phát hiện có `location`, `trigger_condition`, `guard_snippet` và `potential_consequence` + +:::note[Các kiểu review bổ trợ nhau] +Hãy chạy cả `bmad-review-adversarial-general` và `bmad-review-edge-case-hunter` để có độ bao phủ trực giao. Adversarial review bắt lỗi về chất lượng và độ đầy đủ; edge case hunter bắt các đường đi chưa được xử lý. +::: + +## bmad-editorial-review-prose + +**Biên tập câu chữ kiểu lâm sàng, tập trung vào độ rõ ràng khi truyền đạt.** Công cụ này review văn bản để tìm ra các vấn đề cản trở việc hiểu. Nó dùng Microsoft Writing Style Guide làm nền và vẫn giữ giọng văn của tác giả. + +**Dùng khi:** + +- Bạn đã có bản nháp tài liệu và muốn trau chuốt câu chữ +- Bạn cần đảm bảo độ rõ ràng cho một nhóm độc giả cụ thể +- Bạn muốn sửa lỗi giao tiếp mà không áp đặt gu phong cách cá nhân + +**Cách hoạt động:** + +1. Đọc nội dung, bỏ qua code block và frontmatter +2. Xác định các vấn đề cản trở hiểu nghĩa, không phải các sở thích phong cách +3. Khử trùng lặp những lỗi giống nhau xuất hiện nhiều nơi +4. Tạo bảng sửa lỗi ba cột + +**Đầu vào:** + +- `content` *(bắt buộc)* — Markdown, văn bản thường hoặc XML +- `style_guide` *(tùy chọn)* — Style guide riêng của dự án +- `reader_type` *(tùy chọn)* — `humans` mặc định cho độ rõ và nhịp đọc, hoặc `llm` cho độ chính xác và nhất quán + +**Đầu ra:** Bảng markdown ba cột: Original Text | Revised Text | Changes + +## bmad-editorial-review-structure + +**Biên tập cấu trúc — đề xuất cắt, gộp, di chuyển và cô đọng.** Công cụ này review cách tổ chức tài liệu và đề xuất thay đổi mang tính nội dung để tăng độ rõ ràng và luồng đọc trước khi chỉnh câu chữ. + +**Dùng khi:** + +- Một tài liệu được ghép từ nhiều nguồn con và cần tính nhất quán về cấu trúc +- Bạn muốn rút gọn độ dài tài liệu nhưng vẫn giữ được khả năng hiểu +- Bạn cần phát hiện chỗ lệch phạm vi hoặc thông tin quan trọng bị chôn vùi + +**Cách hoạt động:** + +1. Phân tích tài liệu theo 5 mô hình cấu trúc: Tutorial, Reference, Explanation, Prompt, Strategic +2. Xác định phần dư thừa, lệch phạm vi và thông tin bị chìm +3. Tạo danh sách khuyến nghị theo mức ưu tiên: CUT, MERGE, MOVE, CONDENSE, QUESTION, PRESERVE +4. Ước tính số từ và phần trăm có thể giảm + +**Đầu vào:** + +- `content` *(bắt buộc)* — Tài liệu cần review +- `purpose` *(tùy chọn)* — Mục đích mong muốn, ví dụ "quickstart tutorial" +- `target_audience` *(tùy chọn)* — Ai sẽ đọc tài liệu này +- `reader_type` *(tùy chọn)* — `humans` hoặc `llm` +- `length_target` *(tùy chọn)* — Mục tiêu rút gọn, ví dụ "ngắn hơn 30%" + +**Đầu ra:** Tóm tắt tài liệu, danh sách khuyến nghị ưu tiên và ước tính mức giảm + +## bmad-shard-doc + +**Tách file markdown lớn thành các file phần có tổ chức.** Công cụ này dùng các header cấp 2 làm điểm cắt để tạo ra một thư mục gồm các file phần tự chứa cùng một file chỉ mục. + +**Dùng khi:** + +- Một file markdown đã quá lớn để quản lý hiệu quả, thường trên 500 dòng +- Bạn muốn chia một tài liệu nguyên khối thành các phần dễ điều hướng +- Bạn cần các file riêng để chỉnh sửa song song hoặc quản lý context cho LLM + +**Cách hoạt động:** + +1. Xác nhận file nguồn tồn tại và là markdown +2. Tách tại các header cấp 2 `##` thành các file phần được đánh số +3. Tạo `index.md` chứa danh sách phần và liên kết +4. Hỏi bạn có muốn xóa, lưu trữ hay giữ file gốc không + +**Đầu vào:** Đường dẫn file markdown nguồn, cùng thư mục đích tùy chọn + +**Đầu ra:** Một thư mục gồm `index.md` và các file `01-{section}.md`, `02-{section}.md`, v.v. + +## bmad-index-docs + +**Tạo hoặc cập nhật mục lục cho toàn bộ tài liệu trong một thư mục.** Công cụ này quét thư mục, đọc từng file để hiểu mục đích của nó, rồi tạo `index.md` có tổ chức với liên kết và mô tả. + +**Dùng khi:** + +- Bạn cần một chỉ mục nhẹ để LLM quét nhanh các tài liệu hiện có +- Một thư mục tài liệu đã lớn và cần bảng mục lục có tổ chức +- Bạn muốn một cái nhìn tổng quan được tạo tự động và luôn theo kịp hiện trạng + +**Cách hoạt động:** + +1. Quét thư mục đích để lấy mọi file không ẩn +2. Đọc từng file để hiểu đúng mục đích thực tế của nó +3. Nhóm file theo loại, mục đích hoặc thư mục con +4. Tạo mô tả ngắn gọn, thường từ 3-10 từ cho mỗi file + +**Đầu vào:** Đường dẫn thư mục đích + +**Đầu ra:** `index.md` chứa danh sách file có tổ chức, liên kết tương đối và mô tả ngắn diff --git a/docs/vi-vn/reference/modules.md b/docs/vi-vn/reference/modules.md new file mode 100644 index 000000000..1f0bf25ea --- /dev/null +++ b/docs/vi-vn/reference/modules.md @@ -0,0 +1,76 @@ +--- +title: Các Module Chính Thức +description: Các module bổ sung để xây agent tùy chỉnh, tăng cường sáng tạo, phát triển game và kiểm thử +sidebar: + order: 4 +--- + +BMad được mở rộng thông qua các module chính thức mà bạn chọn trong quá trình cài đặt. Những module bổ sung này cung cấp agent, workflow và task chuyên biệt cho các lĩnh vực cụ thể, vượt ra ngoài phần lõi tích hợp sẵn và BMM (Agile suite). + +:::tip[Cài đặt module] +Chạy `npx bmad-method install` rồi chọn những module bạn muốn. Trình cài đặt sẽ tự xử lý phần tải về, cấu hình và tích hợp vào IDE. +::: + +## BMad Builder + +Tạo agent tùy chỉnh, workflow tùy chỉnh và module chuyên biệt theo lĩnh vực với sự hỗ trợ có hướng dẫn. BMad Builder là meta-module để mở rộng chính framework này. + +- **Mã:** `bmb` +- **npm:** [`bmad-builder`](https://www.npmjs.com/package/bmad-builder) +- **GitHub:** [bmad-code-org/bmad-builder](https://github.com/bmad-code-org/bmad-builder) + +**Cung cấp:** + +- Agent Builder — tạo AI agent chuyên biệt với chuyên môn và quyền truy cập công cụ tùy chỉnh +- Workflow Builder — thiết kế quy trình có cấu trúc với các bước và điểm quyết định +- Module Builder — đóng gói agent và workflow thành các module có thể chia sẻ và phát hành +- Thiết lập có tương tác bằng YAML cùng hỗ trợ publish lên npm + +## Creative Intelligence Suite + +Bộ công cụ vận hành bởi AI dành cho sáng tạo có cấu trúc, phát ý tưởng và đổi mới trong giai đoạn đầu phát triển. Bộ này cung cấp nhiều agent giúp brainstorming, design thinking và giải quyết vấn đề bằng các framework đã được kiểm chứng. + +- **Mã:** `cis` +- **npm:** [`bmad-creative-intelligence-suite`](https://www.npmjs.com/package/bmad-creative-intelligence-suite) +- **GitHub:** [bmad-code-org/bmad-module-creative-intelligence-suite](https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite) + +**Cung cấp:** + +- Các agent Innovation Strategist, Design Thinking Coach và Brainstorming Coach +- Problem Solver và Creative Problem Solver cho tư duy hệ thống và tư duy bên lề +- Storyteller và Presentation Master cho kể chuyện và pitching +- Các framework phát ý tưởng như SCAMPER, Reverse Brainstorming và problem reframing + +## Game Dev Studio + +Các workflow phát triển game có cấu trúc, được điều chỉnh cho Unity, Unreal, Godot và các engine tùy chỉnh. Hỗ trợ làm prototype nhanh qua Quick Flow và sản xuất toàn diện bằng sprint theo epic. + +- **Mã:** `gds` +- **npm:** [`bmad-game-dev-studio`](https://www.npmjs.com/package/bmad-game-dev-studio) +- **GitHub:** [bmad-code-org/bmad-module-game-dev-studio](https://github.com/bmad-code-org/bmad-module-game-dev-studio) + +**Cung cấp:** + +- Workflow tạo Game Design Document (GDD) +- Chế độ Quick Dev cho làm prototype nhanh +- Hỗ trợ thiết kế narrative cho nhân vật, hội thoại và world-building +- Bao phủ hơn 21 thể loại game cùng hướng dẫn kiến trúc theo engine + +## Test Architect (TEA) + +Chiến lược kiểm thử cấp doanh nghiệp, hướng dẫn tự động hóa và quyết định release gate thông qua một agent chuyên gia cùng chín workflow có cấu trúc. TEA vượt xa QA agent tích hợp sẵn nhờ ưu tiên theo rủi ro và truy vết yêu cầu. + +- **Mã:** `tea` +- **npm:** [`bmad-method-test-architecture-enterprise`](https://www.npmjs.com/package/bmad-method-test-architecture-enterprise) +- **GitHub:** [bmad-code-org/bmad-method-test-architecture-enterprise](https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise) + +**Cung cấp:** + +- Agent Murat (Master Test Architect and Quality Advisor) +- Các workflow cho test design, ATDD, automation, test review và traceability +- Đánh giá NFR, thiết lập CI và dựng sườn framework kiểm thử +- Ưu tiên P0-P3 cùng tích hợp tùy chọn với Playwright Utils và MCP + +## Community Modules + +Các module cộng đồng và một chợ module đang được chuẩn bị. Hãy theo dõi [tổ chức BMad trên GitHub](https://github.com/bmad-code-org) để cập nhật. diff --git a/docs/vi-vn/reference/testing.md b/docs/vi-vn/reference/testing.md new file mode 100644 index 000000000..11b1acbb4 --- /dev/null +++ b/docs/vi-vn/reference/testing.md @@ -0,0 +1,106 @@ +--- +title: Các Tùy Chọn Kiểm Thử +description: So sánh workflow QA tích hợp sẵn với module Test Architect (TEA) cho tự động hóa kiểm thử. +sidebar: + order: 5 +--- + +BMad cung cấp hai hướng kiểm thử: workflow QA tích hợp sẵn để tạo test nhanh và module Test Architect có thể cài thêm cho chiến lược kiểm thử c��p doanh nghiệp. + +## Nên Dùng Cái Nào? + +| Yếu tố | QA tích hợp sẵn | Module TEA | +| --- | --- | --- | +| **Phù hợp nhất với** | Dự án nhỏ-trung bình, cần bao phủ nhanh | Dự án lớn, miền nghiệp vụ bị ràng buộc hoặc phức tạp | +| **Thiết lập** | Không cần cài thêm, đã có sẵn trong BMM | Cài riêng qua `npx bmad-method install` | +| **Cách tiếp cận** | Tạo test nhanh, lặp tinh chỉnh sau | Lập kế hoạch trước rồi mới tạo test có truy vết | +| **Loại test** | API và E2E | API, E2E, ATDD, NFR và nhiều loại khác | +| **Chiến lược** | Happy path + edge case quan trọng | Ưu tiên theo rủi ro (P0-P3) | +| **Số workflow** | 1 (Automate) | 9 (design, ATDD, automate, review, trace và các workflow khác) | + +:::tip[Bắt đầu với QA tích h��p sẵn] +Phần lớn dự án nên bắt đầu với workflow QA tích hợp sẵn. Nếu sau này bạn cần chiến lược kiểm thử, quality gate hoặc truy vết yêu cầu, hãy cài TEA song song. +::: + +## Workflow QA Tích Hợp Sẵn + +Workflow QA tích hợp sẵn (`bmad-qa-generate-e2e-tests`) nằm trong module BMM (Agile suite), khả dụng thông qua Developer agent. Nó tạo test chạy được rất nhanh bằng framework kiểm thử hiện có của dự án, không cần thêm cấu hình hay bước cài đặt bổ sung. + +**Trigger:** `QA` (thông qua Developer agent) hoặc `bmad-qa-generate-e2e-tests` + +### Workflow Làm Gì + +Workflow QA (Automate) gồm năm bước: + +1. **Phát hiện framework test** — quét `package.json` và các file test hiện có để nhận ra framework của bạn như Jest, Vitest, Playwright, Cypress hoặc bất kỳ runner tiêu chuẩn nào. Nếu chưa có gì, nó sẽ phân tích stack dự án và đề xuất một lựa chọn. +2. **Xác định tính năng** — hỏi cần kiểm thử phần nào hoặc tự khám phá các tính năng trong codebase. +3. **Tạo API tests** — bao phủ status code, cấu trúc phản hồi, happy path và 1-2 trường hợp lỗi. +4. **Tạo E2E tests** — bao phủ workflow người dùng bằng semantic locator và assertion trên kết quả nhìn thấy được. +5. **Chạy và xác minh** — thực thi test vừa tạo và sửa lỗi hỏng ngay lập tức. + +Workflow tạo một bản tóm tắt kiểm thử và lưu nó vào thư mục implementation artifacts của dự án. + +### Mẫu Kiểm Thử + +Các test được tạo theo triết lý “đơn giản và dễ bảo trì”: + +- **Chỉ dùng API chuẩn của framework** — không kéo thêm utility ngoài hay abstraction tùy chỉnh +- **Semantic locator** cho UI test — dùng role, label, text thay vì CSS selector +- **Test độc lập** — không phụ thuộc thứ tự chạy +- **Không hardcode wait hoặc sleep** +- **Mô tả rõ ràng** để test cũng đóng vai trò tài liệu tính năng + +:::note[Phạm vi] +Workflow QA chỉ tạo test. Nếu bạn cần code review hoặc xác nhận story, hãy dùng workflow Code Review (`CR`). +::: + +### Khi Nào Nên Dùng QA Tích Hợp S���n + +- Cần bao phủ test nhanh cho một tính năng mới hoặc hiện có +- Muốn tự động hóa kiểm thử thân thiện với người mới mà không cần thiết lập phức tạp +- Muốn các pattern test chuẩn mà lập trình viên nào cũng đọc và bảo trì được +- Dự án nhỏ-trung bình, nơi chiến lược kiểm thử toàn diện là không cần thiết + +## Module Test Architect (TEA) + +TEA là một module độc lập cung cấp agent chuyên gia Murat cùng chín workflow có cấu trúc cho kiểm thử cấp doanh nghiệp. Nó vượt ra ngoài việc tạo test để bao gồm chiến lược kiểm thử, lập kế hoạch theo rủi ro, quality gate và truy vết yêu cầu. + +- **Tài liệu:** [TEA Module Docs](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/) +- **Cài đặt:** `npx bmad-method install` rồi chọn module TEA +- **npm:** [`bmad-method-test-architecture-enterprise`](https://www.npmjs.com/package/bmad-method-test-architecture-enterprise) + +### TEA Cung Cấp Gì + +| Workflow | Mục đích | +| --- | --- | +| Test Design | Tạo chiến lược kiểm thử toàn diện gắn với yêu cầu | +| ATDD | Phát triển hướng acceptance test với tiêu chí của stakeholder | +| Automate | Tạo test bằng pattern và utility nâng cao | +| Test Review | Kiểm tra chất lượng và độ bao phủ của test so với chiến lược | +| Traceability | Liên kết test ngược về yêu cầu để phục vụ audit và tuân thủ | +| NFR Assessment | Đánh giá các yêu cầu phi chức năng như hiệu năng, bảo mật | +| CI Setup | Cấu hình thực thi test trong pipeline tích hợp liên tục | +| Framework Scaffolding | Dựng hạ tầng và cấu trúc dự án kiểm thử | +| Release Gate | Ra quyết định phát hành go/no-go dựa trên dữ liệu | + +TEA cũng hỗ trợ ưu tiên theo rủi ro P0-P3 và tích hợp tùy chọn với Playwright Utils cùng công cụ MCP. + +### Khi Nào Nên Dùng TEA + +- Dự án cần truy vết yêu cầu hoặc tài liệu tuân thủ +- Đội ngũ cần ưu tiên kiểm thử theo rủi ro trên nhiều tính năng +- Môi trường doanh nghiệp có quality gate chính thức trước phát hành +- Miền nghiệp vụ phức tạp, nơi chiến lược kiểm thử phải được lên trước khi viết test +- Dự án đã vượt quá mô hình một workflow của QA tích hợp sẵn + +## Kiểm Thử Nằm Ở Đâu Trong Workflow + +Workflow QA Automate xuất hiện ở Phase 4 (Implementation) trong workflow map của BMad Method. Nó được thiết kế để chạy **sau khi hoàn tất trọn vẹn một epic** — tức là khi mọi story trong epic đó đã được triển khai và code review xong. Trình tự điển hình là: + +1. Với mỗi story trong epic: triển khai bằng Dev (`DS`), sau đó xác nhận bằng Code Review (`CR`) +2. Sau khi epic hoàn tất: tạo test bằng `QA` (thông qua Developer agent) hoặc workflow Automate của TEA +3. Chạy retrospective (`bmad-retrospective`) để ghi nhận bài học rút ra + +Workflow QA tích hợp sẵn làm việc trực tiếp từ source code mà không cần nạp tài liệu lập kế hoạch như PRD hay architecture. Các workflow của TEA có thể tích hợp với artifact lập kế hoạch ở các bước trước để phục vụ truy vết. + +Để hiểu rõ hơn kiểm thử nằm ở đâu trong quy trình tổng thể, xem [Workflow Map](./workflow-map.md). diff --git a/docs/vi-vn/reference/workflow-map.md b/docs/vi-vn/reference/workflow-map.md new file mode 100644 index 000000000..c4023e481 --- /dev/null +++ b/docs/vi-vn/reference/workflow-map.md @@ -0,0 +1,89 @@ +--- +title: "Sơ đồ workflow" +description: Tài liệu trực quan về các giai đoạn, quy trình và đầu ra của BMad Method +sidebar: + order: 1 +--- + +BMad Method (BMM) là một module trong hệ sinh thái BMad, tập trung vào các thực hành tốt nhất của kỹ nghệ ngữ cảnh và lập kế hoạch. AI agent hoạt động hiệu quả nhất khi có ngữ cảnh rõ ràng và có cấu trúc. Hệ thống BMM xây dựng ngữ cảnh đó theo tiến trình qua 4 giai đoạn riêng biệt. Mỗi giai đoạn, cùng với nhiều quy trình tùy chọn bên trong nó, tạo ra các tài liệu làm đầu vào cho giai đoạn kế tiếp, nhờ vậy agent luôn biết phải xây gì và vì sao. + +Lý do và các khái niệm nền tảng ở đây đến từ các phương pháp Agile đã được áp dụng rất thành công trong toàn ngành như một khung tư duy. + +Nếu có lúc nào bạn không chắc nên làm gì, skill `bmad-help` sẽ giúp bạn giữ đúng hướng hoặc biết bước tiếp theo. Bạn vẫn có thể dùng trang này để tham chiếu, nhưng `bmad-help` mang tính tương tác đầy đủ và nhanh hơn nhiều nếu bạn đã cài BMad Method. Ngoài ra, nếu bạn đang dùng thêm các module mở rộng BMad Method hoặc các module bổ sung khác, `bmad-help` cũng sẽ mở rộng theo để biết mọi thứ đang có sẵn và đưa ra lời khuyên tốt nhất tại thời điểm đó. + +Lưu ý quan trọng cuối cùng: mọi quy trình dưới đây đều có thể chạy trực tiếp bằng công cụ bạn chọn thông qua skill, hoặc bằng cách nạp agent trước rồi chọn mục tương ứng trong menu agent. + + + +

+ Mở sơ đồ trong tab mới ↗ +

+ +## Giai đoạn 1: Phân tích (tùy chọn) + +Khám phá không gian vấn đề và xác nhận ý tưởng trước khi cam kết đi vào lập kế hoạch. [**Tìm hiểu từng công cụ làm gì và nên dùng khi nào**](../explanation/analysis-phase.md). + +| Quy trình | Mục đích | Tạo ra | +| ------------------------------- | -------------------------------------------------------------------------- | ------------------------- | +| `bmad-brainstorming` | Động não ý tưởng dự án với sự điều phối của người dẫn dắt brainstorming | `brainstorming-report.md` | +| `bmad-domain-research`, `bmad-market-research`, `bmad-technical-research` | Xác thực giả định về thị trường, kỹ thuật hoặc miền nghiệp vụ | Kết quả nghiên cứu | +| `bmad-product-brief` | Ghi lại tầm nhìn chiến lược — phù hợp nhất khi concept của bạn đã rõ | `product-brief.md` | +| `bmad-prfaq` | Working Backwards — stress-test và rèn sắc concept sản phẩm của bạn | `prfaq-{project}.md` | + +## Giai đoạn 2: Lập kế hoạch + +Xác định cần xây gì và xây cho ai. + +| Quy trình | Mục đích | Tạo ra | +| --------------------------- | ---------------------------------------- | ------------ | +| `bmad-create-prd` | Xác định yêu cầu (FR/NFR) | `PRD.md` | +| `bmad-create-ux-design` | Thiết kế trải nghiệm người dùng khi UX là yếu tố quan trọng | `ux-spec.md` | + +## Giai đoạn 3: Định hình giải pháp + +Quyết định cách xây và chia nhỏ công việc thành các story. + +| Quy trình | Mục đích | Tạo ra | +| ----------------------------------------- | ------------------------------------------ | --------------------------- | +| `bmad-create-architecture` | Làm rõ các quyết định kỹ thuật | `architecture.md` kèm ADR | +| `bmad-create-epics-and-stories` | Phân rã yêu cầu thành các phần việc có thể triển khai | Các file epic chứa các story | +| `bmad-check-implementation-readiness` | Cổng kiểm tra trước khi triển khai | Quyết định PASS/CONCERNS/FAIL | + +## Giai đoạn 4: Triển khai + +Xây dựng từng story một. Tự động hóa toàn bộ giai đoạn 4 sẽ sớm ra mắt. + +| Quy trình | Mục đích | Tạo ra | +| -------------------------- | ------------------------------------------------------------------------ | -------------------------------- | +| `bmad-sprint-planning` | Khởi tạo theo dõi, thường chạy một lần mỗi dự án để sắp thứ tự chu trình phát triển | `sprint-status.yaml` | +| `bmad-create-story` | Chuẩn bị story tiếp theo cho implementation | `story-[slug].md` | +| `bmad-dev-story` | Triển khai story | Code chạy được + tests | +| `bmad-code-review` | Kiểm tra chất lượng phần triển khai | Được duyệt hoặc yêu cầu thay đổi | +| `bmad-correct-course` | Xử lý thay đổi lớn giữa sprint | Kế hoạch cập nhật hoặc định tuyến lại | +| `bmad-sprint-status` | Theo dõi tiến độ sprint và trạng thái story | Cập nhật trạng thái sprint | +| `bmad-retrospective` | Review sau khi hoàn tất epic | Bài học rút ra | + +## Luồng nhanh (nhánh song song) + +Bỏ qua giai đoạn 1-3 đối với những việc nhỏ, rõ và đã hiểu đầy đủ. + +| Quy trình | Mục đích | Tạo ra | +| ------------------ | --------------------------------------------------------------------------- | ---------------------- | +| `bmad-quick-dev` | Luồng nhanh hợp nhất — làm rõ yêu cầu, lập kế hoạch, triển khai, review và trình bày | `spec-*.md` + mã nguồn | + +## Quản lý ngữ cảnh + +Mỗi tài liệu sẽ trở thành ngữ cảnh cho giai đoạn tiếp theo. PRD cho architect biết những ràng buộc nào quan trọng. Tài liệu kiến trúc chỉ cho dev agent những mẫu cần tuân theo. File story cung cấp ngữ cảnh tập trung và đầy đủ cho việc triển khai. Nếu không có cấu trúc này, agent sẽ đưa ra quyết định thiếu nhất quán. + +### Bối cảnh dự án + +:::tip[Khuyến nghị] +Hãy tạo `project-context.md` để bảo đảm AI agent tuân theo quy tắc và sở thích của dự án. File này hoạt động như một bản hiến pháp cho dự án của bạn, nó dẫn dắt các quyết định triển khai xuyên suốt mọi quy trình. File tùy chọn này có thể được tạo ở cuối bước tạo kiến trúc, hoặc cũng có thể được sinh trong dự án hiện hữu để ghi lại những điều quan trọng cần giữ đồng bộ với quy ước đang có. +::: + +**Cách tạo:** + +- **Thủ công** — Tạo `_bmad-output/project-context.md` với stack công nghệ và các quy tắc triển khai của bạn +- **Tự sinh** — Chạy `bmad-generate-project-context` để sinh tự động từ architecture hoặc codebase + +[**Tìm hiểu thêm về project-context.md**](../explanation/project-context.md) diff --git a/docs/vi-vn/roadmap.mdx b/docs/vi-vn/roadmap.mdx new file mode 100644 index 000000000..1c7fd9059 --- /dev/null +++ b/docs/vi-vn/roadmap.mdx @@ -0,0 +1,136 @@ +--- +title: Lộ trình +description: Điều gì sẽ đến tiếp theo với BMad - tính năng mới, cải tiến và đóng góp từ cộng đồng +--- + +# Lộ Trình Công Khai Của BMad Method + +BMad Method, BMad Method Module (BMM) và BMad Builder (BMB) đang tiếp tục phát triển. Đây là những gì chúng tôi đang thực hiện và sắp ra mắt. + +
+ +

Đang triển khai

+ +
+
+ 🧩 +

Kiến Trúc Skills Phổ Quát

+

Một skill, dùng trên mọi nền tảng. Viết một lần, chạy ở khắp nơi.

+
+
+ 🏗️ +

BMad Builder v1

+

Tạo AI agent và workflow sẵn sàng cho production với evals, teams và graceful degradation được tích hợp sẵn.

+
+
+ 🧠 +

Hệ Thống Project Context

+

AI thực sự hiểu dự án của bạn. Ngữ cảnh nhận biết framework và phát triển cùng codebase của bạn.

+
+
+ 📦 +

Skills Tập Trung

+

Cài một lần, dùng ở mọi nơi. Chia sẻ skills giữa các dự án mà không làm rối file.

+
+
+ 🔄 +

Skills Thích Ứng

+

Skills hiểu công cụ bạn đang dùng. Biến thể tối ưu cho Claude, Codex, Kimi, OpenCode và nhiều công cụ khác.

+
+
+ 📝 +

Blog BMad Team Pros

+

Các bài hướng dẫn, bài viết và góc nhìn từ đội ngũ. Sắp ra mắt.

+
+
+ +

Mới bắt đầu

+ +
+
+ 🏪 +

Chợ Skills

+

Khám phá, cài đặt và cập nhật skills do cộng đồng xây dựng. Chỉ cần một lệnh curl là có thêm siêu năng lực.

+
+
+ 🎨 +

Tùy Biến Workflow

+

Biến nó thành của riêng bạn. Tích hợp Jira, Linear, output tùy chỉnh: workflow của bạn, luật của bạn.

+
+
+ 🚀 +

Tối Ưu Hóa Phase 1-3

+

Lập kế hoạch cực nhanh với cơ chế thu thập context bằng sub-agent. YOLO mode kết hợp với hướng dẫn có kiểm soát.

+
+
+ 🌐 +

Sẵn Sàng Cho Doanh Nghiệp

+

SSO, audit logs, team workspaces. Toàn bộ phần “không hào nhoáng” nhưng khiến doanh nghiệp yên tâm triển khai.

+
+
+ 💎 +

Bùng Nổ Module Cộng Đồng

+

Giải trí, bảo mật, trị liệu, roleplay và nhiều hơn nữa. Mở rộng nền tảng BMad Method.

+
+
+ +

Tự Động Hóa Dev Loop

+

Chế độ autopilot tùy chọn cho phát triển phần mềm. Để AI xử lý flow trong khi vẫn giữ chất lượng ở mức cao.

+
+
+ +

Cộng đồng và đội ngũ

+ +
+
+ 🎙️ +

Podcast The BMad Method

+

Các cuộc trò chuyện về phát triển phần mềm AI-native. Ra mắt ngày 1 tháng 3 năm 2026.

+
+
+ 🎓 +

Lớp Master Class The BMad Method

+

Đi từ người dùng thành chuyên gia. Đào sâu vào từng phase, từng workflow và từng bí quyết.

+
+
+ 🏗️ +

Lớp Master Class BMad Builder

+

Tự xây agent của riêng bạn. Kỹ thuật nâng cao cho lúc bạn đã sẵn sàng tạo ra thứ mới, không chỉ sử dụng.

+
+
+ +

BMad Prototype First

+

Từ ý tưởng đến prototype chạy được chỉ trong một phiên làm việc. Tạo ứng dụng mơ ước của bạn như một tác phẩm thủ công tinh chỉnh.

+
+
+ 🌴 +

BMad BALM!

+

Quản trị cuộc sống cho người dùng AI-native. Tasks, habits, goals: AI copilot của bạn cho mọi thứ.

+
+
+ 🖥️ +

Giao Diện Chính Thức

+

Một giao diện đẹp cho toàn bộ hệ sinh thái BMad. Sức mạnh của CLI, độ hoàn thiện của GUI.

+
+
+ 🔒 +

BMad in a Box

+

Tự host, air-gapped, chuẩn doanh nghiệp. Trợ lý AI của bạn, hạ tầng của bạn, quyền kiểm soát của bạn.

+
+
+ +
+

Muốn đóng góp?

+

+ Đây mới chỉ là một phần của những gì đang được lên kế hoạch. Đội ngũ mã nguồn mở BMad luôn chào đón contributor!
+ Tham gia cùng chúng tôi trên GitHub để cùng định hình tương lai của phát triển phần mềm hướng AI. +

+

+ Nếu bạn thích những gì chúng tôi đang xây dựng, chúng tôi trân trọng cả hỗ trợ một lần lẫn hàng tháng. +

+

+ Với tài trợ doanh nghiệp, hợp tác, diễn thuyết, đào tạo hoặc liên hệ truyền thông:{" "} + contact@bmadcode.com +

+
+
diff --git a/docs/vi-vn/tutorials/getting-started.md b/docs/vi-vn/tutorials/getting-started.md new file mode 100644 index 000000000..cfd06a5d5 --- /dev/null +++ b/docs/vi-vn/tutorials/getting-started.md @@ -0,0 +1,276 @@ +--- +title: "Bắt đầu" +description: Cài đặt BMad và xây dựng dự án đầu tiên của bạn +--- + +Xây dựng phần mềm nhanh hơn bằng các workflow vận hành bởi AI, với những agent chuyên biệt hướng dẫn bạn qua các bước lập kế hoạch, kiến trúc và triển khai. + +## Bạn Sẽ Học Được Gì + +- Cài đặt và khởi tạo BMad Method cho một dự án mới +- Dùng **BMad-Help** — trợ lý thông minh biết bước tiếp theo bạn nên làm gì +- Chọn nhánh lập kế hoạch phù hợp với quy mô dự án +- Đi qua các phase từ yêu cầu đến code chạy được +- Sử dụng agent và workflow hiệu quả + +:::note[Điều kiện tiên quyết] +- **Node.js 20+** — Bắt buộc cho trình cài đặt +- **Git** — Khuyến nghị để quản lý phiên bản +- **IDE có AI** — Claude Code, Cursor hoặc công cụ tương tự +- **Một ý tưởng dự án** — Chỉ cần đơn giản cũng đủ để học +::: + +:::tip[Cách Dễ Nhất] +**Cài đặt** → `npx bmad-method install` +**Hỏi** → `bmad-help what should I do first?` +**Xây dựng** → Để BMad-Help dẫn bạn qua từng workflow +::: + +## Làm Quen Với BMad-Help: Người Dẫn Đường Thông Minh Của Bạn + +**BMad-Help là cách nhanh nhất để bắt đầu với BMad.** Bạn không cần phải nhớ workflow hay phase nào cả, chỉ cần hỏi, và BMad-Help sẽ: + +- **Kiểm tra dự án của bạn** để xem những gì đã hoàn thành +- **Hiển thị các lựa chọn** dựa trên những module bạn đã cài +- **Đề xuất bước tiếp theo** — bao gồm cả tác vụ bắt buộc đầu tiên +- **Trả lời câu hỏi** như “Tôi có ý tưởng cho một sản phẩm SaaS, tôi nên bắt đầu từ đâu?” + +### Cách Dùng BMad-Help + +Chạy trong AI IDE của bạn bằng cách gọi skill: + +```text +bmad-help +``` + +Hoặc ghép cùng câu hỏi để nhận hướng dẫn có ngữ cảnh: + +```text +bmad-help I have an idea for a SaaS product, I already know all the features I want. where do I get started? +``` + +BMad-Help sẽ trả lời: +- Điều gì được khuyến nghị trong tình huống của bạn +- Tác vụ bắt buộc đầu tiên là gì +- Phần còn lại của quy trình sẽ trông như thế nào + +### Nó Cũng Điều Khiển Workflow + +BMad-Help không chỉ trả lời câu hỏi — **nó còn tự động chạy ở cuối mỗi workflow** để cho bạn biết chính xác bước tiếp theo cần làm là gì. Không phải đoán, không phải lục tài liệu, chỉ có chỉ dẫn rõ ràng về workflow bắt buộc tiếp theo. + +:::tip[Bắt Đầu Từ Đây] +Sau khi cài BMad, hãy gọi skill `bmad-help` ngay. Nó sẽ nhận biết các module bạn đã cài và hướng bạn đến điểm bắt đầu phù hợp cho dự án. +::: + +## Hiểu Về BMad + +BMad giúp bạn xây dựng phần mềm thông qua các workflow có hướng dẫn với những AI agent chuyên biệt. Quy trình gồm bốn phase: + +| Phase | Tên | Điều xảy ra | +| ----- | -------------- | --------------------------------------------------- | +| 1 | Analysis | Brainstorming, nghiên cứu, product brief hoặc PRFAQ *(tùy chọn)* | +| 2 | Planning | Tạo tài liệu yêu cầu (PRD hoặc spec) | +| 3 | Solutioning | Thiết kế kiến trúc *(chỉ dành cho BMad Method/Enterprise)* | +| 4 | Implementation | Xây dựng theo từng epic, từng story | + +**[Mở Workflow Map](../reference/workflow-map.md)** để khám phá các phase, workflow và cách quản lý context. + +Dựa trên độ phức tạp của dự án, BMad cung cấp ba nhánh lập kế hoạch: + +| Nhánh | Phù hợp nhất với | Tài liệu được tạo | +| --------------- | ------------------------------------------------------ | -------------------------------------- | +| **Quick Flow** | Sửa lỗi, tính năng đơn giản, phạm vi rõ ràng (1-15 story) | Chỉ spec | +| **BMad Method** | Sản phẩm, nền tảng, tính năng phức tạp (10-50+ story) | PRD + Architecture + UX | +| **Enterprise** | Yêu cầu tuân thủ, hệ thống đa tenant (30+ story) | PRD + Architecture + Security + DevOps | + +:::note +Số lượng story chỉ là gợi ý, không phải định nghĩa cứng. Hãy chọn nhánh dựa trên nhu cầu lập kế hoạch, không phải phép đếm story. +::: + +## Cài Đặt + +Mở terminal trong thư mục dự án và chạy: + +```bash +npx bmad-method install +``` + +Nếu bạn muốn dùng bản prerelease mới nhất thay vì kênh release mặc định, hãy dùng `npx bmad-method@next install`. + +Khi được hỏi chọn module, hãy chọn **BMad Method**. + +Trình cài đặt sẽ tạo hai thư mục: +- `_bmad/` — agents, workflows, tasks và cấu hình +- `_bmad-output/` — hiện tại để trống, nhưng đây là nơi các artifact của bạn sẽ được lưu + +:::tip[Bước Tiếp Theo Của Bạn] +Mở AI IDE trong thư mục dự án rồi chạy: + +```text +bmad-help +``` + +BMad-Help sẽ nhận biết bạn đã làm đến đâu và đề xuất chính xác bước tiếp theo. Bạn cũng có thể hỏi những câu như “Tôi có những lựa chọn nào?” hoặc “Tôi có ý tưởng SaaS, nên bắt đầu từ đâu?” +::: + +:::note[Cách Nạp Agent Và Chạy Workflow] +Mỗi workflow có một **skill** được gọi bằng tên trong IDE của bạn, ví dụ `bmad-create-prd`. Công cụ AI sẽ nhận diện tên `bmad-*` và chạy nó, bạn không cần nạp agent riêng. Bạn cũng có thể gọi trực tiếp skill của agent để trò chuyện tổng quát, ví dụ `bmad-agent-pm` cho PM agent. +::: + +:::caution[Chat Mới] +Luôn bắt đầu một chat mới cho mỗi workflow. Điều này tránh các vấn đề do giới hạn context gây ra. +::: + +## Bước 1: Tạo Kế Hoạch + +Đi qua các phase 1-3. **Dùng chat mới cho từng workflow.** + +:::tip[Project Context (Tùy chọn)] +Trước khi bắt đầu, hãy cân nhắc tạo `project-context.md` để ghi lại các ưu tiên kỹ thuật và quy tắc triển khai. Nhờ vậy mọi AI agent sẽ tuân theo cùng một quy ước trong suốt dự án. + +Bạn có thể tạo thủ công tại `_bmad-output/project-context.md` hoặc sinh ra sau phần kiến trúc bằng `bmad-generate-project-context`. [Xem thêm](../explanation/project-context.md). +::: + +### Phase 1: Analysis (Tùy chọn) + +Tất cả workflow trong phase này đều là tùy chọn. [**Chưa chắc nên dùng cái nào?**](../explanation/analysis-phase.md) +- **brainstorming** (`bmad-brainstorming`) — Gợi ý ý tưởng có hướng dẫn +- **research** (`bmad-market-research` / `bmad-domain-research` / `bmad-technical-research`) — Nghiên cứu thị trường, miền nghiệp vụ và kỹ thuật +- **product-brief** (`bmad-product-brief`) — Tài liệu nền tảng được khuyến nghị khi concept của bạn đã rõ +- **prfaq** (`bmad-prfaq`) — Bài kiểm tra Working Backwards để stress-test và rèn sắc concept sản phẩm của bạn + +### Phase 2: Planning (Bắt buộc) + +**Với nhánh BMad Method và Enterprise:** +1. Gọi **PM agent** (`bmad-agent-pm`) trong một chat mới +2. Chạy workflow `bmad-create-prd` (`bmad-create-prd`) +3. Kết quả: `PRD.md` + +**Với nhánh Quick Flow:** +- Chạy `bmad-quick-dev` — workflow này gộp cả planning và implementation trong một lần, nên bạn có thể chuyển thẳng sang triển khai + +:::note[Thiết kế UX (Tùy chọn)] +Nếu dự án của bạn có giao diện người dùng, hãy gọi **UX-Designer agent** (`bmad-agent-ux-designer`) và chạy workflow thiết kế UX (`bmad-create-ux-design`) sau khi tạo PRD. +::: + +### Phase 3: Solutioning (BMad Method/Enterprise) + +**Tạo Architecture** +1. Gọi **Architect agent** (`bmad-agent-architect`) trong một chat mới +2. Chạy `bmad-create-architecture` (`bmad-create-architecture`) +3. Kết quả: tài liệu kiến trúc chứa các quyết định kỹ thuật + +**Tạo Epics và Stories** + +:::tip[Cải tiến trong V6] +Epics và stories giờ được tạo *sau* kiến trúc. Điều này giúp story có chất lượng tốt hơn vì các quyết định kiến trúc như database, API pattern và tech stack ảnh hưởng trực tiếp đến cách chia nhỏ công việc. +::: + +1. Gọi **PM agent** (`bmad-agent-pm`) trong một chat mới +2. Chạy `bmad-create-epics-and-stories` (`bmad-create-epics-and-stories`) +3. Workflow sẽ dùng cả PRD lẫn Architecture để tạo story có đủ ngữ cảnh kỹ thuật + +**Kiểm tra mức sẵn sàng để triển khai** *(Rất nên dùng)* +1. Gọi **Architect agent** (`bmad-agent-architect`) trong một chat mới +2. Chạy `bmad-check-implementation-readiness` (`bmad-check-implementation-readiness`) +3. Xác nhận tính nhất quán giữa toàn bộ tài liệu lập kế hoạch + +## Bước 2: Xây Dựng Dự Án + +Sau khi lập kế hoạch xong, chuyển sang implementation. **Mỗi workflow nên chạy trong một chat mới.** + +### Khởi Tạo Sprint Planning + +Gọi **Developer agent** (`bmad-agent-dev`) và chạy `bmad-sprint-planning` (`bmad-sprint-planning`). Workflow này sẽ tạo `sprint-status.yaml` để theo dõi toàn bộ epic và story. + +### Chu Trình Xây Dựng + +Với mỗi story, lặp lại chu trình này trong chat mới: + +| Bước | Agent | Workflow | Lệnh | Mục đích | +| ---- | ----- | -------------- | -------------------------- | ---------------------------------- | +| 1 | DEV | `bmad-create-story` | `bmad-create-story` | Tạo file story từ epic | +| 2 | DEV | `bmad-dev-story` | `bmad-dev-story` | Triển khai story | +| 3 | DEV | `bmad-code-review` | `bmad-code-review` | Kiểm tra chất lượng *(khuyến nghị)* | + +Sau khi hoàn tất tất cả story trong một epic, hãy gọi **Developer agent** (`bmad-agent-dev`) và chạy `bmad-retrospective` (`bmad-retrospective`). + +## Bạn Đã Hoàn Thành Những Gì + +Bạn đã nắm được nền tảng để xây dựng với BMad: + +- Đã cài BMad và cấu hình cho IDE của bạn +- Đã khởi tạo dự án theo nhánh lập kế hoạch phù hợp +- Đã tạo các tài liệu lập kế hoạch (PRD, Architecture, Epics và Stories) +- Đã hiểu chu trình triển khai trong implementation + +Dự án của bạn bây giờ sẽ có dạng: + +```text +your-project/ +├── _bmad/ # Cấu hình BMad +├── _bmad-output/ +│ ├── planning-artifacts/ +│ │ ├── PRD.md # Tài liệu yêu cầu của bạn +│ │ ├── architecture.md # Các quyết định kỹ thuật +│ │ └── epics/ # Các file epic và story +│ ├── implementation-artifacts/ +│ │ └── sprint-status.yaml # Theo dõi sprint +│ └── project-context.md # Quy tắc triển khai (tùy chọn) +└── ... +``` + +## Tra Cứu Nhanh + +| Workflow | Lệnh | Agent | Mục đích | +| ------------------------------------- | ------------------------------------------ | --------- | ----------------------------------------------- | +| **`bmad-help`** ⭐ | `bmad-help` | Bất kỳ | **Người dẫn đường thông minh của bạn — hỏi gì cũng được!** | +| `bmad-create-prd` | `bmad-create-prd` | PM | Tạo tài liệu yêu cầu sản phẩm | +| `bmad-create-architecture` | `bmad-create-architecture` | Architect | Tạo tài liệu kiến trúc | +| `bmad-generate-project-context` | `bmad-generate-project-context` | Analyst | Tạo file project context | +| `bmad-create-epics-and-stories` | `bmad-create-epics-and-stories` | PM | Phân rã PRD thành epics | +| `bmad-check-implementation-readiness` | `bmad-check-implementation-readiness` | Architect | Kiểm tra độ nhất quán của kế hoạch | +| `bmad-sprint-planning` | `bmad-sprint-planning` | DEV | Khởi tạo theo dõi sprint | +| `bmad-create-story` | `bmad-create-story` | DEV | Tạo file story | +| `bmad-dev-story` | `bmad-dev-story` | DEV | Triển khai một story | +| `bmad-code-review` | `bmad-code-review` | DEV | Review phần code đã triển khai | + +## Câu Hỏi Thường Gặp + +**Lúc nào cũng cần kiến trúc à?** +Chỉ với nhánh BMad Method và Enterprise. Quick Flow bỏ qua bước kiến trúc và chuyển thẳng từ spec sang implementation. + +**Tôi có thể đổi kế hoạch về sau không?** +Có. Workflow `bmad-correct-course` (`bmad-correct-course`) xử lý thay đổi phạm vi giữa chừng. + +**Nếu tôi muốn brainstorming trước thì sao?** +Gọi Analyst agent (`bmad-agent-analyst`) và chạy `bmad-brainstorming` (`bmad-brainstorming`) trước khi bắt đầu PRD. + +**Tôi có cần tuân theo đúng thứ tự tuyệt đối không?** +Không hẳn. Khi đã quen flow, bạn có thể chạy workflow trực tiếp bằng bảng Tra Cứu Nhanh ở trên. + +## Nhận Hỗ Trợ + +:::tip[Điểm Dừng Đầu Tiên: BMad-Help] +**Hãy gọi `bmad-help` bất cứ lúc nào** — đây là cách nhanh nhất để gỡ vướng. Bạn có thể hỏi: +- "Tôi nên làm gì sau khi cài đặt?" +- "Tôi đang kẹt ở workflow X" +- "Tôi có những lựa chọn nào cho Y?" +- "Cho tôi xem đến giờ đã làm được gì" + +BMad-Help sẽ kiểm tra dự án, phát hiện những gì bạn đã hoàn thành và chỉ cho bạn chính xác bước cần làm tiếp theo. +::: + +- **Trong workflow** — Các agent sẽ hướng dẫn bạn bằng câu hỏi và giải thích +- **Cộng đồng** — [Discord](https://discord.gg/gk8jAdXWmj) (#bmad-method-help, #report-bugs-and-issues) + +## Những Điểm Cần Ghi Nhớ + +:::tip[Hãy Nhớ Các Điểm Này] +- **Bắt đầu với `bmad-help`** — Trợ lý thông minh hiểu dự án và các lựa chọn của bạn +- **Luôn dùng chat mới** — Mỗi workflow nên bắt đầu trong một chat riêng +- **Nhánh rất quan trọng** — Quick Flow dùng `bmad-quick-dev`; Method/Enterprise cần PRD và kiến trúc +- **BMad-Help chạy tự động** — Mỗi workflow đều kết thúc bằng hướng dẫn về bước tiếp theo +::: + +Sẵn sàng bắt đầu chưa? Hãy cài BMad, gọi `bmad-help`, và để người dẫn đường thông minh của bạn đưa bạn đi tiếp. diff --git a/docs/zh-cn/_STYLE_GUIDE.md b/docs/zh-cn/_STYLE_GUIDE.md index 13cb44d02..39aacee59 100644 --- a/docs/zh-cn/_STYLE_GUIDE.md +++ b/docs/zh-cn/_STYLE_GUIDE.md @@ -353,7 +353,7 @@ Only for BMad Method and Enterprise tracks. Quick Flow skips to implementation. ### Can I change my plan later? -Yes. The SM agent has a `bmad-correct-course` workflow for handling scope changes. +Yes. The `bmad-correct-course` workflow handles scope changes mid-implementation. **Have a question not answered here?** [Open an issue](...) or ask in [Discord](...). ``` diff --git a/docs/zh-cn/how-to/install-bmad.md b/docs/zh-cn/how-to/install-bmad.md index e9fc1af9a..3c5ceff44 100644 --- a/docs/zh-cn/how-to/install-bmad.md +++ b/docs/zh-cn/how-to/install-bmad.md @@ -72,7 +72,7 @@ npx github:bmad-code-org/BMAD-METHOD install ### 5. 按照提示操作 -安装程序会引导你完成剩余步骤——自定义内容、设置等。 +安装程序会引导你完成剩余步骤——设置、工具集成等。 ## 你将获得 diff --git a/docs/zh-cn/how-to/non-interactive-installation.md b/docs/zh-cn/how-to/non-interactive-installation.md index fdcfbc9fd..788c18d52 100644 --- a/docs/zh-cn/how-to/non-interactive-installation.md +++ b/docs/zh-cn/how-to/non-interactive-installation.md @@ -27,7 +27,6 @@ sidebar: | `--directory ` | 安装目录 | `--directory ~/projects/myapp` | | `--modules ` | 逗号分隔的模块 ID | `--modules bmm,bmb` | | `--tools ` | 逗号分隔的工具/IDE ID(使用 `none` 跳过) | `--tools claude-code,cursor` 或 `--tools none` | -| `--custom-content ` | 逗号分隔的自定义模块路径 | `--custom-content ~/my-module,~/another-module` | | `--action ` | 对现有安装的操作:`install`(默认)、`update` 或 `quick-update` | `--action quick-update` | ### 核心配置 @@ -61,7 +60,7 @@ sidebar: **推荐:** `claude-code`、`cursor` -运行一次 `npx bmad-method install` 交互式安装以查看完整的当前支持工具列表,或查看 [平台代码配置](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/cli/installers/lib/ide/platform-codes.yaml)。 +运行一次 `npx bmad-method install` 交互式安装以查看完整的当前支持工具列表,或查看 [平台代码配置](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/installer/ide/platform-codes.yaml)。 ## 安装模式 @@ -108,16 +107,6 @@ npx bmad-method install \ --action quick-update ``` -### 使用自定义内容安装 - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --modules bmm \ - --custom-content ~/my-custom-module,~/another-module \ - --tools claude-code -``` - ## 安装结果 - 项目中完全配置的 `_bmad/` 目录 @@ -131,12 +120,11 @@ BMad 会验证你提供的所有参数: - **目录** — 必须是具有写入权限的有效路径 - **模块** — 对无效的模块 ID 发出警告(但不会失败) - **工具** — 对无效的工具 ID 发出警告(但不会失败) -- **自定义内容** — 每个路径必须包含有效的 `module.yaml` 文件 - **操作** — 必须是以下之一:`install`、`update`、`quick-update` 无效值将: 1. 显示错误并退出(对于目录等关键选项) -2. 显示警告并跳过(对于自定义内容等可选项目) +2. 显示警告并跳过(对于可选项目) 3. 回退到交互式提示(对于缺失的必需值) :::tip[最佳实践] @@ -159,13 +147,6 @@ BMad 会验证你提供的所有参数: - 验证模块 ID 是否正确 - 外部模块必须在注册表中可用 -### 自定义内容路径无效 - -确保每个自定义内容路径: -- 指向一个目录 -- 在根目录中包含 `module.yaml` 文件 -- 在 `module.yaml` 中有 `code` 字段 - :::note[仍然卡住了?] 使用 `--debug` 获取详细输出,尝试交互模式定位问题,或在 提交反馈。 ::: diff --git a/docs/zh-cn/how-to/upgrade-to-v6.md b/docs/zh-cn/how-to/upgrade-to-v6.md index eb28c9c38..8a3ed4a46 100644 --- a/docs/zh-cn/how-to/upgrade-to-v6.md +++ b/docs/zh-cn/how-to/upgrade-to-v6.md @@ -65,8 +65,8 @@ v6 新技能会安装到: 1. 完成 v6 安装 2. 将 `epics.md` 或 `epics/epic*.md` 放入 `_bmad-output/planning-artifacts/` -3. 运行 Scrum Master 的 `bmad-sprint-planning` 工作流 -4. 告诉 SM 哪些史诗/故事已经完成 +3. 运行 Developer 的 `bmad-sprint-planning` 工作流 +4. 告知智能体哪些史诗/故事已经完成 ## 你将获得 diff --git a/docs/zh-cn/reference/agents.md b/docs/zh-cn/reference/agents.md index 803ad3d02..3fbebcca9 100644 --- a/docs/zh-cn/reference/agents.md +++ b/docs/zh-cn/reference/agents.md @@ -11,21 +11,18 @@ sidebar: | 智能体 | Skill ID | 触发器 | 主要 workflow | | --- | --- | --- | --- | -| Analyst (Mary) | `bmad-analyst` | `BP`、`RS`、`CB`、`DP` | Brainstorm、Research、Create Brief、Document Project | +| Analyst (Mary) | `bmad-analyst` | `BP`、`MR`、`DR`、`TR`、`CB`、`WB`、`DP` | Brainstorm、Market Research、Domain Research、Technical Research、Create Brief、PRFAQ Challenge、Document Project | | Product Manager (John) | `bmad-pm` | `CP`、`VP`、`EP`、`CE`、`IR`、`CC` | Create/Validate/Edit PRD、Create Epics and Stories、Implementation Readiness、Correct Course | | Architect (Winston) | `bmad-architect` | `CA`、`IR` | Create Architecture、Implementation Readiness | -| Scrum Master (Bob) | `bmad-sm` | `SP`、`CS`、`ER`、`CC` | Sprint Planning、Create Story、Epic Retrospective、Correct Course | -| Developer (Amelia) | `bmad-dev` | `DS`、`CR` | Dev Story、Code Review | -| QA Engineer (Quinn) | `bmad-qa` | `QA` | Automate(为既有功能生成测试) | -| Quick Flow Solo Dev (Barry) | `bmad-master` | `QD`、`CR` | Quick Dev、Code Review | +| Developer (Amelia) | `bmad-agent-dev` | `DS`、`QD`、`QA`、`CR`、`SP`、`CS`、`ER` | Dev Story、Quick Dev、QA Test Generation、Code Review、Sprint Planning、Create Story、Epic Retrospective | | UX Designer (Sally) | `bmad-ux-designer` | `CU` | Create UX Design | | Technical Writer (Paige) | `bmad-tech-writer` | `DP`、`WD`、`US`、`MG`、`VD`、`EC` | Document Project、Write Document、Update Standards、Mermaid Generate、Validate Doc、Explain Concept | ## 使用说明 -- `Skill ID` 是直接调用该智能体的名称(例如 `bmad-dev`) +- `Skill ID` 是直接调用该智能体的名称(例如 `bmad-agent-dev`) - 触发器是进入智能体会话后可使用的菜单短码 -- QA(Quinn)是 BMM 内置轻量测试角色;完整 TEA 能力位于独立模块 +- QA 测试生成由 `bmad-qa-generate-e2e-tests` workflow skill 处理,通过 Developer 智能体调用;完整 TEA 能力位于独立模块 ## 触发器类型 diff --git a/docs/zh-cn/reference/commands.md b/docs/zh-cn/reference/commands.md index 99680f32d..118aee280 100644 --- a/docs/zh-cn/reference/commands.md +++ b/docs/zh-cn/reference/commands.md @@ -48,12 +48,12 @@ sidebar: │ └── SKILL.md ├── bmad-create-prd/ │ └── SKILL.md -├── bmad-dev/ +├── bmad-agent-dev/ │ └── SKILL.md └── ... ``` -skill 目录名就是调用名,例如 `bmad-dev/` 对应 skill `bmad-dev`。 +skill 目录名就是调用名,例如 `bmad-agent-dev/` 对应 skill `bmad-agent-dev`。 ## 如何发现可用 skills @@ -73,10 +73,9 @@ skill 目录名就是调用名,例如 `bmad-dev/` 对应 skill `bmad-dev`。 | 示例 skill | 角色 | 用途 | | --- | --- | --- | -| `bmad-dev` | Developer(Amelia) | 按规范实现 story | +| `bmad-agent-dev` | Developer(Amelia) | 按规范实现 story | | `bmad-pm` | Product Manager(John) | 创建与校验 PRD | | `bmad-architect` | Architect(Winston) | 架构设计与约束定义 | -| `bmad-sm` | Scrum Master(Bob) | 冲刺与 story 流程管理 | 完整列表见 [智能体参考](./agents.md)。 @@ -105,7 +104,7 @@ skill 目录名就是调用名,例如 `bmad-dev/` 对应 skill `bmad-dev`。 ## 命名规则 -所有技能统一以 `bmad-` 开头,后接语义化名称(如 `bmad-dev`、`bmad-create-prd`、`bmad-help`)。 +所有技能统一以 `bmad-` 开头,后接语义化名称(如 `bmad-agent-dev`、`bmad-create-prd`、`bmad-help`)。 ## 故障排查 diff --git a/docs/zh-cn/reference/testing.md b/docs/zh-cn/reference/testing.md index a3f035ffb..c5b7e3890 100644 --- a/docs/zh-cn/reference/testing.md +++ b/docs/zh-cn/reference/testing.md @@ -1,17 +1,17 @@ --- title: "测试选项" -description: 内置 QA(Quinn)与 TEA 模块对比:何时用哪个、各自边界是什么 +description: 内置 QA workflow 与 TEA 模块对比:何时用哪个、各自边界是什么 sidebar: order: 5 --- BMad 有两条测试路径: -- **Quinn(内置 QA)**:快速生成可运行测试 +- **内置 QA workflow**:快速生成可运行测试 - **TEA(可选模块)**:企业级测试策略与治理能力 -## 该选 Quinn 还是 TEA? +## 该选内置 QA 还是 TEA? -| 维度 | Quinn(内置 QA) | TEA 模块 | +| 维度 | 内置 QA | TEA 模块 | | --- | --- | --- | | 最适合 | 中小项目、快速补覆盖 | 大型项目、受监管或复杂业务 | | 安装成本 | 无需额外安装(BMM 内置) | 需通过安装器单独选择 | @@ -21,20 +21,20 @@ BMad 有两条测试路径: | workflow 数量 | 1(Automate) | 9(设计/自动化/审查/追溯等) | :::tip[默认建议] -大多数项目先用 Quinn。只有当你需要质量门控、合规追溯或系统化测试治理时,再引入 TEA。 +大多数项目先用内置 QA workflow。只有当你需要质量门控、合规追溯或系统化测试治理时,再引入 TEA。 ::: -## 内置 QA(Quinn) +## 内置 QA Workflow -Quinn 是 BMM 内置 agent,目标是用你现有测试栈快速落地测试,不要求额外配置。 +内置 QA workflow(`bmad-qa-generate-e2e-tests`)是 BMM 模块的一部分,通过 Developer 智能体调用。目标是用你现有测试栈快速落地测试,不要求额外配置。 **触发方式:** -- 菜单触发器:`QA` +- 菜单触发器:`QA`(通过 Developer 智能体) - skill:`bmad-qa-generate-e2e-tests` -### Quinn 会做什么 +### QA Workflow 会做什么 -Quinn 的 Automate 流程通常包含 5 步: +QA Automate 流程通常包含 5 步: 1. 检测现有测试框架(如 Jest、Vitest、Playwright、Cypress) 2. 确认待测功能(手动指定或自动发现) 3. 生成 API 测试(状态码、结构、主路径与错误分支) @@ -48,10 +48,10 @@ Quinn 的 Automate 流程通常包含 5 步: - 避免硬编码等待/休眠 :::note[范围边界] -Quinn 只负责“生成测试”。如需实现质量评审与故事验收,请配合代码审查 workflow(`CR` / `bmad-code-review`)。 +QA workflow 只负责”生成测试”。如需实现质量评审与故事验收,请配合代码审查 workflow(`CR` / `bmad-code-review`)。 ::: -### 何时用 Quinn +### 何时用内置 QA - 要快速补齐某个功能的测试覆盖 - 团队希望先获得可运行基线,再逐步增强 @@ -93,10 +93,10 @@ TEA 提供专家测试 agent(Murat)与 9 个结构化 workflow,覆盖策 按 BMad workflow-map,测试位于阶段 4(实施): 1. epic 内逐个 story:开发(`DS` / `bmad-dev-story`)+ 代码审查(`CR` / `bmad-code-review`) -2. epic 完成后:用 Quinn 或 TEA 的 Automate 统一生成/补齐测试 +2. epic 完成后:用 `QA`(通过 Developer 智能体)或 TEA 的 Automate 统一生成/补齐测试 3. 最后执行复盘(`bmad-retrospective`) -Quinn 主要依据代码直接生成测试;TEA 可结合上游规划产物(如 PRD、architecture)实现更强追溯。 +内置 QA workflow 主要依据代码直接生成测试;TEA 可结合上游规划产物(如 PRD、architecture)实现更强追溯。 ## 相关参考 diff --git a/docs/zh-cn/tutorials/getting-started.md b/docs/zh-cn/tutorials/getting-started.md index 753a88a8f..aa1e5b610 100644 --- a/docs/zh-cn/tutorials/getting-started.md +++ b/docs/zh-cn/tutorials/getting-started.md @@ -180,7 +180,7 @@ BMad-Help 将检测你已完成的内容,并准确推荐下一步该做什么 ### 初始化冲刺规划 -调用 **SM 智能体**(`bmad-agent-sm`)并运行 `bmad-sprint-planning`(`bmad-sprint-planning`)。这会创建 `sprint-status.yaml` 来跟踪所有史诗和故事。 +调用 **Developer 智能体**(`bmad-agent-dev`)并运行 `bmad-sprint-planning`(`bmad-sprint-planning`)。这会创建 `sprint-status.yaml` 来跟踪所有史诗和故事。 ### 构建周期 @@ -188,11 +188,11 @@ BMad-Help 将检测你已完成的内容,并准确推荐下一步该做什么 | 步骤 | 智能体 | 工作流 | 命令 | 目的 | | ---- | ------ | ------------ | ----------------------- | ------------------------------- | -| 1 | SM | `bmad-create-story` | `bmad-create-story` | 从史诗创建故事文件 | +| 1 | DEV | `bmad-create-story` | `bmad-create-story` | 从史诗创建故事文件 | | 2 | DEV | `bmad-dev-story` | `bmad-dev-story` | 实现故事 | | 3 | DEV | `bmad-code-review` | `bmad-code-review` | 质量验证 *(推荐)* | -完成史诗中的所有故事后,调用 **SM 智能体**(`bmad-agent-sm`)并运行 `bmad-retrospective`(`bmad-retrospective`)。 +完成史诗中的所有故事后,调用 **Developer 智能体**(`bmad-agent-dev`)并运行 `bmad-retrospective`(`bmad-retrospective`)。 ## 你已完成的工作 @@ -229,8 +229,8 @@ your-project/ | `bmad-generate-project-context` | `bmad-generate-project-context` | Analyst | 创建项目上下文文件 | | `bmad-create-epics-and-stories` | `bmad-create-epics-and-stories` | PM | 将 PRD 分解为史诗 | | `bmad-check-implementation-readiness` | `bmad-check-implementation-readiness` | Architect | 验证规划一致性 | -| `bmad-sprint-planning` | `bmad-sprint-planning` | SM | 初始化冲刺跟踪 | -| `bmad-create-story` | `bmad-create-story` | SM | 创建故事文件 | +| `bmad-sprint-planning` | `bmad-sprint-planning` | DEV | 初始化冲刺跟踪 | +| `bmad-create-story` | `bmad-create-story` | DEV | 创建故事文件 | | `bmad-dev-story` | `bmad-dev-story` | DEV | 实现故事 | | `bmad-code-review` | `bmad-code-review` | DEV | 审查已实现的代码 | @@ -240,7 +240,7 @@ your-project/ 仅对于 BMad Method 和 Enterprise 路径。Quick Flow 从技术规范跳转到实现。 **我可以稍后更改我的计划吗?** -可以。SM 智能体提供 `bmad-correct-course` 工作流(`bmad-correct-course`)来处理范围变化。 +可以。`bmad-correct-course` 工作流用于处理实现过程中的范围变化。 **如果我想先进行头脑风暴怎么办?** 在开始 PRD 之前,调用 Analyst 智能体(`bmad-agent-analyst`)并运行 `bmad-brainstorming`(`bmad-brainstorming`)。 diff --git a/package-lock.json b/package-lock.json index f141eb45b..bfd60ee1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bmad-method", - "version": "6.2.2", + "version": "6.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bmad-method", - "version": "6.2.2", + "version": "6.3.0", "license": "MIT", "dependencies": { "@clack/core": "^1.0.0", diff --git a/package.json b/package.json index 13825fe87..875d788f5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "bmad-method", - "version": "6.2.2", + "version": "6.3.0", "description": "Breakthrough Method of Agile AI-driven Development", "keywords": [ "agile", @@ -18,14 +18,14 @@ }, "license": "MIT", "author": "Brian (BMad) Madison", - "main": "tools/cli/bmad-cli.js", + "main": "tools/installer/bmad-cli.js", "bin": { - "bmad": "tools/bmad-npx-wrapper.js", - "bmad-method": "tools/bmad-npx-wrapper.js" + "bmad": "tools/installer/bmad-cli.js", + "bmad-method": "tools/installer/bmad-cli.js" }, "scripts": { - "bmad:install": "node tools/cli/bmad-cli.js install", - "bmad:uninstall": "node tools/cli/bmad-cli.js uninstall", + "bmad:install": "node tools/installer/bmad-cli.js install", + "bmad:uninstall": "node tools/installer/bmad-cli.js uninstall", "docs:build": "node tools/build-docs.mjs", "docs:dev": "astro dev --root website", "docs:fix-links": "node tools/fix-doc-links.js", @@ -34,13 +34,13 @@ "format:check": "prettier --check \"**/*.{js,cjs,mjs,json,yaml}\"", "format:fix": "prettier --write \"**/*.{js,cjs,mjs,json,yaml}\"", "format:fix:staged": "prettier --write", - "install:bmad": "node tools/cli/bmad-cli.js install", + "install:bmad": "node tools/installer/bmad-cli.js install", "lint": "eslint . --ext .js,.cjs,.mjs,.yaml --max-warnings=0", "lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix", "lint:md": "markdownlint-cli2 \"**/*.md\"", "prepare": "command -v husky >/dev/null 2>&1 && husky || exit 0", "quality": "npm run format:check && npm run lint && npm run lint:md && npm run docs:build && npm run test:install && npm run validate:refs && npm run validate:skills", - "rebundle": "node tools/cli/bundlers/bundle-web.js rebundle", + "rebundle": "node tools/installer/bundlers/bundle-web.js rebundle", "test": "npm run test:refs && npm run test:install && npm run lint && npm run lint:md && npm run format:check", "test:install": "node test/test-installation-components.js", "test:refs": "node test/test-file-refs-csv.js", @@ -97,6 +97,7 @@ "prettier": "^3.7.4", "prettier-plugin-packagejson": "^2.5.19", "sharp": "^0.33.5", + "unist-util-visit": "^5.1.0", "yaml-eslint-parser": "^1.2.3", "yaml-lint": "^1.7.0" }, diff --git a/removals.txt b/removals.txt new file mode 100644 index 000000000..81a2b5dce --- /dev/null +++ b/removals.txt @@ -0,0 +1,17 @@ +# BMad Method - Skill Removal List +# Entries listed here will be removed from IDE skill directories during install/update. +# One entry per line. Lines starting with # are comments. +# Each entry is a skill directory name (canonicalId) that was removed or renamed. + +# Removed agents (v6.2.0 - v6.2.2) +bmad-agent-sm +bmad-agent-qa +bmad-agent-quick-flow-solo-dev + +# Removed skills (v6.2.0 - v6.2.2) +bmad-create-product-brief +bmad-product-brief-preview +bmad-quick-spec +bmad-quick-flow +bmad-quick-dev-new-preview +bmad-init diff --git a/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md b/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md index 1118aea64..d85063694 100644 --- a/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md +++ b/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md @@ -36,14 +36,17 @@ When you are in this persona and the user calls a skill, this persona must carry | DR | Industry domain deep dive, subject matter expertise and terminology | bmad-domain-research | | TR | Technical feasibility, architecture options and implementation approaches | bmad-technical-research | | CB | Create or update product briefs through guided or autonomous discovery | bmad-product-brief-preview | +| WB | Working Backwards PRFAQ challenge — forge and stress-test product concepts | bmad-prfaq | | DP | Analyze an existing project to produce documentation for human and LLM consumption | bmad-document-project | ## On Activation -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning 2. **Continue with steps below:** - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. diff --git a/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md b/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md index 032ea56f2..bb645095a 100644 --- a/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md +++ b/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md @@ -39,10 +39,12 @@ When you are in this persona and the user calls a skill, this persona must carry ## On Activation -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning 2. **Continue with steps below:** - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. diff --git a/src/bmm-skills/1-analysis/bmad-document-project/workflow.md b/src/bmm-skills/1-analysis/bmad-document-project/workflow.md index 344873050..a21e54ba7 100644 --- a/src/bmm-skills/1-analysis/bmad-document-project/workflow.md +++ b/src/bmm-skills/1-analysis/bmad-document-project/workflow.md @@ -9,16 +9,14 @@ ## INITIALIZATION -### Configuration Loading +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning -Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: - -- `project_knowledge` -- `user_name` -- `communication_language` -- `document_output_language` -- `user_skill_level` -- `date` as system-generated current datetime +2. **Greet user** as `{user_name}`, speaking in `{communication_language}`. --- diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/SKILL.md b/src/bmm-skills/1-analysis/bmad-prfaq/SKILL.md new file mode 100644 index 000000000..36e9b3ba4 --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/SKILL.md @@ -0,0 +1,96 @@ +--- +name: bmad-prfaq +description: Working Backwards PRFAQ challenge to forge product concepts. Use when the user requests to 'create a PRFAQ', 'work backwards', or 'run the PRFAQ challenge'. +--- + +# Working Backwards: The PRFAQ Challenge + +## Overview + +This skill forges product concepts through Amazon's Working Backwards methodology — the PRFAQ (Press Release / Frequently Asked Questions). Act as a relentless but constructive product coach who stress-tests every claim, challenges vague thinking, and refuses to let weak ideas pass unchallenged. The user walks in with an idea. They walk out with a battle-hardened concept — or the honest realization they need to go deeper. Both are wins. + +The PRFAQ forces customer-first clarity: write the press release announcing the finished product before building it. If you can't write a compelling press release, the product isn't ready. The customer FAQ validates the value proposition from the outside in. The internal FAQ addresses feasibility, risks, and hard trade-offs. + +**This is hardcore mode.** The coaching is direct, the questions are hard, and vague answers get challenged. But when users are stuck, offer concrete suggestions, reframings, and alternatives — tough love, not tough silence. The goal is to strengthen the concept, not to gatekeep it. + +**Args:** Accepts `--headless` / `-H` for autonomous first-draft generation from provided context. + +**Output:** A complete PRFAQ document + PRD distillate for downstream pipeline consumption. + +**Research-grounded.** All competitive, market, and feasibility claims in the output must be verified against current real-world data. Proactively research to fill knowledge gaps — the user deserves a PRFAQ informed by today's landscape, not yesterday's assumptions. + +## On Activation + +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning + +2. **Greet user** as `{user_name}`, speaking in `{communication_language}`. Be warm but efficient — dream builder energy. + +3. **Resume detection:** Check if `{planning_artifacts}/prfaq-{project_name}.md` already exists. If it does, read only the first 20 lines to extract the frontmatter `stage` field and offer to resume from the next stage. Do not read the full document. If the user confirms, route directly to that stage's reference file. + +4. **Mode detection:** +- `--headless` / `-H`: Produce complete first-draft PRFAQ from provided inputs without interaction. Validate the input schema only (customer, problem, stakes, solution concept present and non-vague) — do not read any referenced files or documents yourself. If required fields are missing or too vague, return an error with specific guidance on what's needed. Fan out artifact analyzer and web researcher subagents in parallel (see Contextual Gathering below) to process all referenced materials, then create the output document at `{planning_artifacts}/prfaq-{project_name}.md` using `./assets/prfaq-template.md` and route to `./references/press-release.md`. +- Default: Full interactive coaching — the gauntlet. + +**Headless input schema:** +- **Required:** customer (specific persona), problem (concrete), stakes (why it matters), solution (concept) +- **Optional:** competitive context, technical constraints, team/org context, target market, existing research + +**Set the tone immediately.** This isn't a warm, exploratory greeting. Frame it as a challenge — the user is about to stress-test their thinking by writing the press release for a finished product before building anything. Convey that surviving this process means the concept is ready, and failing here saves wasted effort. Be direct and energizing. + +Then briefly ground the user on what a PRFAQ actually is — Amazon's Working Backwards method where you write the finished-product press release first, then answer the hardest customer and stakeholder questions. The point is forcing clarity before committing resources. + +Then proceed to Stage 1 below. + +## Stage 1: Ignition + +**Goal:** Get the raw concept on the table and immediately establish customer-first thinking. This stage ends when you have enough clarity on the customer, their problem, and the proposed solution to draft a press release headline. + +**Customer-first enforcement:** + +- If the user leads with a solution ("I want to build X"): redirect to the customer's problem. Don't let them skip the pain. +- If the user leads with a technology ("I want to use AI/blockchain/etc"): challenge harder. Technology is a "how", not a "why" — push them to articulate the human problem. Strip away the buzzword and ask whether anyone still cares. +- If the user leads with a customer problem: dig deeper into specifics — how they cope today, what they've tried, why it hasn't been solved. + +When the user gets stuck, offer concrete suggestions based on what they've shared so far. Draft a hypothesis for them to react to rather than repeating the question harder. + +**Concept type detection:** Early in the conversation, identify whether this is a commercial product, internal tool, open-source project, or community/nonprofit initiative. Store this as `{concept_type}` — it calibrates FAQ question generation in Stages 3 and 4. Non-commercial concepts don't have "unit economics" or "first 100 customers" — adapt the framing to stakeholder value, adoption paths, and sustainability instead. + +**Essentials to capture before progressing:** +- Who is the customer/user? (specific persona, not "everyone") +- What is their problem? (concrete and felt, not abstract) +- Why does this matter to them? (stakes and consequences) +- What's the initial concept for a solution? (even rough) + +**Fast-track:** If the user provides all four essentials in their opening message (or via structured input), acknowledge and confirm understanding, then move directly to document creation and Stage 2 without extended discovery. + +**Graceful redirect:** If after 2-3 exchanges the user can't articulate a customer or problem, don't force it — suggest the idea may need more exploration first and recommend they invoke the `bmad-brainstorming` skill to develop it further. + +**Contextual Gathering:** Once you understand the concept, gather external context before drafting begins. + +1. **Ask about inputs:** Ask the user whether they have existing documents, research, brainstorming, or other materials to inform the PRFAQ. Collect paths for subagent scanning — do not read user-provided files yourself; that's the Artifact Analyzer's job. +2. **Fan out subagents in parallel:** + - **Artifact Analyzer** (`./agents/artifact-analyzer.md`) — Scans `{planning_artifacts}` and `{project_knowledge}` for relevant documents, plus any user-provided paths. Receives the product intent summary so it knows what's relevant. + - **Web Researcher** (`./agents/web-researcher.md`) — Searches for competitive landscape, market context, and current industry data relevant to the concept. Receives the product intent summary. +3. **Graceful degradation:** If subagents are unavailable, scan the most relevant 1-2 documents inline and do targeted web searches directly. Never block the workflow. +4. **Merge findings** with what the user shared. Surface anything surprising that enriches or challenges their assumptions before proceeding. + +**Create the output document** at `{planning_artifacts}/prfaq-{project_name}.md` using `./assets/prfaq-template.md`. Write the frontmatter (populate `inputs` with any source documents used) and any initial content captured during Ignition. This document is the working artifact — update it progressively through all stages. + +**Coaching Notes Capture:** Before moving on, append a `` block to the output document: concept type and rationale, initial assumptions challenged, why this direction over alternatives discussed, key subagent findings that shaped the concept framing, and any user context captured that doesn't fit the PRFAQ itself. + +**When you have enough to draft a press release headline**, route to `./references/press-release.md`. + +## Stages + +| # | Stage | Purpose | Location | +|---|-------|---------|----------| +| 1 | Ignition | Raw concept, enforce customer-first thinking | SKILL.md (above) | +| 2 | The Press Release | Iterative drafting with hard coaching | `./references/press-release.md` | +| 3 | Customer FAQ | Devil's advocate customer questions | `./references/customer-faq.md` | +| 4 | Internal FAQ | Skeptical stakeholder questions | `./references/internal-faq.md` | +| 5 | The Verdict | Synthesis, strength assessment, final output | `./references/verdict.md` | diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/agents/artifact-analyzer.md b/src/bmm-skills/1-analysis/bmad-prfaq/agents/artifact-analyzer.md new file mode 100644 index 000000000..69c7ff863 --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/agents/artifact-analyzer.md @@ -0,0 +1,60 @@ +# Artifact Analyzer + +You are a research analyst. Your job is to scan project documents and extract information relevant to a product concept being stress-tested through the PRFAQ process. + +## Input + +You will receive: +- **Product intent:** A summary of the concept — customer, problem, solution direction +- **Scan paths:** Directories to search for relevant documents (e.g., planning artifacts, project knowledge folders) +- **User-provided paths:** Any specific files the user pointed to + +## Process + +1. **Scan the provided directories** for documents that could be relevant: + - Brainstorming reports (`*brainstorm*`, `*ideation*`) + - Research documents (`*research*`, `*analysis*`, `*findings*`) + - Project context (`*context*`, `*overview*`, `*background*`) + - Existing briefs or summaries (`*brief*`, `*summary*`) + - Any markdown, text, or structured documents that look relevant + +2. **For sharded documents** (a folder with `index.md` and multiple files), read the index first to understand what's there, then read only the relevant parts. + +3. **For very large documents** (estimated >50 pages), read the table of contents, executive summary, and section headings first. Read only sections directly relevant to the stated product intent. Note which sections were skimmed vs read fully. + +4. **Read all relevant documents in parallel** — issue all Read calls in a single message rather than one at a time. Extract: + - Key insights that relate to the product intent + - Market or competitive information + - User research or persona information + - Technical context or constraints + - Ideas, both accepted and rejected (rejected ideas are valuable — they prevent re-proposing) + - Any metrics, data points, or evidence + +5. **Ignore documents that aren't relevant** to the stated product intent. Don't waste tokens on unrelated content. + +## Output + +Return ONLY the following JSON object. No preamble, no commentary. Keep total response under 1,500 tokens. Maximum 5 bullets per section — prioritize the most impactful findings. + +```json +{ + "documents_found": [ + {"path": "file path", "relevance": "one-line summary"} + ], + "key_insights": [ + "bullet — grouped by theme, each self-contained" + ], + "user_market_context": [ + "bullet — users, market, competition found in docs" + ], + "technical_context": [ + "bullet — platforms, constraints, integrations" + ], + "ideas_and_decisions": [ + {"idea": "description", "status": "accepted|rejected|open", "rationale": "brief why"} + ], + "raw_detail_worth_preserving": [ + "bullet — specific details, data points, quotes for the distillate" + ] +} +``` diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/agents/web-researcher.md b/src/bmm-skills/1-analysis/bmad-prfaq/agents/web-researcher.md new file mode 100644 index 000000000..b09d738b3 --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/agents/web-researcher.md @@ -0,0 +1,49 @@ +# Web Researcher + +You are a market research analyst. Your job is to find current, relevant competitive, market, and industry context for a product concept being stress-tested through the PRFAQ process. + +## Input + +You will receive: +- **Product intent:** A summary of the concept — customer, problem, solution direction, and the domain it operates in + +## Process + +1. **Identify search angles** based on the product intent: + - Direct competitors (products solving the same problem) + - Adjacent solutions (different approaches to the same pain point) + - Market size and trends for the domain + - Industry news or developments that create opportunity or risk + - User sentiment about existing solutions (what's frustrating people) + +2. **Execute 3-5 targeted web searches** — quality over quantity. Search for: + - "[problem domain] solutions comparison" + - "[competitor names] alternatives" (if competitors are known) + - "[industry] market trends [current year]" + - "[target user type] pain points [domain]" + +3. **Synthesize findings** — don't just list links. Extract the signal. + +## Output + +Return ONLY the following JSON object. No preamble, no commentary. Keep total response under 1,000 tokens. Maximum 5 bullets per section. + +```json +{ + "competitive_landscape": [ + {"name": "competitor", "approach": "one-line description", "gaps": "where they fall short"} + ], + "market_context": [ + "bullet — market size, growth trends, relevant data points" + ], + "user_sentiment": [ + "bullet — what users say about existing solutions" + ], + "timing_and_opportunity": [ + "bullet — why now, enabling shifts" + ], + "risks_and_considerations": [ + "bullet — market risks, competitive threats, regulatory concerns" + ] +} +``` diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/assets/prfaq-template.md b/src/bmm-skills/1-analysis/bmad-prfaq/assets/prfaq-template.md new file mode 100644 index 000000000..0d7f5f2f0 --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/assets/prfaq-template.md @@ -0,0 +1,62 @@ +--- +title: "PRFAQ: {project_name}" +status: "{status}" +created: "{timestamp}" +updated: "{timestamp}" +stage: "{current_stage}" +inputs: [] +--- + +# {Headline} + +## {Subheadline — one sentence: who benefits and what changes for them} + +**{City, Date}** — {Opening paragraph: announce the product/initiative, state the user's problem, and the key benefit.} + +{Problem paragraph: the user's pain today. Specific, concrete, felt. No mention of the solution yet.} + +{Solution paragraph: what changes for the user. Benefits, not features. Outcomes, not implementation.} + +> "{Leader/founder quote — the vision beyond the feature list.}" +> — {Name, Title/Role} + +### How It Works + +{The user experience, step by step. Written from THEIR perspective. How they discover it, start using it, and get value from it.} + +> "{User quote — what a real person would say after using this. Must sound human, not like marketing copy.}" +> — {Name, Role} + +### Getting Started + +{Clear, concrete path to first value. How to access, try, adopt, or contribute.} + +--- + +## Customer FAQ + +### Q: {Hardest customer question first} + +A: {Honest, specific answer} + +### Q: {Next question} + +A: {Answer} + +--- + +## Internal FAQ + +### Q: {Hardest internal question first} + +A: {Honest, specific answer} + +### Q: {Next question} + +A: {Answer} + +--- + +## The Verdict + +{Concept strength assessment — what's forged in steel, what needs more heat, what has cracks in the foundation.} diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/bmad-manifest.json b/src/bmm-skills/1-analysis/bmad-prfaq/bmad-manifest.json new file mode 100644 index 000000000..9c3ad043c --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/bmad-manifest.json @@ -0,0 +1,16 @@ +{ + "module-code": "bmm", + "capabilities": [ + { + "name": "working-backwards", + "menu-code": "WB", + "description": "Produces battle-tested PRFAQ document and optional LLM distillate for PRD input.", + "supports-headless": true, + "phase-name": "1-analysis", + "after": ["brainstorming", "perform-research"], + "before": ["create-prd"], + "is-required": false, + "output-location": "{planning_artifacts}" + } + ] +} diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/references/customer-faq.md b/src/bmm-skills/1-analysis/bmad-prfaq/references/customer-faq.md new file mode 100644 index 000000000..c677bb25d --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/references/customer-faq.md @@ -0,0 +1,55 @@ +**Language:** Use `{communication_language}` for all output. +**Output Language:** Use `{document_output_language}` for documents. +**Output Location:** `{planning_artifacts}` +**Coaching stance:** Be direct, challenge vague thinking, but offer concrete alternatives when the user is stuck — tough love, not tough silence. +**Concept type:** Check `{concept_type}` — calibrate all question framing to match (commercial, internal tool, open-source, community/nonprofit). + +# Stage 3: Customer FAQ + +**Goal:** Validate the value proposition by asking the hardest questions a real user would ask — and crafting answers that hold up under scrutiny. + +## The Devil's Advocate + +You are now the customer. Not a friendly early-adopter — a busy, skeptical person who has been burned by promises before. You've read the press release. Now you have questions. + +**Generate 6-10 customer FAQ questions** that cover these angles: + +- **Skepticism:** "How is this different from [existing solution]?" / "Why should I switch from what I use today?" +- **Trust:** "What happens to my data?" / "What if this shuts down?" / "Who's behind this?" +- **Practical concerns:** "How much does it cost?" / "How long does it take to get started?" / "Does it work with [thing I already use]?" +- **Edge cases:** "What if I need to [uncommon but real scenario]?" / "Does it work for [adjacent use case]?" +- **The hard question they're afraid of:** Every product has one question the team hopes nobody asks. Find it and ask it. + +**Don't generate softball questions.** "How do I sign up?" is not a FAQ — it's a CTA. Real customer FAQs are the objections standing between interest and adoption. + +**Calibrate to concept type.** For non-commercial concepts (internal tools, open-source, community projects), adapt question framing: replace "cost" with "effort to adopt," replace "competitor switching" with "why change from current workflow," replace "trust/company viability" with "maintenance and sustainability." + +## Coaching the Answers + +Present the questions and work through answers with the user: + +1. **Present all questions at once** — let the user see the full landscape of customer concern. +2. **Work through answers together.** The user drafts (or you draft and they react). For each answer: + - Is it honest? If the answer is "we don't do that yet," say so — and explain the roadmap or alternative. + - Is it specific? "We have enterprise-grade security" is not an answer. What certifications? What encryption? What SLA? + - Would a customer believe it? Marketing language in FAQ answers destroys credibility. +3. **If an answer reveals a real gap in the concept**, name it directly and force a decision: is this a launch blocker, a fast-follow, or an accepted trade-off? +4. **The user can add their own questions too.** Often they know the scary questions better than anyone. + +## Headless Mode + +Generate questions and best-effort answers from available context. Flag answers with low confidence so a human can review. + +## Updating the Document + +Append the Customer FAQ section to the output document. Update frontmatter: `status: "customer-faq"`, `stage: 3`, `updated` timestamp. + +## Coaching Notes Capture + +Before moving on, append a `` block to the output document: gaps revealed by customer questions, trade-off decisions made (launch blocker vs fast-follow vs accepted), competitive intelligence surfaced, and any scope or requirements signals. + +## Stage Complete + +This stage is complete when every question has an honest, specific answer — and the user has confronted the hardest customer objections their concept faces. No softballs survived. + +Route to `./internal-faq.md`. diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/references/internal-faq.md b/src/bmm-skills/1-analysis/bmad-prfaq/references/internal-faq.md new file mode 100644 index 000000000..42942826d --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/references/internal-faq.md @@ -0,0 +1,51 @@ +**Language:** Use `{communication_language}` for all output. +**Output Language:** Use `{document_output_language}` for documents. +**Output Location:** `{planning_artifacts}` +**Coaching stance:** Be direct, challenge vague thinking, but offer concrete alternatives when the user is stuck — tough love, not tough silence. +**Concept type:** Check `{concept_type}` — calibrate all question framing to match (commercial, internal tool, open-source, community/nonprofit). + +# Stage 4: Internal FAQ + +**Goal:** Stress-test the concept from the builder's side. The customer FAQ asked "should I use this?" The internal FAQ asks "can we actually pull this off — and should we?" + +## The Skeptical Stakeholder + +You are now the internal stakeholder panel — engineering lead, finance, legal, operations, the CEO who's seen a hundred pitches. The press release was inspiring. Now prove it's real. + +**Generate 6-10 internal FAQ questions** that cover these angles: + +- **Feasibility:** "What's the hardest technical problem here?" / "What do we not know how to build yet?" / "What are the key dependencies and risks?" +- **Business viability:** "What does the unit economics look like?" / "How do we acquire the first 100 customers?" / "What's the competitive moat — and how durable is it?" +- **Resource reality:** "What does the team need to look like?" / "What's the realistic timeline to a usable product?" / "What do we have to say no to in order to do this?" +- **Risk:** "What kills this?" / "What's the worst-case scenario if we ship and it doesn't work?" / "What regulatory or legal exposure exists?" +- **Strategic fit:** "Why us? Why now?" / "What does this cannibalize?" / "If this succeeds, what does the company look like in 3 years?" +- **The question the founder avoids:** The internal counterpart to the hard customer question. The thing that keeps them up at night but hasn't been said out loud. + +**Calibrate questions to context.** A solo founder building an MVP needs different internal questions than a team inside a large organization. Don't ask about "board alignment" for a weekend project. Don't ask about "weekend viability" for an enterprise product. For non-commercial concepts (internal tools, open-source, community projects), replace "unit economics" with "maintenance burden," replace "customer acquisition" with "adoption strategy," and replace "competitive moat" with "sustainability and contributor/stakeholder engagement." + +## Coaching the Answers + +Same approach as Customer FAQ — draft, challenge, refine: + +1. **Present all questions at once.** +2. **Work through answers.** Demand specificity. "We'll figure it out" is not an answer. Neither is "we'll hire for that." What's the actual plan? +3. **Honest unknowns are fine — unexamined unknowns are not.** If the answer is "we don't know yet," the follow-up is: "What would it take to find out, and when do you need to know by?" +4. **Watch for hand-waving on resources and timeline.** These are the most commonly over-optimistic answers. Push for concrete scoping. + +## Headless Mode + +Generate questions calibrated to context and best-effort answers. Flag high-risk areas and unknowns prominently. + +## Updating the Document + +Append the Internal FAQ section to the output document. Update frontmatter: `status: "internal-faq"`, `stage: 4`, `updated` timestamp. + +## Coaching Notes Capture + +Before moving on, append a `` block to the output document: feasibility risks identified, resource/timeline estimates discussed, unknowns flagged with "what would it take to find out" answers, strategic positioning decisions, and any technical constraints or dependencies surfaced. + +## Stage Complete + +This stage is complete when the internal questions have honest, specific answers — and the user has a clear-eyed view of what it actually takes to execute this concept. Optimism is fine. Delusion is not. + +Route to `./verdict.md`. diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/references/press-release.md b/src/bmm-skills/1-analysis/bmad-prfaq/references/press-release.md new file mode 100644 index 000000000..0bd21ff17 --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/references/press-release.md @@ -0,0 +1,60 @@ +**Language:** Use `{communication_language}` for all output. +**Output Language:** Use `{document_output_language}` for documents. +**Output Location:** `{planning_artifacts}` +**Coaching stance:** Be direct, challenge vague thinking, but offer concrete alternatives when the user is stuck — tough love, not tough silence. + +# Stage 2: The Press Release + +**Goal:** Produce a press release that would make a real customer stop scrolling and pay attention. Draft iteratively, challenging every sentence for specificity, customer relevance, and honesty. + +**Concept type adaptation:** Check `{concept_type}` (commercial product, internal tool, open-source, community/nonprofit). For non-commercial concepts, adapt press release framing: "announce the initiative" not "announce the product," "How to Participate" not "Getting Started," "Community Member quote" not "Customer quote." The structure stays — the language shifts to match the audience. + +## The Forge + +The press release is the heart of Working Backwards. It has a specific structure, and each part earns its place by forcing a different type of clarity: + +| Section | What It Forces | +|---------|---------------| +| **Headline** | Can you say what this is in one sentence a customer would understand? | +| **Subheadline** | Who benefits and what changes for them? | +| **Opening paragraph** | What are you announcing, who is it for, and why should they care? | +| **Problem paragraph** | Can you make the reader feel the customer's pain without mentioning your solution? | +| **Solution paragraph** | What changes for the customer? (Not: what did you build.) | +| **Leader quote** | What's the vision beyond the feature list? | +| **How It Works** | Can you explain the experience from the customer's perspective? | +| **Customer quote** | Would a real person say this? Does it sound human? | +| **Getting Started** | Is the path to value clear and concrete? | + +## Coaching Approach + +The coaching dynamic: draft each section yourself first, then model critical thinking by challenging your own draft out loud before inviting the user to sharpen it. Push one level deeper on every response — if the user gives you a generality, demand the specific. The cycle is: draft → self-challenge → invite → deepen. + +When the user is stuck, offer 2-3 concrete alternatives to react to rather than repeating the question harder. + +## Quality Bars + +These are the standards to hold the press release to. Don't enumerate them to the user — embody them in your challenges: + +- **No jargon** — If a customer wouldn't use the word, neither should the press release +- **No weasel words** — "significantly", "revolutionary", "best-in-class" are banned. Replace with specifics. +- **The mom test** — Could you explain this to someone outside your industry and have them understand why it matters? +- **The "so what?" test** — Every sentence should survive "so what?" If it can't, cut or sharpen it. +- **Honest framing** — The press release should be compelling without being dishonest. If you're overselling, the customer FAQ will expose it. + +## Headless Mode + +If running headless: draft the complete press release based on available inputs without interaction. Apply the quality bars internally — challenge yourself and produce the strongest version you can. Write directly to the output document. + +## Updating the Document + +After each section is refined, append it to the output document at `{planning_artifacts}/prfaq-{project_name}.md`. Update frontmatter: `status: "press-release"`, `stage: 2`, and `updated` timestamp. + +## Coaching Notes Capture + +Before moving on, append a brief `` block to the output document capturing key contextual observations from this stage: rejected headline framings, competitive positioning discussed, differentiators explored but not used, and any out-of-scope details the user mentioned (technical constraints, timeline, team context). These notes survive context compaction and feed the Stage 5 distillate. + +## Stage Complete + +This stage is complete when the full press release reads as a coherent, compelling announcement that a real customer would find relevant. The user should feel proud of what they've written — and confident every sentence earned its place. + +Route to `./customer-faq.md`. diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/references/verdict.md b/src/bmm-skills/1-analysis/bmad-prfaq/references/verdict.md new file mode 100644 index 000000000..f77a95020 --- /dev/null +++ b/src/bmm-skills/1-analysis/bmad-prfaq/references/verdict.md @@ -0,0 +1,79 @@ +**Language:** Use `{communication_language}` for all output. +**Output Language:** Use `{document_output_language}` for documents. +**Output Location:** `{planning_artifacts}` +**Coaching stance:** Be direct and honest — the verdict exists to surface truth, not to soften it. But frame every finding constructively. + +# Stage 5: The Verdict + +**Goal:** Step back from the details and give the user an honest assessment of where their concept stands. Finalize the PRFAQ document and produce the downstream distillate. + +## The Assessment + +Review the entire PRFAQ — press release, customer FAQ, internal FAQ — and deliver a candid verdict: + +**Concept Strength:** Rate the overall concept readiness. Not a score — a narrative assessment. Where is the thinking sharp and where is it still soft? What survived the gauntlet and what barely held together? + +**Three categories of findings:** + +- **Forged in steel** — aspects of the concept that are clear, compelling, and defensible. The press release sections that would actually make a customer stop. The FAQ answers that are honest and convincing. +- **Needs more heat** — areas that are promising but underdeveloped. The user has a direction but hasn't gone deep enough. These need more work before they're ready for a PRD. +- **Cracks in the foundation** — genuine risks, unresolved contradictions, or gaps that could undermine the whole concept. Not necessarily deal-breakers, but things that must be addressed deliberately. + +**Present the verdict directly.** Don't soften it. The whole point of this process is to surface truth before committing resources. But frame findings constructively — for every crack, suggest what it would take to address it. + +## Finalize the Document + +1. **Polish the PRFAQ** — ensure the press release reads as a cohesive narrative, FAQs flow logically, formatting is consistent +2. **Append The Verdict section** to the output document with the assessment +3. Update frontmatter: `status: "complete"`, `stage: 5`, `updated` timestamp + +## Produce the Distillate + +Throughout the process, you captured context beyond what fits in the PRFAQ. Source material for the distillate includes the `` blocks in the output document (which survive context compaction) as well as anything remaining in session memory — rejected framings, alternative positioning, technical constraints, competitive intelligence, scope signals, resource estimates, open questions. + +**Always produce the distillate** at `{planning_artifacts}/prfaq-{project_name}-distillate.md`: + +```yaml +--- +title: "PRFAQ Distillate: {project_name}" +type: llm-distillate +source: "prfaq-{project_name}.md" +created: "{timestamp}" +purpose: "Token-efficient context for downstream PRD creation" +--- +``` + +**Distillate content:** Dense bullet points grouped by theme. Each bullet stands alone with enough context for a downstream LLM to use it. Include: +- Rejected framings and why they were dropped +- Requirements signals captured during coaching +- Technical context, constraints, and platform preferences +- Competitive intelligence from discussion +- Open questions and unknowns flagged during internal FAQ +- Scope signals — what's in, out, and maybe for MVP +- Resource and timeline estimates discussed +- The Verdict findings (especially "needs more heat" and "cracks") as actionable items + +## Present Completion + +"Your PRFAQ for {project_name} has survived the gauntlet. + +**PRFAQ:** `{planning_artifacts}/prfaq-{project_name}.md` +**Detail Pack:** `{planning_artifacts}/prfaq-{project_name}-distillate.md` + +**Recommended next step:** Use the PRFAQ and detail pack as input for PRD creation. The PRFAQ replaces the product brief in your planning pipeline — tell your PM 'create a PRD' and point them to these files." + +**Headless mode output:** +```json +{ + "status": "complete", + "prfaq": "{planning_artifacts}/prfaq-{project_name}.md", + "distillate": "{planning_artifacts}/prfaq-{project_name}-distillate.md", + "verdict": "forged|needs-heat|cracked", + "key_risks": ["top unresolved items"], + "open_questions": ["unresolved items from FAQs"] +} +``` + +## Stage Complete + +This is the terminal stage. If the user wants to revise, loop back to the relevant stage. Otherwise, the workflow is done. diff --git a/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md b/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md index da612e54f..06ba558c9 100644 --- a/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md +++ b/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md @@ -37,7 +37,7 @@ Check activation context immediately: - Use `{planning_artifacts}` for output location and artifact scanning - Use `{project_knowledge}` for additional context scanning -2. **Greet user** as `{user_name}`, speaking in `{communication_language}`. Be warm but efficient — dream builder energy. +2. **Greet user** as `{user_name}`, speaking in `{communication_language}`. 3. **Stage 1: Understand Intent** (handled here in SKILL.md) @@ -80,8 +80,3 @@ Check activation context immediately: | 3 | Guided Elicitation | Fill gaps through smart questioning | `prompts/guided-elicitation.md` | | 4 | Draft & Review | Draft brief, fan out review subagents | `prompts/draft-and-review.md` | | 5 | Finalize | Polish, output, offer distillate | `prompts/finalize.md` | - -## External Skills - -This workflow uses: -- `bmad-init` — Configuration loading (module: bmm) diff --git a/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json b/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json index 42ea35c0a..28e2f2b17 100644 --- a/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json +++ b/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json @@ -8,7 +8,7 @@ "description": "Produces executive product brief and optional LLM distillate for PRD input.", "supports-headless": true, "phase-name": "1-analysis", - "after": ["brainstorming, perform-research"], + "after": ["brainstorming", "perform-research"], "before": ["create-prd"], "is-required": true, "output-location": "{planning_artifacts}" diff --git a/src/bmm-skills/1-analysis/research/bmad-domain-research/workflow.md b/src/bmm-skills/1-analysis/research/bmad-domain-research/workflow.md index 09976cb9a..fca2613f2 100644 --- a/src/bmm-skills/1-analysis/research/bmad-domain-research/workflow.md +++ b/src/bmm-skills/1-analysis/research/bmad-domain-research/workflow.md @@ -8,12 +8,14 @@ **⛔ Web search required.** If unavailable, abort and tell the user. -## CONFIGURATION +## Activation -Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as a system-generated value +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning ## QUICK TOPIC DISCOVERY diff --git a/src/bmm-skills/1-analysis/research/bmad-market-research/workflow.md b/src/bmm-skills/1-analysis/research/bmad-market-research/workflow.md index 23822ca3b..77cb0cf08 100644 --- a/src/bmm-skills/1-analysis/research/bmad-market-research/workflow.md +++ b/src/bmm-skills/1-analysis/research/bmad-market-research/workflow.md @@ -8,12 +8,14 @@ **⛔ Web search required.** If unavailable, abort and tell the user. -## CONFIGURATION +## Activation -Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as a system-generated value +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning ## QUICK TOPIC DISCOVERY diff --git a/src/bmm-skills/1-analysis/research/bmad-technical-research/workflow.md b/src/bmm-skills/1-analysis/research/bmad-technical-research/workflow.md index bf7020f56..f85b1479d 100644 --- a/src/bmm-skills/1-analysis/research/bmad-technical-research/workflow.md +++ b/src/bmm-skills/1-analysis/research/bmad-technical-research/workflow.md @@ -9,12 +9,14 @@ **⛔ Web search required.** If unavailable, abort and tell the user. -## CONFIGURATION +## Activation -Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as a system-generated value +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning ## QUICK TOPIC DISCOVERY diff --git a/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md b/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md index eb57ce029..89f94e24c 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md +++ b/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md @@ -41,10 +41,12 @@ When you are in this persona and the user calls a skill, this persona must carry ## On Activation -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning 2. **Continue with steps below:** - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. diff --git a/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md b/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md index 2ef4b8c08..c6d7296a5 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md +++ b/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md @@ -37,10 +37,12 @@ When you are in this persona and the user calls a skill, this persona must carry ## On Activation -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning 2. **Continue with steps below:** - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. diff --git a/src/bmm-skills/2-plan-workflows/bmad-create-prd/workflow.md b/src/bmm-skills/2-plan-workflows/bmad-create-prd/workflow.md index 39f78e9d5..70fbe7a85 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-create-prd/workflow.md +++ b/src/bmm-skills/2-plan-workflows/bmad-create-prd/workflow.md @@ -42,20 +42,19 @@ This uses **step-file architecture** for disciplined execution: - ⏸️ **ALWAYS** halt at menus and wait for user input - 📋 **NEVER** create mental todo lists from future steps -## INITIALIZATION SEQUENCE +## Activation -### 1. Configuration Loading - -Load and read full config from {main_config} and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as system-generated current datetime +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the configured `{communication_language}`. ✅ YOU MUST ALWAYS WRITE all artifact and document content in `{document_output_language}`. -### 2. Route to Create Workflow +2. Route to Create Workflow "**Create Mode: Creating a new PRD from scratch.**" diff --git a/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/steps/step-13-responsive-accessibility.md b/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/steps/step-13-responsive-accessibility.md index 02368a08d..612faa2ea 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/steps/step-13-responsive-accessibility.md +++ b/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/steps/step-13-responsive-accessibility.md @@ -240,7 +240,7 @@ When user selects 'C', append the content directly to the document using the str ✅ Appropriate breakpoint strategy established ✅ Accessibility requirements determined and documented ✅ Comprehensive testing strategy planned -✅ Implementation guidelines provided for development team +✅ Implementation guidelines provided for Developer agent ✅ A/P/C menu presented and handled correctly ✅ Content properly appended to document when C selected diff --git a/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/workflow.md b/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/workflow.md index 04be36641..8ca55f1e9 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/workflow.md +++ b/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/workflow.md @@ -15,15 +15,14 @@ This uses **micro-file architecture** for disciplined execution: --- -## INITIALIZATION +## Activation -### Configuration Loading - -Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as system-generated current datetime +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning ### Paths diff --git a/src/bmm-skills/2-plan-workflows/create-prd/data/prd-purpose.md b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/data/prd-purpose.md similarity index 100% rename from src/bmm-skills/2-plan-workflows/create-prd/data/prd-purpose.md rename to src/bmm-skills/2-plan-workflows/bmad-edit-prd/data/prd-purpose.md diff --git a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01-discovery.md b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01-discovery.md index 85b29ad01..39e344946 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01-discovery.md +++ b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01-discovery.md @@ -1,6 +1,6 @@ --- # File references (ONLY variables used in this step) -prdPurpose: '{project-root}/_bmad/bmm-skills/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '../data/prd-purpose.md' --- # Step E-1: Discovery & Understanding diff --git a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01b-legacy-conversion.md b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01b-legacy-conversion.md index a4f463f50..54f82525b 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01b-legacy-conversion.md +++ b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-01b-legacy-conversion.md @@ -1,7 +1,7 @@ --- # File references (ONLY variables used in this step) prdFile: '{prd_file_path}' -prdPurpose: '{project-root}/_bmad/bmm-skills/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '../data/prd-purpose.md' --- # Step E-1B: Legacy PRD Conversion Assessment diff --git a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-02-review.md b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-02-review.md index 8440edd4d..c01a0adb9 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-02-review.md +++ b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-02-review.md @@ -2,7 +2,7 @@ # File references (ONLY variables used in this step) prdFile: '{prd_file_path}' validationReport: '{validation_report_path}' # If provided -prdPurpose: '{project-root}/_bmad/bmm-skills/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '../data/prd-purpose.md' --- # Step E-2: Deep Review & Analysis diff --git a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-03-edit.md b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-03-edit.md index e0391fba7..5b5e66902 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-03-edit.md +++ b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-03-edit.md @@ -1,7 +1,7 @@ --- # File references (ONLY variables used in this step) prdFile: '{prd_file_path}' -prdPurpose: '{project-root}/_bmad/bmm-skills/2-plan-workflows/create-prd/data/prd-purpose.md' +prdPurpose: '../data/prd-purpose.md' --- # Step E-3: Edit & Update diff --git a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-04-complete.md b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-04-complete.md index 25af09ade..1406e631c 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-04-complete.md +++ b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-04-complete.md @@ -1,7 +1,6 @@ --- # File references (ONLY variables used in this step) prdFile: '{prd_file_path}' -validationWorkflow: '{project-root}/_bmad/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md' --- # Step E-4: Complete & Validate @@ -117,8 +116,7 @@ Display: - Display: "This will run all 13 validation checks on the updated PRD." - Display: "Preparing to validate: {prd_file_path}" - Display: "**Proceeding to validation...**" - - Read fully and follow: {validationWorkflow} (steps-v/step-v-01-discovery.md) - - Note: This hands off to the validation workflow which will run its complete 13-step process + - Invoke the `bmad-validate-prd` skill to run the complete validation workflow - **IF E (Edit More):** - Display: "**Additional Edits**" diff --git a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/workflow.md b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/workflow.md index 2439a6c96..23bd97c6f 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-edit-prd/workflow.md +++ b/src/bmm-skills/2-plan-workflows/bmad-edit-prd/workflow.md @@ -41,20 +41,19 @@ This uses **step-file architecture** for disciplined execution: - ⏸️ **ALWAYS** halt at menus and wait for user input - 📋 **NEVER** create mental todo lists from future steps -## INITIALIZATION SEQUENCE +## Activation -### 1. Configuration Loading - -Load and read full config from {main_config} and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as system-generated current datetime +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the configured `{communication_language}`. ✅ YOU MUST ALWAYS WRITE all artifact and document content in `{document_output_language}`. -### 2. Route to Edit Workflow +2. Route to Edit Workflow "**Edit Mode: Improving an existing PRD.**" diff --git a/src/bmm-skills/2-plan-workflows/bmad-validate-prd/workflow.md b/src/bmm-skills/2-plan-workflows/bmad-validate-prd/workflow.md index 3de6ff24f..4fe8fcea9 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-validate-prd/workflow.md +++ b/src/bmm-skills/2-plan-workflows/bmad-validate-prd/workflow.md @@ -42,20 +42,19 @@ This uses **step-file architecture** for disciplined execution: - ⏸️ **ALWAYS** halt at menus and wait for user input - 📋 **NEVER** create mental todo lists from future steps -## INITIALIZATION SEQUENCE +## Activation -### 1. Configuration Loading - -Load and read full config from {main_config} and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as system-generated current datetime +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the configured `{communication_language}`. ✅ YOU MUST ALWAYS WRITE all artifact and document content in `{document_output_language}`. -### 2. Route to Validate Workflow +2. Route to Validate Workflow "**Validate Mode: Validating an existing PRD against BMAD standards.**" diff --git a/src/bmm-skills/2-plan-workflows/create-prd/data/domain-complexity.csv b/src/bmm-skills/2-plan-workflows/create-prd/data/domain-complexity.csv deleted file mode 100644 index 60a7b503f..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/data/domain-complexity.csv +++ /dev/null @@ -1,15 +0,0 @@ -domain,signals,complexity,key_concerns,required_knowledge,suggested_workflow,web_searches,special_sections -healthcare,"medical,diagnostic,clinical,FDA,patient,treatment,HIPAA,therapy,pharma,drug",high,"FDA approval;Clinical validation;HIPAA compliance;Patient safety;Medical device classification;Liability","Regulatory pathways;Clinical trial design;Medical standards;Data privacy;Integration requirements","domain-research","FDA software medical device guidance {date};HIPAA compliance software requirements;Medical software standards {date};Clinical validation software","clinical_requirements;regulatory_pathway;validation_methodology;safety_measures" -fintech,"payment,banking,trading,investment,crypto,wallet,transaction,KYC,AML,funds,fintech",high,"Regional compliance;Security standards;Audit requirements;Fraud prevention;Data protection","KYC/AML requirements;PCI DSS;Open banking;Regional laws (US/EU/APAC);Crypto regulations","domain-research","fintech regulations {date};payment processing compliance {date};open banking API standards;cryptocurrency regulations {date}","compliance_matrix;security_architecture;audit_requirements;fraud_prevention" -govtech,"government,federal,civic,public sector,citizen,municipal,voting",high,"Procurement rules;Security clearance;Accessibility (508);FedRAMP;Privacy;Transparency","Government procurement;Security frameworks;Accessibility standards;Privacy laws;Open data requirements","domain-research","government software procurement {date};FedRAMP compliance requirements;section 508 accessibility;government security standards","procurement_compliance;security_clearance;accessibility_standards;transparency_requirements" -edtech,"education,learning,student,teacher,curriculum,assessment,K-12,university,LMS",medium,"Student privacy (COPPA/FERPA);Accessibility;Content moderation;Age verification;Curriculum standards","Educational privacy laws;Learning standards;Accessibility requirements;Content guidelines;Assessment validity","domain-research","educational software privacy {date};COPPA FERPA compliance;WCAG education requirements;learning management standards","privacy_compliance;content_guidelines;accessibility_features;curriculum_alignment" -aerospace,"aircraft,spacecraft,aviation,drone,satellite,propulsion,flight,radar,navigation",high,"Safety certification;DO-178C compliance;Performance validation;Simulation accuracy;Export controls","Aviation standards;Safety analysis;Simulation validation;ITAR/export controls;Performance requirements","domain-research + technical-model","DO-178C software certification;aerospace simulation standards {date};ITAR export controls software;aviation safety requirements","safety_certification;simulation_validation;performance_requirements;export_compliance" -automotive,"vehicle,car,autonomous,ADAS,automotive,driving,EV,charging",high,"Safety standards;ISO 26262;V2X communication;Real-time requirements;Certification","Automotive standards;Functional safety;V2X protocols;Real-time systems;Testing requirements","domain-research","ISO 26262 automotive software;automotive safety standards {date};V2X communication protocols;EV charging standards","safety_standards;functional_safety;communication_protocols;certification_requirements" -scientific,"research,algorithm,simulation,modeling,computational,analysis,data science,ML,AI",medium,"Reproducibility;Validation methodology;Peer review;Performance;Accuracy;Computational resources","Scientific method;Statistical validity;Computational requirements;Domain expertise;Publication standards","technical-model","scientific computing best practices {date};research reproducibility standards;computational modeling validation;peer review software","validation_methodology;accuracy_metrics;reproducibility_plan;computational_requirements" -legaltech,"legal,law,contract,compliance,litigation,patent,attorney,court",high,"Legal ethics;Bar regulations;Data retention;Attorney-client privilege;Court system integration","Legal practice rules;Ethics requirements;Court filing systems;Document standards;Confidentiality","domain-research","legal technology ethics {date};law practice management software requirements;court filing system standards;attorney client privilege technology","ethics_compliance;data_retention;confidentiality_measures;court_integration" -insuretech,"insurance,claims,underwriting,actuarial,policy,risk,premium",high,"Insurance regulations;Actuarial standards;Data privacy;Fraud detection;State compliance","Insurance regulations by state;Actuarial methods;Risk modeling;Claims processing;Regulatory reporting","domain-research","insurance software regulations {date};actuarial standards software;insurance fraud detection;state insurance compliance","regulatory_requirements;risk_modeling;fraud_detection;reporting_compliance" -energy,"energy,utility,grid,solar,wind,power,electricity,oil,gas",high,"Grid compliance;NERC standards;Environmental regulations;Safety requirements;Real-time operations","Energy regulations;Grid standards;Environmental compliance;Safety protocols;SCADA systems","domain-research","energy sector software compliance {date};NERC CIP standards;smart grid requirements;renewable energy software standards","grid_compliance;safety_protocols;environmental_compliance;operational_requirements" -process_control,"industrial automation,process control,PLC,SCADA,DCS,HMI,operational technology,OT,control system,cyberphysical,MES,historian,instrumentation,I&C,P&ID",high,"Functional safety;OT cybersecurity;Real-time control requirements;Legacy system integration;Process safety and hazard analysis;Environmental compliance and permitting;Engineering authority and PE requirements","Functional safety standards;OT security frameworks;Industrial protocols;Process control architecture;Plant reliability and maintainability","domain-research + technical-model","IEC 62443 OT cybersecurity requirements {date};functional safety software requirements {date};industrial process control architecture;ISA-95 manufacturing integration","functional_safety;ot_security;process_requirements;engineering_authority" -building_automation,"building automation,BAS,BMS,HVAC,smart building,lighting control,fire alarm,fire protection,fire suppression,life safety,elevator,access control,DDC,energy management,sequence of operations,commissioning",high,"Life safety codes;Building energy standards;Multi-trade coordination and interoperability;Commissioning and ongoing operational performance;Indoor environmental quality and occupant comfort;Engineering authority and PE requirements","Building automation protocols;HVAC and mechanical controls;Fire alarm, fire protection, and life safety design;Commissioning process and sequence of operations;Building codes and energy standards","domain-research","smart building software architecture {date};BACnet integration best practices;building automation cybersecurity {date};ASHRAE building standards","life_safety;energy_compliance;commissioning_requirements;engineering_authority" -gaming,"game,player,gameplay,level,character,multiplayer,quest",redirect,"REDIRECT TO GAME WORKFLOWS","Game design","game-brief","NA","NA" -general,"",low,"Standard requirements;Basic security;User experience;Performance","General software practices","continue","software development best practices {date}","standard_requirements" \ No newline at end of file diff --git a/src/bmm-skills/2-plan-workflows/create-prd/data/project-types.csv b/src/bmm-skills/2-plan-workflows/create-prd/data/project-types.csv deleted file mode 100644 index 6f71c513a..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/data/project-types.csv +++ /dev/null @@ -1,11 +0,0 @@ -project_type,detection_signals,key_questions,required_sections,skip_sections,web_search_triggers,innovation_signals -api_backend,"API,REST,GraphQL,backend,service,endpoints","Endpoints needed?;Authentication method?;Data formats?;Rate limits?;Versioning?;SDK needed?","endpoint_specs;auth_model;data_schemas;error_codes;rate_limits;api_docs","ux_ui;visual_design;user_journeys","framework best practices;OpenAPI standards","API composition;New protocol" -mobile_app,"iOS,Android,app,mobile,iPhone,iPad","Native or cross-platform?;Offline needed?;Push notifications?;Device features?;Store compliance?","platform_reqs;device_permissions;offline_mode;push_strategy;store_compliance","desktop_features;cli_commands","app store guidelines;platform requirements","Gesture innovation;AR/VR features" -saas_b2b,"SaaS,B2B,platform,dashboard,teams,enterprise","Multi-tenant?;Permission model?;Subscription tiers?;Integrations?;Compliance?","tenant_model;rbac_matrix;subscription_tiers;integration_list;compliance_reqs","cli_interface;mobile_first","compliance requirements;integration guides","Workflow automation;AI agents" -developer_tool,"SDK,library,package,npm,pip,framework","Language support?;Package managers?;IDE integration?;Documentation?;Examples?","language_matrix;installation_methods;api_surface;code_examples;migration_guide","visual_design;store_compliance","package manager best practices;API design patterns","New paradigm;DSL creation" -cli_tool,"CLI,command,terminal,bash,script","Interactive or scriptable?;Output formats?;Config method?;Shell completion?","command_structure;output_formats;config_schema;scripting_support","visual_design;ux_principles;touch_interactions","CLI design patterns;shell integration","Natural language CLI;AI commands" -web_app,"website,webapp,browser,SPA,PWA","SPA or MPA?;Browser support?;SEO needed?;Real-time?;Accessibility?","browser_matrix;responsive_design;performance_targets;seo_strategy;accessibility_level","native_features;cli_commands","web standards;WCAG guidelines","New interaction;WebAssembly use" -game,"game,player,gameplay,level,character","REDIRECT TO USE THE BMad Method Game Module Agent and Workflows - HALT","game-brief;GDD","most_sections","game design patterns","Novel mechanics;Genre mixing" -desktop_app,"desktop,Windows,Mac,Linux,native","Cross-platform?;Auto-update?;System integration?;Offline?","platform_support;system_integration;update_strategy;offline_capabilities","web_seo;mobile_features","desktop guidelines;platform requirements","Desktop AI;System automation" -iot_embedded,"IoT,embedded,device,sensor,hardware","Hardware specs?;Connectivity?;Power constraints?;Security?;OTA updates?","hardware_reqs;connectivity_protocol;power_profile;security_model;update_mechanism","visual_ui;browser_support","IoT standards;protocol specs","Edge AI;New sensors" -blockchain_web3,"blockchain,crypto,DeFi,NFT,smart contract","Chain selection?;Wallet integration?;Gas optimization?;Security audit?","chain_specs;wallet_support;smart_contracts;security_audit;gas_optimization","traditional_auth;centralized_db","blockchain standards;security patterns","Novel tokenomics;DAO structure" \ No newline at end of file diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md deleted file mode 100644 index 561ae8901..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -name: 'step-v-01-discovery' -description: 'Document Discovery & Confirmation - Handle fresh context validation, confirm PRD path, discover input documents' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-02-format-detection.md' -prdPurpose: '../data/prd-purpose.md' ---- - -# Step 1: Document Discovery & Confirmation - -## STEP GOAL: - -Handle fresh context validation by confirming PRD path, discovering and loading input documents from frontmatter, and initializing the validation report. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in collaborative dialogue, not command-response -- ✅ You bring systematic validation expertise and analytical rigor -- ✅ User brings domain knowledge and specific PRD context - -### Step-Specific Rules: - -- 🎯 Focus ONLY on discovering PRD and input documents, not validating yet -- 🚫 FORBIDDEN to perform any validation checks in this step -- 💬 Approach: Systematic discovery with clear reporting to user -- 🚪 This is the setup step - get everything ready for validation - -## EXECUTION PROTOCOLS: - -- 🎯 Discover and confirm PRD to validate -- 💾 Load PRD and all input documents from frontmatter -- 📖 Initialize validation report next to PRD -- 🚫 FORBIDDEN to load next step until user confirms setup - -## CONTEXT BOUNDARIES: - -- Available context: PRD path (user-specified or discovered), workflow configuration -- Focus: Document discovery and setup only -- Limits: Don't perform validation, don't skip discovery -- Dependencies: Configuration loaded from PRD workflow.md initialization - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Load PRD Purpose and Standards - -Load and read the complete file at: -`{prdPurpose}` - -This file contains the BMAD PRD philosophy, standards, and validation criteria that will guide all validation checks. Internalize this understanding - it defines what makes a great BMAD PRD. - -### 2. Discover PRD to Validate - -**If PRD path provided as invocation parameter:** -- Use provided path - -**If no PRD path provided, auto-discover:** -- Search `{planning_artifacts}` for files matching `*prd*.md` -- Also check for sharded PRDs: `{planning_artifacts}/*prd*/*.md` - -**If exactly ONE PRD found:** -- Use it automatically -- Inform user: "Found PRD: {discovered_path} — using it for validation." - -**If MULTIPLE PRDs found:** -- List all discovered PRDs with numbered options -- "I found multiple PRDs. Which one would you like to validate?" -- Wait for user selection - -**If NO PRDs found:** -- "I couldn't find any PRD files in {planning_artifacts}. Please provide the path to the PRD file you want to validate." -- Wait for user to provide PRD path. - -### 3. Validate PRD Exists and Load - -Once PRD path is provided: - -- Check if PRD file exists at specified path -- If not found: "I cannot find a PRD at that path. Please check the path and try again." -- If found: Load the complete PRD file including frontmatter - -### 4. Extract Frontmatter and Input Documents - -From the loaded PRD frontmatter, extract: - -- `inputDocuments: []` array (if present) -- Any other relevant metadata (classification, date, etc.) - -**If no inputDocuments array exists:** -Note this and proceed with PRD-only validation - -### 5. Load Input Documents - -For each document listed in `inputDocuments`: - -- Attempt to load the document -- Track successfully loaded documents -- Note any documents that fail to load - -**Build list of loaded input documents:** -- Product Brief (if present) -- Research documents (if present) -- Other reference materials (if present) - -### 6. Ask About Additional Reference Documents - -"**I've loaded the following documents from your PRD frontmatter:** - -{list loaded documents with file names} - -**Are there any additional reference documents you'd like me to include in this validation?** - -These could include: -- Additional research or context documents -- Project documentation not tracked in frontmatter -- Standards or compliance documents -- Competitive analysis or benchmarks - -Please provide paths to any additional documents, or type 'none' to proceed." - -**Load any additional documents provided by user.** - -### 7. Initialize Validation Report - -Create validation report at: `{validationReportPath}` - -**Initialize with frontmatter:** -```yaml ---- -validationTarget: '{prd_path}' -validationDate: '{current_date}' -inputDocuments: [list of all loaded documents] -validationStepsCompleted: [] -validationStatus: IN_PROGRESS ---- -``` - -**Initial content:** -```markdown -# PRD Validation Report - -**PRD Being Validated:** {prd_path} -**Validation Date:** {current_date} - -## Input Documents - -{list all documents loaded for validation} - -## Validation Findings - -[Findings will be appended as validation progresses] -``` - -### 8. Present Discovery Summary - -"**Setup Complete!** - -**PRD to Validate:** {prd_path} - -**Input Documents Loaded:** -- PRD: {prd_name} ✓ -- Product Brief: {count} {if count > 0}✓{else}(none found){/if} -- Research: {count} {if count > 0}✓{else}(none found){/if} -- Additional References: {count} {if count > 0}✓{else}(none){/if} - -**Validation Report:** {validationReportPath} - -**Ready to begin validation.**" - -### 9. Present MENU OPTIONS - -Display: **Select an Option:** [A] Advanced Elicitation [P] Party Mode [C] Continue to Format Detection - -#### EXECUTION RULES: - -- ALWAYS halt and wait for user input after presenting menu -- ONLY proceed to next step when user selects 'C' -- User can ask questions or add more documents - always respond and redisplay menu - -#### Menu Handling Logic: - -- IF A: Invoke the `bmad-advanced-elicitation` skill, and when finished redisplay the menu -- IF P: Invoke the `bmad-party-mode` skill, and when finished redisplay the menu -- IF C: Read fully and follow: {nextStepFile} to begin format detection -- IF user provides additional document: Load it, update report, redisplay summary -- IF Any other: help user, then redisplay menu - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- PRD path discovered and confirmed -- PRD file exists and loads successfully -- All input documents from frontmatter loaded -- Additional reference documents (if any) loaded -- Validation report initialized next to PRD -- User clearly informed of setup status -- Menu presented and user input handled correctly - -### ❌ SYSTEM FAILURE: - -- Proceeding with non-existent PRD file -- Not loading input documents from frontmatter -- Creating validation report in wrong location -- Proceeding without user confirming setup -- Not handling missing input documents gracefully - -**Master Rule:** Complete discovery and setup BEFORE validation. This step ensures everything is in place for systematic validation checks. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md deleted file mode 100644 index a354b5aff..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -name: 'step-v-02-format-detection' -description: 'Format Detection & Structure Analysis - Classify PRD format and route appropriately' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-03-density-validation.md' -altStepFile: './step-v-02b-parity-check.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 2: Format Detection & Structure Analysis - -## STEP GOAL: - -Detect if PRD follows BMAD format and route appropriately - classify as BMAD Standard / BMAD Variant / Non-Standard, with optional parity check for non-standard formats. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in collaborative dialogue, not command-response -- ✅ You bring systematic validation expertise and pattern recognition -- ✅ User brings domain knowledge and PRD context - -### Step-Specific Rules: - -- 🎯 Focus ONLY on detecting format and classifying structure -- 🚫 FORBIDDEN to perform other validation checks in this step -- 💬 Approach: Analytical and systematic, clear reporting of findings -- 🚪 This is a branch step - may route to parity check for non-standard PRDs - -## EXECUTION PROTOCOLS: - -- 🎯 Analyze PRD structure systematically -- 💾 Append format findings to validation report -- 📖 Route appropriately based on format classification -- 🚫 FORBIDDEN to skip format detection or proceed without classification - -## CONTEXT BOUNDARIES: - -- Available context: PRD file loaded in step 1, validation report initialized -- Focus: Format detection and classification only -- Limits: Don't perform other validation, don't skip classification -- Dependencies: Step 1 completed - PRD loaded and report initialized - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Extract PRD Structure - -Load the complete PRD file and extract: - -**All Level 2 (##) headers:** -- Scan through entire PRD document -- Extract all ## section headers -- List them in order - -**PRD frontmatter:** -- Extract classification.domain if present -- Extract classification.projectType if present -- Note any other relevant metadata - -### 2. Check for BMAD PRD Core Sections - -Check if the PRD contains the following BMAD PRD core sections: - -1. **Executive Summary** (or variations: ## Executive Summary, ## Overview, ## Introduction) -2. **Success Criteria** (or: ## Success Criteria, ## Goals, ## Objectives) -3. **Product Scope** (or: ## Product Scope, ## Scope, ## In Scope, ## Out of Scope) -4. **User Journeys** (or: ## User Journeys, ## User Stories, ## User Flows) -5. **Functional Requirements** (or: ## Functional Requirements, ## Features, ## Capabilities) -6. **Non-Functional Requirements** (or: ## Non-Functional Requirements, ## NFRs, ## Quality Attributes) - -**Count matches:** -- How many of these 6 core sections are present? -- Which specific sections are present? -- Which are missing? - -### 3. Classify PRD Format - -Based on core section count, classify: - -**BMAD Standard:** -- 5-6 core sections present -- Follows BMAD PRD structure closely - -**BMAD Variant:** -- 3-4 core sections present -- Generally follows BMAD patterns but may have structural differences -- Missing some sections but recognizable as BMAD-style - -**Non-Standard:** -- Fewer than 3 core sections present -- Does not follow BMAD PRD structure -- May be completely custom format, legacy format, or from another framework - -### 4. Report Format Findings to Validation Report - -Append to validation report: - -```markdown -## Format Detection - -**PRD Structure:** -[List all ## Level 2 headers found] - -**BMAD Core Sections Present:** -- Executive Summary: [Present/Missing] -- Success Criteria: [Present/Missing] -- Product Scope: [Present/Missing] -- User Journeys: [Present/Missing] -- Functional Requirements: [Present/Missing] -- Non-Functional Requirements: [Present/Missing] - -**Format Classification:** [BMAD Standard / BMAD Variant / Non-Standard] -**Core Sections Present:** [count]/6 -``` - -### 5. Route Based on Format Classification - -**IF format is BMAD Standard or BMAD Variant:** - -Display: "**Format Detected:** {classification} - -Proceeding to systematic validation checks..." - -Without delay, read fully and follow: {nextStepFile} (step-v-03-density-validation.md) - -**IF format is Non-Standard (< 3 core sections):** - -Display: "**Format Detected:** Non-Standard PRD - -This PRD does not follow BMAD standard structure (only {count}/6 core sections present). - -You have options:" - -Present MENU OPTIONS below for user selection - -### 6. Present MENU OPTIONS (Non-Standard PRDs Only) - -**[A] Parity Check** - Analyze gaps and estimate effort to reach BMAD PRD parity -**[B] Validate As-Is** - Proceed with validation using current structure -**[C] Exit** - Exit validation and review format findings - -#### EXECUTION RULES: - -- ALWAYS halt and wait for user input -- Only proceed based on user selection - -#### Menu Handling Logic: - -- IF A (Parity Check): Read fully and follow: {altStepFile} (step-v-02b-parity-check.md) -- IF B (Validate As-Is): Display "Proceeding with validation..." then read fully and follow: {nextStepFile} -- IF C (Exit): Display format findings summary and exit validation -- IF Any other: help user respond, then redisplay menu - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- All ## Level 2 headers extracted successfully -- BMAD core sections checked systematically -- Format classified correctly based on section count -- Findings reported to validation report -- BMAD Standard/Variant PRDs proceed directly to next validation step -- Non-Standard PRDs pause and present options to user -- User can choose parity check, validate as-is, or exit - -### ❌ SYSTEM FAILURE: - -- Not extracting all headers before classification -- Incorrect format classification -- Not reporting findings to validation report -- Not pausing for non-standard PRDs -- Proceeding without user decision for non-standard formats - -**Master Rule:** Format detection determines validation path. Non-standard PRDs require user choice before proceeding. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md deleted file mode 100644 index 604265a9a..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -name: 'step-v-02b-parity-check' -description: 'Document Parity Check - Analyze non-standard PRD and identify gaps to achieve BMAD PRD parity' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-03-density-validation.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 2B: Document Parity Check - -## STEP GOAL: - -Analyze non-standard PRD and identify gaps to achieve BMAD PRD parity, presenting user with options for how to proceed. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in collaborative dialogue, not command-response -- ✅ You bring BMAD PRD standards expertise and gap analysis -- ✅ User brings domain knowledge and PRD context - -### Step-Specific Rules: - -- 🎯 Focus ONLY on analyzing gaps and estimating parity effort -- 🚫 FORBIDDEN to perform other validation checks in this step -- 💬 Approach: Systematic gap analysis with clear recommendations -- 🚪 This is an optional branch step - user chooses next action - -## EXECUTION PROTOCOLS: - -- 🎯 Analyze each BMAD PRD section for gaps -- 💾 Append parity analysis to validation report -- 📖 Present options and await user decision -- 🚫 FORBIDDEN to proceed without user selection - -## CONTEXT BOUNDARIES: - -- Available context: Non-standard PRD from step 2, validation report in progress -- Focus: Parity analysis only - what's missing, what's needed -- Limits: Don't perform validation checks, don't auto-proceed -- Dependencies: Step 2 classified PRD as non-standard and user chose parity check - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Analyze Each BMAD PRD Section - -For each of the 6 BMAD PRD core sections, analyze: - -**Executive Summary:** -- Does PRD have vision/overview? -- Is problem statement clear? -- Are target users identified? -- Gap: [What's missing or incomplete] - -**Success Criteria:** -- Are measurable goals defined? -- Is success clearly defined? -- Gap: [What's missing or incomplete] - -**Product Scope:** -- Is scope clearly defined? -- Are in-scope items listed? -- Are out-of-scope items listed? -- Gap: [What's missing or incomplete] - -**User Journeys:** -- Are user types/personas identified? -- Are user flows documented? -- Gap: [What's missing or incomplete] - -**Functional Requirements:** -- Are features/capabilities listed? -- Are requirements structured? -- Gap: [What's missing or incomplete] - -**Non-Functional Requirements:** -- Are quality attributes defined? -- Are performance/security/etc. requirements documented? -- Gap: [What's missing or incomplete] - -### 2. Estimate Effort to Reach Parity - -For each missing or incomplete section, estimate: - -**Effort Level:** -- Minimal - Section exists but needs minor enhancements -- Moderate - Section missing but content exists elsewhere in PRD -- Significant - Section missing, requires new content creation - -**Total Parity Effort:** -- Based on individual section estimates -- Classify overall: Quick / Moderate / Substantial effort - -### 3. Report Parity Analysis to Validation Report - -Append to validation report: - -```markdown -## Parity Analysis (Non-Standard PRD) - -### Section-by-Section Gap Analysis - -**Executive Summary:** -- Status: [Present/Missing/Incomplete] -- Gap: [specific gap description] -- Effort to Complete: [Minimal/Moderate/Significant] - -**Success Criteria:** -- Status: [Present/Missing/Incomplete] -- Gap: [specific gap description] -- Effort to Complete: [Minimal/Moderate/Significant] - -**Product Scope:** -- Status: [Present/Missing/Incomplete] -- Gap: [specific gap description] -- Effort to Complete: [Minimal/Moderate/Significant] - -**User Journeys:** -- Status: [Present/Missing/Incomplete] -- Gap: [specific gap description] -- Effort to Complete: [Minimal/Moderate/Significant] - -**Functional Requirements:** -- Status: [Present/Missing/Incomplete] -- Gap: [specific gap description] -- Effort to Complete: [Minimal/Moderate/Significant] - -**Non-Functional Requirements:** -- Status: [Present/Missing/Incomplete] -- Gap: [specific gap description] -- Effort to Complete: [Minimal/Moderate/Significant] - -### Overall Parity Assessment - -**Overall Effort to Reach BMAD Standard:** [Quick/Moderate/Substantial] -**Recommendation:** [Brief recommendation based on analysis] -``` - -### 4. Present Parity Analysis and Options - -Display: - -"**Parity Analysis Complete** - -Your PRD is missing {count} of 6 core BMAD PRD sections. The overall effort to reach BMAD standard is: **{effort level}** - -**Quick Summary:** -[2-3 sentence summary of key gaps] - -**Recommendation:** -{recommendation from analysis} - -**How would you like to proceed?**" - -### 5. Present MENU OPTIONS - -**[C] Continue Validation** - Proceed with validation using current structure -**[E] Exit & Review** - Exit validation and review parity report -**[S] Save & Exit** - Save parity report and exit - -#### EXECUTION RULES: - -- ALWAYS halt and wait for user input -- Only proceed based on user selection - -#### Menu Handling Logic: - -- IF C (Continue): Display "Proceeding with validation..." then read fully and follow: {nextStepFile} -- IF E (Exit): Display parity summary and exit validation -- IF S (Save): Confirm saved, display summary, exit -- IF Any other: help user respond, then redisplay menu - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- All 6 BMAD PRD sections analyzed for gaps -- Effort estimates provided for each gap -- Overall parity effort assessed correctly -- Parity analysis reported to validation report -- Clear summary presented to user -- User can choose to continue validation, exit, or save report - -### ❌ SYSTEM FAILURE: - -- Not analyzing all 6 sections systematically -- Missing effort estimates -- Not reporting parity analysis to validation report -- Auto-proceeding without user decision -- Unclear recommendations - -**Master Rule:** Parity check informs user of gaps and effort, but user decides whether to proceed with validation or address gaps first. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md deleted file mode 100644 index d00478c10..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -name: 'step-v-03-density-validation' -description: 'Information Density Check - Scan for anti-patterns that violate information density principles' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-04-brief-coverage-validation.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 3: Information Density Validation - -## STEP GOAL: - -Validate PRD meets BMAD information density standards by scanning for conversational filler, wordy phrases, and redundant expressions that violate conciseness principles. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring analytical rigor and attention to detail -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on information density anti-patterns -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Systematic scanning and categorization -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Scan PRD for density anti-patterns systematically -- 💾 Append density findings to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file, validation report with format findings -- Focus: Information density validation only -- Limits: Don't validate other aspects, don't pause for user input -- Dependencies: Step 2 completed - format classification done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Attempt Sub-Process Validation - -**Try to use Task tool to spawn a subprocess:** - -"Perform information density validation on this PRD: - -1. Load the PRD file -2. Scan for the following anti-patterns: - - Conversational filler phrases (examples: 'The system will allow users to...', 'It is important to note that...', 'In order to') - - Wordy phrases (examples: 'Due to the fact that', 'In the event of', 'For the purpose of') - - Redundant phrases (examples: 'Future plans', 'Absolutely essential', 'Past history') -3. Count violations by category with line numbers -4. Classify severity: Critical (>10 violations), Warning (5-10), Pass (<5) - -Return structured findings with counts and examples." - -### 2. Graceful Degradation (if Task tool unavailable) - -If Task tool unavailable, perform analysis directly: - -**Scan for conversational filler patterns:** -- "The system will allow users to..." -- "It is important to note that..." -- "In order to" -- "For the purpose of" -- "With regard to" -- Count occurrences and note line numbers - -**Scan for wordy phrases:** -- "Due to the fact that" (use "because") -- "In the event of" (use "if") -- "At this point in time" (use "now") -- "In a manner that" (use "how") -- Count occurrences and note line numbers - -**Scan for redundant phrases:** -- "Future plans" (just "plans") -- "Past history" (just "history") -- "Absolutely essential" (just "essential") -- "Completely finish" (just "finish") -- Count occurrences and note line numbers - -### 3. Classify Severity - -**Calculate total violations:** -- Conversational filler count -- Wordy phrases count -- Redundant phrases count -- Total = sum of all categories - -**Determine severity:** -- **Critical:** Total > 10 violations -- **Warning:** Total 5-10 violations -- **Pass:** Total < 5 violations - -### 4. Report Density Findings to Validation Report - -Append to validation report: - -```markdown -## Information Density Validation - -**Anti-Pattern Violations:** - -**Conversational Filler:** {count} occurrences -[If count > 0, list examples with line numbers] - -**Wordy Phrases:** {count} occurrences -[If count > 0, list examples with line numbers] - -**Redundant Phrases:** {count} occurrences -[If count > 0, list examples with line numbers] - -**Total Violations:** {total} - -**Severity Assessment:** [Critical/Warning/Pass] - -**Recommendation:** -[If Critical] "PRD requires significant revision to improve information density. Every sentence should carry weight without filler." -[If Warning] "PRD would benefit from reducing wordiness and eliminating filler phrases." -[If Pass] "PRD demonstrates good information density with minimal violations." -``` - -### 5. Display Progress and Auto-Proceed - -Display: "**Information Density Validation Complete** - -Severity: {Critical/Warning/Pass} - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-04-brief-coverage-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- PRD scanned for all three anti-pattern categories -- Violations counted with line numbers -- Severity classified correctly -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not scanning all anti-pattern categories -- Missing severity classification -- Not reporting findings to validation report -- Pausing for user input (should auto-proceed) -- Not attempting subprocess architecture - -**Master Rule:** Information density validation runs autonomously. Scan, classify, report, auto-proceed. No user interaction needed. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md deleted file mode 100644 index 60ad8684f..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +++ /dev/null @@ -1,214 +0,0 @@ ---- -name: 'step-v-04-brief-coverage-validation' -description: 'Product Brief Coverage Check - Validate PRD covers all content from Product Brief (if used as input)' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-05-measurability-validation.md' -prdFile: '{prd_file_path}' -productBrief: '{product_brief_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 4: Product Brief Coverage Validation - -## STEP GOAL: - -Validate that PRD covers all content from Product Brief (if brief was used as input), mapping brief content to PRD sections and identifying gaps. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring analytical rigor and traceability expertise -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on Product Brief coverage (conditional on brief existence) -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Systematic mapping and gap analysis -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Check if Product Brief exists in input documents -- 💬 If no brief: Skip this check and report "N/A - No Product Brief" -- 🎯 If brief exists: Map brief content to PRD sections -- 💾 Append coverage findings to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file, input documents from step 1, validation report -- Focus: Product Brief coverage only (conditional) -- Limits: Don't validate other aspects, conditional execution -- Dependencies: Step 1 completed - input documents loaded - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Check for Product Brief - -Check if Product Brief was loaded in step 1's inputDocuments: - -**IF no Product Brief found:** -Append to validation report: -```markdown -## Product Brief Coverage - -**Status:** N/A - No Product Brief was provided as input -``` - -Display: "**Product Brief Coverage: Skipped** (No Product Brief provided) - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} - -**IF Product Brief exists:** Continue to step 2 below - -### 2. Attempt Sub-Process Validation - -**Try to use Task tool to spawn a subprocess:** - -"Perform Product Brief coverage validation: - -1. Load the Product Brief -2. Extract key content: - - Vision statement - - Target users/personas - - Problem statement - - Key features - - Goals/objectives - - Differentiators - - Constraints -3. For each item, search PRD for corresponding coverage -4. Classify coverage: Fully Covered / Partially Covered / Not Found / Intentionally Excluded -5. Note any gaps with severity: Critical / Moderate / Informational - -Return structured coverage map with classifications." - -### 3. Graceful Degradation (if Task tool unavailable) - -If Task tool unavailable, perform analysis directly: - -**Extract from Product Brief:** -- Vision: What is this product? -- Users: Who is it for? -- Problem: What problem does it solve? -- Features: What are the key capabilities? -- Goals: What are the success criteria? -- Differentiators: What makes it unique? - -**For each item, search PRD:** -- Scan Executive Summary for vision -- Check User Journeys or user personas -- Look for problem statement -- Review Functional Requirements for features -- Check Success Criteria section -- Search for differentiators - -**Classify coverage:** -- **Fully Covered:** Content present and complete -- **Partially Covered:** Content present but incomplete -- **Not Found:** Content missing from PRD -- **Intentionally Excluded:** Content explicitly out of scope - -### 4. Assess Coverage and Severity - -**For each gap (Partially Covered or Not Found):** -- Is this Critical? (Core vision, primary users, main features) -- Is this Moderate? (Secondary features, some goals) -- Is this Informational? (Nice-to-have features, minor details) - -**Note:** Some exclusions may be intentional (valid scoping decisions) - -### 5. Report Coverage Findings to Validation Report - -Append to validation report: - -```markdown -## Product Brief Coverage - -**Product Brief:** {brief_file_name} - -### Coverage Map - -**Vision Statement:** [Fully/Partially/Not Found/Intentionally Excluded] -[If gap: Note severity and specific missing content] - -**Target Users:** [Fully/Partially/Not Found/Intentionally Excluded] -[If gap: Note severity and specific missing content] - -**Problem Statement:** [Fully/Partially/Not Found/Intentionally Excluded] -[If gap: Note severity and specific missing content] - -**Key Features:** [Fully/Partially/Not Found/Intentionally Excluded] -[If gap: List specific features with severity] - -**Goals/Objectives:** [Fully/Partially/Not Found/Intentionally Excluded] -[If gap: Note severity and specific missing content] - -**Differentiators:** [Fully/Partially/Not Found/Intentionally Excluded] -[If gap: Note severity and specific missing content] - -### Coverage Summary - -**Overall Coverage:** [percentage or qualitative assessment] -**Critical Gaps:** [count] [list if any] -**Moderate Gaps:** [count] [list if any] -**Informational Gaps:** [count] [list if any] - -**Recommendation:** -[If critical gaps exist] "PRD should be revised to cover critical Product Brief content." -[If moderate gaps] "Consider addressing moderate gaps for complete coverage." -[If minimal gaps] "PRD provides good coverage of Product Brief content." -``` - -### 6. Display Progress and Auto-Proceed - -Display: "**Product Brief Coverage Validation Complete** - -Overall Coverage: {assessment} - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-05-measurability-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- Checked for Product Brief existence correctly -- If no brief: Reported "N/A" and skipped gracefully -- If brief exists: Mapped all key brief content to PRD sections -- Coverage classified appropriately (Fully/Partially/Not Found/Intentionally Excluded) -- Severity assessed for gaps (Critical/Moderate/Informational) -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not checking for brief existence before attempting validation -- If brief exists: not mapping all key content areas -- Missing coverage classifications -- Not reporting findings to validation report -- Not auto-proceeding - -**Master Rule:** Product Brief coverage is conditional - skip if no brief, validate thoroughly if brief exists. Always auto-proceed. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md deleted file mode 100644 index a97187184..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -name: 'step-v-05-measurability-validation' -description: 'Measurability Validation - Validate that all requirements (FRs and NFRs) are measurable and testable' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-06-traceability-validation.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 5: Measurability Validation - -## STEP GOAL: - -Validate that all Functional Requirements (FRs) and Non-Functional Requirements (NFRs) are measurable, testable, and follow proper format without implementation details. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring analytical rigor and requirements engineering expertise -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on FR and NFR measurability -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Systematic requirement-by-requirement analysis -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Extract all FRs and NFRs from PRD -- 💾 Validate each for measurability and format -- 📖 Append findings to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file, validation report -- Focus: FR and NFR measurability only -- Limits: Don't validate other aspects, don't pause for user input -- Dependencies: Steps 2-4 completed - initial validation checks done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Attempt Sub-Process Validation - -**Try to use Task tool to spawn a subprocess:** - -"Perform measurability validation on this PRD: - -**Functional Requirements (FRs):** -1. Extract all FRs from Functional Requirements section -2. Check each FR for: - - '[Actor] can [capability]' format compliance - - No subjective adjectives (easy, fast, simple, intuitive, etc.) - - No vague quantifiers (multiple, several, some, many, etc.) - - No implementation details (technology names, library names, data structures unless capability-relevant) -3. Document violations with line numbers - -**Non-Functional Requirements (NFRs):** -1. Extract all NFRs from Non-Functional Requirements section -2. Check each NFR for: - - Specific metrics with measurement methods - - Template compliance (criterion, metric, measurement method, context) - - Context included (why this matters, who it affects) -3. Document violations with line numbers - -Return structured findings with violation counts and examples." - -### 2. Graceful Degradation (if Task tool unavailable) - -If Task tool unavailable, perform analysis directly: - -**Functional Requirements Analysis:** - -Extract all FRs and check each for: - -**Format compliance:** -- Does it follow "[Actor] can [capability]" pattern? -- Is actor clearly defined? -- Is capability actionable and testable? - -**No subjective adjectives:** -- Scan for: easy, fast, simple, intuitive, user-friendly, responsive, quick, efficient (without metrics) -- Note line numbers - -**No vague quantifiers:** -- Scan for: multiple, several, some, many, few, various, number of -- Note line numbers - -**No implementation details:** -- Scan for: React, Vue, Angular, PostgreSQL, MongoDB, AWS, Docker, Kubernetes, Redux, etc. -- Unless capability-relevant (e.g., "API consumers can access...") -- Note line numbers - -**Non-Functional Requirements Analysis:** - -Extract all NFRs and check each for: - -**Specific metrics:** -- Is there a measurable criterion? (e.g., "response time < 200ms", not "fast response") -- Can this be measured or tested? - -**Template compliance:** -- Criterion defined? -- Metric specified? -- Measurement method included? -- Context provided? - -### 3. Tally Violations - -**FR Violations:** -- Format violations: count -- Subjective adjectives: count -- Vague quantifiers: count -- Implementation leakage: count -- Total FR violations: sum - -**NFR Violations:** -- Missing metrics: count -- Incomplete template: count -- Missing context: count -- Total NFR violations: sum - -**Total violations:** FR violations + NFR violations - -### 4. Report Measurability Findings to Validation Report - -Append to validation report: - -```markdown -## Measurability Validation - -### Functional Requirements - -**Total FRs Analyzed:** {count} - -**Format Violations:** {count} -[If violations exist, list examples with line numbers] - -**Subjective Adjectives Found:** {count} -[If found, list examples with line numbers] - -**Vague Quantifiers Found:** {count} -[If found, list examples with line numbers] - -**Implementation Leakage:** {count} -[If found, list examples with line numbers] - -**FR Violations Total:** {total} - -### Non-Functional Requirements - -**Total NFRs Analyzed:** {count} - -**Missing Metrics:** {count} -[If missing, list examples with line numbers] - -**Incomplete Template:** {count} -[If incomplete, list examples with line numbers] - -**Missing Context:** {count} -[If missing, list examples with line numbers] - -**NFR Violations Total:** {total} - -### Overall Assessment - -**Total Requirements:** {FRs + NFRs} -**Total Violations:** {FR violations + NFR violations} - -**Severity:** [Critical if >10 violations, Warning if 5-10, Pass if <5] - -**Recommendation:** -[If Critical] "Many requirements are not measurable or testable. Requirements must be revised to be testable for downstream work." -[If Warning] "Some requirements need refinement for measurability. Focus on violating requirements above." -[If Pass] "Requirements demonstrate good measurability with minimal issues." -``` - -### 5. Display Progress and Auto-Proceed - -Display: "**Measurability Validation Complete** - -Total Violations: {count} ({severity}) - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-06-traceability-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- All FRs extracted and analyzed for measurability -- All NFRs extracted and analyzed for measurability -- Violations documented with line numbers -- Severity assessed correctly -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not analyzing all FRs and NFRs -- Missing line numbers for violations -- Not reporting findings to validation report -- Not assessing severity -- Not auto-proceeding - -**Master Rule:** Requirements must be testable to be useful. Validate every requirement for measurability, document violations, auto-proceed. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md deleted file mode 100644 index 84bf9cce9..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +++ /dev/null @@ -1,217 +0,0 @@ ---- -name: 'step-v-06-traceability-validation' -description: 'Traceability Validation - Validate the traceability chain from vision → success → journeys → FRs is intact' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-07-implementation-leakage-validation.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 6: Traceability Validation - -## STEP GOAL: - -Validate the traceability chain from Executive Summary → Success Criteria → User Journeys → Functional Requirements is intact, ensuring every requirement traces back to a user need or business objective. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring analytical rigor and traceability matrix expertise -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on traceability chain validation -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Systematic chain validation and orphan detection -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Build and validate traceability matrix -- 💾 Identify broken chains and orphan requirements -- 📖 Append findings to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file, validation report -- Focus: Traceability chain validation only -- Limits: Don't validate other aspects, don't pause for user input -- Dependencies: Steps 2-5 completed - initial validations done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Attempt Sub-Process Validation - -**Try to use Task tool to spawn a subprocess:** - -"Perform traceability validation on this PRD: - -1. Extract content from Executive Summary (vision, goals) -2. Extract Success Criteria -3. Extract User Journeys (user types, flows, outcomes) -4. Extract Functional Requirements (FRs) -5. Extract Product Scope (in-scope items) - -**Validate chains:** -- Executive Summary → Success Criteria: Does vision align with defined success? -- Success Criteria → User Journeys: Are success criteria supported by user journeys? -- User Journeys → Functional Requirements: Does each FR trace back to a user journey? -- Scope → FRs: Do MVP scope FRs align with in-scope items? - -**Identify orphans:** -- FRs not traceable to any user journey or business objective -- Success criteria not supported by user journeys -- User journeys without supporting FRs - -Build traceability matrix and identify broken chains and orphan FRs. - -Return structured findings with chain status and orphan list." - -### 2. Graceful Degradation (if Task tool unavailable) - -If Task tool unavailable, perform analysis directly: - -**Step 1: Extract key elements** -- Executive Summary: Note vision, goals, objectives -- Success Criteria: List all criteria -- User Journeys: List user types and their flows -- Functional Requirements: List all FRs -- Product Scope: List in-scope items - -**Step 2: Validate Executive Summary → Success Criteria** -- Does Executive Summary mention the success dimensions? -- Are Success Criteria aligned with vision? -- Note any misalignment - -**Step 3: Validate Success Criteria → User Journeys** -- For each success criterion, is there a user journey that achieves it? -- Note success criteria without supporting journeys - -**Step 4: Validate User Journeys → FRs** -- For each user journey/flow, are there FRs that enable it? -- List FRs with no clear user journey origin -- Note orphan FRs (requirements without traceable source) - -**Step 5: Validate Scope → FR Alignment** -- Does MVP scope align with essential FRs? -- Are in-scope items supported by FRs? -- Note misalignments - -**Step 6: Build traceability matrix** -- Map each FR to its source (journey or business objective) -- Note orphan FRs -- Identify broken chains - -### 3. Tally Traceability Issues - -**Broken chains:** -- Executive Summary → Success Criteria gaps: count -- Success Criteria → User Journeys gaps: count -- User Journeys → FRs gaps: count -- Scope → FR misalignments: count - -**Orphan elements:** -- Orphan FRs (no traceable source): count -- Unsupported success criteria: count -- User journeys without FRs: count - -**Total issues:** Sum of all broken chains and orphans - -### 4. Report Traceability Findings to Validation Report - -Append to validation report: - -```markdown -## Traceability Validation - -### Chain Validation - -**Executive Summary → Success Criteria:** [Intact/Gaps Identified] -{If gaps: List specific misalignments} - -**Success Criteria → User Journeys:** [Intact/Gaps Identified] -{If gaps: List unsupported success criteria} - -**User Journeys → Functional Requirements:** [Intact/Gaps Identified] -{If gaps: List journeys without supporting FRs} - -**Scope → FR Alignment:** [Intact/Misaligned] -{If misaligned: List specific issues} - -### Orphan Elements - -**Orphan Functional Requirements:** {count} -{List orphan FRs with numbers} - -**Unsupported Success Criteria:** {count} -{List unsupported criteria} - -**User Journeys Without FRs:** {count} -{List journeys without FRs} - -### Traceability Matrix - -{Summary table showing traceability coverage} - -**Total Traceability Issues:** {total} - -**Severity:** [Critical if orphan FRs exist, Warning if gaps, Pass if intact] - -**Recommendation:** -[If Critical] "Orphan requirements exist - every FR must trace back to a user need or business objective." -[If Warning] "Traceability gaps identified - strengthen chains to ensure all requirements are justified." -[If Pass] "Traceability chain is intact - all requirements trace to user needs or business objectives." -``` - -### 5. Display Progress and Auto-Proceed - -Display: "**Traceability Validation Complete** - -Total Issues: {count} ({severity}) - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-07-implementation-leakage-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- All traceability chains validated systematically -- Orphan FRs identified with numbers -- Broken chains documented -- Traceability matrix built -- Severity assessed correctly -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not validating all traceability chains -- Missing orphan FR detection -- Not building traceability matrix -- Not reporting findings to validation report -- Not auto-proceeding - -**Master Rule:** Every requirement should trace to a user need or business objective. Orphan FRs indicate broken traceability that must be fixed. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md deleted file mode 100644 index 923f99691..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -name: 'step-v-07-implementation-leakage-validation' -description: 'Implementation Leakage Check - Ensure FRs and NFRs don\'t include implementation details' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-08-domain-compliance-validation.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 7: Implementation Leakage Validation - -## STEP GOAL: - -Ensure Functional Requirements and Non-Functional Requirements don't include implementation details - they should specify WHAT, not HOW. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring analytical rigor and separation of concerns expertise -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on implementation leakage detection -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Systematic scanning for technology and implementation terms -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Scan FRs and NFRs for implementation terms -- 💾 Distinguish capability-relevant vs leakage -- 📖 Append findings to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file, validation report -- Focus: Implementation leakage detection only -- Limits: Don't validate other aspects, don't pause for user input -- Dependencies: Steps 2-6 completed - initial validations done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Attempt Sub-Process Validation - -**Try to use Task tool to spawn a subprocess:** - -"Perform implementation leakage validation on this PRD: - -**Scan for:** -1. Technology names (React, Vue, Angular, PostgreSQL, MongoDB, AWS, GCP, Azure, Docker, Kubernetes, etc.) -2. Library names (Redux, axios, lodash, Express, Django, Rails, Spring, etc.) -3. Data structures (JSON, XML, CSV) unless relevant to capability -4. Architecture patterns (MVC, microservices, serverless) unless business requirement -5. Protocol names (HTTP, REST, GraphQL, WebSockets) - check if capability-relevant - -**For each term found:** -- Is this capability-relevant? (e.g., 'API consumers can access...' - API is capability) -- Or is this implementation detail? (e.g., 'React component for...' - implementation) - -Document violations with line numbers and explanation. - -Return structured findings with leakage counts and examples." - -### 2. Graceful Degradation (if Task tool unavailable) - -If Task tool unavailable, perform analysis directly: - -**Implementation leakage terms to scan for:** - -**Frontend Frameworks:** -React, Vue, Angular, Svelte, Solid, Next.js, Nuxt, etc. - -**Backend Frameworks:** -Express, Django, Rails, Spring, Laravel, FastAPI, etc. - -**Databases:** -PostgreSQL, MySQL, MongoDB, Redis, DynamoDB, Cassandra, etc. - -**Cloud Platforms:** -AWS, GCP, Azure, Cloudflare, Vercel, Netlify, etc. - -**Infrastructure:** -Docker, Kubernetes, Terraform, Ansible, etc. - -**Libraries:** -Redux, Zustand, axios, fetch, lodash, jQuery, etc. - -**Data Formats:** -JSON, XML, YAML, CSV (unless capability-relevant) - -**For each term found in FRs/NFRs:** -- Determine if it's capability-relevant or implementation leakage -- Example: "API consumers can access data via REST endpoints" - API/REST is capability -- Example: "React components fetch data using Redux" - implementation leakage - -**Count violations and note line numbers** - -### 3. Tally Implementation Leakage - -**By category:** -- Frontend framework leakage: count -- Backend framework leakage: count -- Database leakage: count -- Cloud platform leakage: count -- Infrastructure leakage: count -- Library leakage: count -- Other implementation details: count - -**Total implementation leakage violations:** sum - -### 4. Report Implementation Leakage Findings to Validation Report - -Append to validation report: - -```markdown -## Implementation Leakage Validation - -### Leakage by Category - -**Frontend Frameworks:** {count} violations -{If violations, list examples with line numbers} - -**Backend Frameworks:** {count} violations -{If violations, list examples with line numbers} - -**Databases:** {count} violations -{If violations, list examples with line numbers} - -**Cloud Platforms:** {count} violations -{If violations, list examples with line numbers} - -**Infrastructure:** {count} violations -{If violations, list examples with line numbers} - -**Libraries:** {count} violations -{If violations, list examples with line numbers} - -**Other Implementation Details:** {count} violations -{If violations, list examples with line numbers} - -### Summary - -**Total Implementation Leakage Violations:** {total} - -**Severity:** [Critical if >5 violations, Warning if 2-5, Pass if <2] - -**Recommendation:** -[If Critical] "Extensive implementation leakage found. Requirements specify HOW instead of WHAT. Remove all implementation details - these belong in architecture, not PRD." -[If Warning] "Some implementation leakage detected. Review violations and remove implementation details from requirements." -[If Pass] "No significant implementation leakage found. Requirements properly specify WHAT without HOW." - -**Note:** API consumers, GraphQL (when required), and other capability-relevant terms are acceptable when they describe WHAT the system must do, not HOW to build it. -``` - -### 5. Display Progress and Auto-Proceed - -Display: "**Implementation Leakage Validation Complete** - -Total Violations: {count} ({severity}) - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-08-domain-compliance-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- Scanned FRs and NFRs for all implementation term categories -- Distinguished capability-relevant from implementation leakage -- Violations documented with line numbers and explanations -- Severity assessed correctly -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not scanning all implementation term categories -- Not distinguishing capability-relevant from leakage -- Missing line numbers for violations -- Not reporting findings to validation report -- Not auto-proceeding - -**Master Rule:** Requirements specify WHAT, not HOW. Implementation details belong in architecture documents, not PRDs. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md deleted file mode 100644 index 562697eda..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +++ /dev/null @@ -1,243 +0,0 @@ ---- -name: 'step-v-08-domain-compliance-validation' -description: 'Domain Compliance Validation - Validate domain-specific requirements are present for high-complexity domains' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-09-project-type-validation.md' -prdFile: '{prd_file_path}' -prdFrontmatter: '{prd_frontmatter}' -validationReportPath: '{validation_report_path}' -domainComplexityData: '../data/domain-complexity.csv' ---- - -# Step 8: Domain Compliance Validation - -## STEP GOAL: - -Validate domain-specific requirements are present for high-complexity domains (Healthcare, Fintech, GovTech, etc.), ensuring regulatory and compliance requirements are properly documented. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring domain expertise and compliance knowledge -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on domain-specific compliance requirements -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Conditional validation based on domain classification -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Check classification.domain from PRD frontmatter -- 💬 If low complexity (general): Skip detailed checks -- 🎯 If high complexity: Validate required special sections -- 💾 Append compliance findings to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file with frontmatter classification, validation report -- Focus: Domain compliance only (conditional on domain complexity) -- Limits: Don't validate other aspects, conditional execution -- Dependencies: Steps 2-7 completed - format and requirements validation done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Load Domain Complexity Data - -Load and read the complete file at: -`{domainComplexityData}` (../data/domain-complexity.csv) - -This CSV contains: -- Domain classifications and complexity levels (high/medium/low) -- Required special sections for each domain -- Key concerns and requirements for regulated industries - -Internalize this data - it drives which domains require special compliance sections. - -### 2. Extract Domain Classification - -From PRD frontmatter, extract: -- `classification.domain` - what domain is this PRD for? - -**If no domain classification found:** -Treat as "general" (low complexity) and proceed to step 4 - -### 2. Determine Domain Complexity - -**Low complexity domains (skip detailed checks):** -- General -- Consumer apps (standard e-commerce, social, productivity) -- Content websites -- Business tools (standard) - -**High complexity domains (require special sections):** -- Healthcare / Healthtech -- Fintech / Financial services -- GovTech / Public sector -- EdTech (educational records, accredited courses) -- Legal tech -- Other regulated domains - -### 3. For High-Complexity Domains: Validate Required Special Sections - -**Attempt subprocess validation:** - -"Perform domain compliance validation for {domain}: - -Based on {domain} requirements, check PRD for: - -**Healthcare:** -- Clinical Requirements section -- Regulatory Pathway (FDA, HIPAA, etc.) -- Safety Measures -- HIPAA Compliance (data privacy, security) -- Patient safety considerations - -**Fintech:** -- Compliance Matrix (SOC2, PCI-DSS, GDPR, etc.) -- Security Architecture -- Audit Requirements -- Fraud Prevention measures -- Financial transaction handling - -**GovTech:** -- Accessibility Standards (WCAG 2.1 AA, Section 508) -- Procurement Compliance -- Security Clearance requirements -- Data residency requirements - -**Other regulated domains:** -- Check for domain-specific regulatory sections -- Compliance requirements -- Special considerations - -For each required section: -- Is it present in PRD? -- Is it adequately documented? -- Note any gaps - -Return compliance matrix with presence/adequacy assessment." - -**Graceful degradation (if no Task tool):** -- Manually check for required sections based on domain -- List present sections and missing sections -- Assess adequacy of documentation - -### 5. For Low-Complexity Domains: Skip Detailed Checks - -Append to validation report: -```markdown -## Domain Compliance Validation - -**Domain:** {domain} -**Complexity:** Low (general/standard) -**Assessment:** N/A - No special domain compliance requirements - -**Note:** This PRD is for a standard domain without regulatory compliance requirements. -``` - -Display: "**Domain Compliance Validation Skipped** - -Domain: {domain} (low complexity) - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} - -### 6. Report Compliance Findings (High-Complexity Domains) - -Append to validation report: - -```markdown -## Domain Compliance Validation - -**Domain:** {domain} -**Complexity:** High (regulated) - -### Required Special Sections - -**{Section 1 Name}:** [Present/Missing/Adequate] -{If missing or inadequate: Note specific gaps} - -**{Section 2 Name}:** [Present/Missing/Adequate] -{If missing or inadequate: Note specific gaps} - -[Continue for all required sections] - -### Compliance Matrix - -| Requirement | Status | Notes | -|-------------|--------|-------| -| {Requirement 1} | [Met/Partial/Missing] | {Notes} | -| {Requirement 2} | [Met/Partial/Missing] | {Notes} | -[... continue for all requirements] - -### Summary - -**Required Sections Present:** {count}/{total} -**Compliance Gaps:** {count} - -**Severity:** [Critical if missing regulatory sections, Warning if incomplete, Pass if complete] - -**Recommendation:** -[If Critical] "PRD is missing required domain-specific compliance sections. These are essential for {domain} products." -[If Warning] "Some domain compliance sections are incomplete. Strengthen documentation for full compliance." -[If Pass] "All required domain compliance sections are present and adequately documented." -``` - -### 7. Display Progress and Auto-Proceed - -Display: "**Domain Compliance Validation Complete** - -Domain: {domain} ({complexity}) -Compliance Status: {status} - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-09-project-type-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- Domain classification extracted correctly -- Complexity assessed appropriately -- Low complexity domains: Skipped with clear "N/A" documentation -- High complexity domains: All required sections checked -- Compliance matrix built with status for each requirement -- Severity assessed correctly -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not checking domain classification before proceeding -- Performing detailed checks on low complexity domains -- For high complexity: missing required section checks -- Not building compliance matrix -- Not reporting findings to validation report -- Not auto-proceeding - -**Master Rule:** Domain compliance is conditional. High-complexity domains require special sections - low complexity domains skip these checks. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md deleted file mode 100644 index aea41d924..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +++ /dev/null @@ -1,263 +0,0 @@ ---- -name: 'step-v-09-project-type-validation' -description: 'Project-Type Compliance Validation - Validate project-type specific requirements are properly documented' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-10-smart-validation.md' -prdFile: '{prd_file_path}' -prdFrontmatter: '{prd_frontmatter}' -validationReportPath: '{validation_report_path}' -projectTypesData: '../data/project-types.csv' ---- - -# Step 9: Project-Type Compliance Validation - -## STEP GOAL: - -Validate project-type specific requirements are properly documented - different project types (api_backend, web_app, mobile_app, etc.) have different required and excluded sections. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring project type expertise and architectural knowledge -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on project-type compliance -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Validate required sections present, excluded sections absent -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Check classification.projectType from PRD frontmatter -- 🎯 Validate required sections for that project type are present -- 🎯 Validate excluded sections for that project type are absent -- 💾 Append compliance findings to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file with frontmatter classification, validation report -- Focus: Project-type compliance only -- Limits: Don't validate other aspects, don't pause for user input -- Dependencies: Steps 2-8 completed - domain and requirements validation done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Load Project Types Data - -Load and read the complete file at: -`{projectTypesData}` (../data/project-types.csv) - -This CSV contains: -- Detection signals for each project type -- Required sections for each project type -- Skip/excluded sections for each project type -- Innovation signals - -Internalize this data - it drives what sections must be present or absent for each project type. - -### 2. Extract Project Type Classification - -From PRD frontmatter, extract: -- `classification.projectType` - what type of project is this? - -**Common project types:** -- api_backend -- web_app -- mobile_app -- desktop_app -- data_pipeline -- ml_system -- library_sdk -- infrastructure -- other - -**If no projectType classification found:** -Assume "web_app" (most common) and note in findings - -### 3. Determine Required and Excluded Sections from CSV Data - -**From loaded project-types.csv data, for this project type:** - -**Required sections:** (from required_sections column) -These MUST be present in the PRD - -**Skip sections:** (from skip_sections column) -These MUST NOT be present in the PRD - -**Example mappings from CSV:** -- api_backend: Required=[endpoint_specs, auth_model, data_schemas], Skip=[ux_ui, visual_design] -- mobile_app: Required=[platform_reqs, device_permissions, offline_mode], Skip=[desktop_features, cli_commands] -- cli_tool: Required=[command_structure, output_formats, config_schema], Skip=[visual_design, ux_principles, touch_interactions] -- etc. - -### 4. Validate Against CSV-Based Requirements - -**Based on project type, determine:** - -**api_backend:** -- Required: Endpoint Specs, Auth Model, Data Schemas, API Versioning -- Excluded: UX/UI sections, mobile-specific sections - -**web_app:** -- Required: User Journeys, UX/UI Requirements, Responsive Design -- Excluded: None typically - -**mobile_app:** -- Required: Mobile UX, Platform specifics (iOS/Android), Offline mode -- Excluded: Desktop-specific sections - -**desktop_app:** -- Required: Desktop UX, Platform specifics (Windows/Mac/Linux) -- Excluded: Mobile-specific sections - -**data_pipeline:** -- Required: Data Sources, Data Transformation, Data Sinks, Error Handling -- Excluded: UX/UI sections - -**ml_system:** -- Required: Model Requirements, Training Data, Inference Requirements, Model Performance -- Excluded: UX/UI sections (unless ML UI) - -**library_sdk:** -- Required: API Surface, Usage Examples, Integration Guide -- Excluded: UX/UI sections, deployment sections - -**infrastructure:** -- Required: Infrastructure Components, Deployment, Monitoring, Scaling -- Excluded: Feature requirements (this is infrastructure, not product) - -### 4. Attempt Sub-Process Validation - -"Perform project-type compliance validation for {projectType}: - -**Check that required sections are present:** -{List required sections for this project type} -For each: Is it present in PRD? Is it adequately documented? - -**Check that excluded sections are absent:** -{List excluded sections for this project type} -For each: Is it absent from PRD? (Should not be present) - -Build compliance table showing: -- Required sections: [Present/Missing/Incomplete] -- Excluded sections: [Absent/Present] (Present = violation) - -Return compliance table with findings." - -**Graceful degradation (if no Task tool):** -- Manually check PRD for required sections -- Manually check PRD for excluded sections -- Build compliance table - -### 5. Build Compliance Table - -**Required sections check:** -- For each required section: Present / Missing / Incomplete -- Count: Required sections present vs total required - -**Excluded sections check:** -- For each excluded section: Absent / Present (violation) -- Count: Excluded sections present (violations) - -**Total compliance score:** -- Required: {present}/{total} -- Excluded violations: {count} - -### 6. Report Project-Type Compliance Findings to Validation Report - -Append to validation report: - -```markdown -## Project-Type Compliance Validation - -**Project Type:** {projectType} - -### Required Sections - -**{Section 1}:** [Present/Missing/Incomplete] -{If missing or incomplete: Note specific gaps} - -**{Section 2}:** [Present/Missing/Incomplete] -{If missing or incomplete: Note specific gaps} - -[Continue for all required sections] - -### Excluded Sections (Should Not Be Present) - -**{Section 1}:** [Absent/Present] ✓ -{If present: This section should not be present for {projectType}} - -**{Section 2}:** [Absent/Present] ✓ -{If present: This section should not be present for {projectType}} - -[Continue for all excluded sections] - -### Compliance Summary - -**Required Sections:** {present}/{total} present -**Excluded Sections Present:** {violations} (should be 0) -**Compliance Score:** {percentage}% - -**Severity:** [Critical if required sections missing, Warning if incomplete, Pass if complete] - -**Recommendation:** -[If Critical] "PRD is missing required sections for {projectType}. Add missing sections to properly specify this type of project." -[If Warning] "Some required sections for {projectType} are incomplete. Strengthen documentation." -[If Pass] "All required sections for {projectType} are present. No excluded sections found." -``` - -### 7. Display Progress and Auto-Proceed - -Display: "**Project-Type Compliance Validation Complete** - -Project Type: {projectType} -Compliance: {score}% - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-10-smart-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- Project type extracted correctly (or default assumed) -- Required sections validated for presence and completeness -- Excluded sections validated for absence -- Compliance table built with status for all sections -- Severity assessed correctly -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not checking project type before proceeding -- Missing required section checks -- Missing excluded section checks -- Not building compliance table -- Not reporting findings to validation report -- Not auto-proceeding - -**Master Rule:** Different project types have different requirements. API PRDs don't need UX sections - validate accordingly. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md deleted file mode 100644 index 0c44b00da..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -name: 'step-v-10-smart-validation' -description: 'SMART Requirements Validation - Validate Functional Requirements meet SMART quality criteria' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-11-holistic-quality-validation.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 10: SMART Requirements Validation - -## STEP GOAL: - -Validate Functional Requirements meet SMART quality criteria (Specific, Measurable, Attainable, Relevant, Traceable), ensuring high-quality requirements. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ 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}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring requirements engineering expertise and quality assessment -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on FR quality assessment using SMART framework -- 🚫 FORBIDDEN to validate other aspects in this step -- 💬 Approach: Score each FR on SMART criteria (1-5 scale) -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Extract all FRs from PRD -- 🎯 Score each FR on SMART criteria (Specific, Measurable, Attainable, Relevant, Traceable) -- 💾 Flag FRs with score < 3 in any category -- 📖 Append scoring table and suggestions to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: PRD file, validation report -- Focus: FR quality assessment only using SMART framework -- Limits: Don't validate NFRs or other aspects, don't pause for user input -- Dependencies: Steps 2-9 completed - comprehensive validation checks done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Extract All Functional Requirements - -From the PRD's Functional Requirements section, extract: -- All FRs with their FR numbers (FR-001, FR-002, etc.) -- Count total FRs - -### 2. Attempt Sub-Process Validation - -**Try to use Task tool to spawn a subprocess:** - -"Perform SMART requirements validation on these Functional Requirements: - -{List all FRs} - -**For each FR, score on SMART criteria (1-5 scale):** - -**Specific (1-5):** -- 5: Clear, unambiguous, well-defined -- 3: Somewhat clear but could be more specific -- 1: Vague, ambiguous, unclear - -**Measurable (1-5):** -- 5: Quantifiable metrics, testable -- 3: Partially measurable -- 1: Not measurable, subjective - -**Attainable (1-5):** -- 5: Realistic, achievable with constraints -- 3: Probably achievable but uncertain -- 1: Unrealistic, technically infeasible - -**Relevant (1-5):** -- 5: Clearly aligned with user needs and business objectives -- 3: Somewhat relevant but connection unclear -- 1: Not relevant, doesn't align with goals - -**Traceable (1-5):** -- 5: Clearly traces to user journey or business objective -- 3: Partially traceable -- 1: Orphan requirement, no clear source - -**For each FR with score < 3 in any category:** -- Provide specific improvement suggestions - -Return scoring table with all FR scores and improvement suggestions for low-scoring FRs." - -**Graceful degradation (if no Task tool):** -- Manually score each FR on SMART criteria -- Note FRs with low scores -- Provide improvement suggestions - -### 3. Build Scoring Table - -For each FR: -- FR number -- Specific score (1-5) -- Measurable score (1-5) -- Attainable score (1-5) -- Relevant score (1-5) -- Traceable score (1-5) -- Average score -- Flag if any category < 3 - -**Calculate overall FR quality:** -- Percentage of FRs with all scores ≥ 3 -- Percentage of FRs with all scores ≥ 4 -- Average score across all FRs and categories - -### 4. Report SMART Findings to Validation Report - -Append to validation report: - -```markdown -## SMART Requirements Validation - -**Total Functional Requirements:** {count} - -### Scoring Summary - -**All scores ≥ 3:** {percentage}% ({count}/{total}) -**All scores ≥ 4:** {percentage}% ({count}/{total}) -**Overall Average Score:** {average}/5.0 - -### Scoring Table - -| FR # | Specific | Measurable | Attainable | Relevant | Traceable | Average | Flag | -|------|----------|------------|------------|----------|-----------|--------|------| -| FR-001 | {s1} | {m1} | {a1} | {r1} | {t1} | {avg1} | {X if any <3} | -| FR-002 | {s2} | {m2} | {a2} | {r2} | {t2} | {avg2} | {X if any <3} | -[Continue for all FRs] - -**Legend:** 1=Poor, 3=Acceptable, 5=Excellent -**Flag:** X = Score < 3 in one or more categories - -### Improvement Suggestions - -**Low-Scoring FRs:** - -**FR-{number}:** {specific suggestion for improvement} -[For each FR with score < 3 in any category] - -### Overall Assessment - -**Severity:** [Critical if >30% flagged FRs, Warning if 10-30%, Pass if <10%] - -**Recommendation:** -[If Critical] "Many FRs have quality issues. Revise flagged FRs using SMART framework to improve clarity and testability." -[If Warning] "Some FRs would benefit from SMART refinement. Focus on flagged requirements above." -[If Pass] "Functional Requirements demonstrate good SMART quality overall." -``` - -### 5. Display Progress and Auto-Proceed - -Display: "**SMART Requirements Validation Complete** - -FR Quality: {percentage}% with acceptable scores ({severity}) - -**Proceeding to next validation check...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-11-holistic-quality-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- All FRs extracted from PRD -- Each FR scored on all 5 SMART criteria (1-5 scale) -- FRs with scores < 3 flagged for improvement -- Improvement suggestions provided for low-scoring FRs -- Scoring table built with all FR scores -- Overall quality assessment calculated -- Findings reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not scoring all FRs on all SMART criteria -- Missing improvement suggestions for low-scoring FRs -- Not building scoring table -- Not calculating overall quality metrics -- Not reporting findings to validation report -- Not auto-proceeding - -**Master Rule:** FRs should be high-quality, not just present. SMART framework provides objective quality measure. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md deleted file mode 100644 index f34dee65a..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +++ /dev/null @@ -1,264 +0,0 @@ ---- -name: 'step-v-11-holistic-quality-validation' -description: 'Holistic Quality Assessment - Assess PRD as cohesive, compelling document - is it a good PRD?' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-12-completeness-validation.md' -prdFile: '{prd_file_path}' -validationReportPath: '{validation_report_path}' ---- - -# Step 11: Holistic Quality Assessment - -## STEP GOAL: - -Assess the PRD as a cohesive, compelling document - evaluating document flow, dual audience effectiveness (humans and LLMs), BMAD PRD principles compliance, and overall quality rating. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ 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}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring analytical rigor and document quality expertise -- ✅ This step runs autonomously - no user input needed -- ✅ Uses Advanced Elicitation for multi-perspective evaluation - -### Step-Specific Rules: - -- 🎯 Focus ONLY on holistic document quality assessment -- 🚫 FORBIDDEN to validate individual components (done in previous steps) -- 💬 Approach: Multi-perspective evaluation using Advanced Elicitation -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Use Advanced Elicitation for multi-perspective assessment -- 🎯 Evaluate document flow, dual audience, BMAD principles -- 💾 Append comprehensive assessment to validation report -- 📖 Display "Proceeding to next check..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: Complete PRD file, validation report with findings from steps 1-10 -- Focus: Holistic quality - the WHOLE document -- Limits: Don't re-validate individual components, don't pause for user input -- Dependencies: Steps 1-10 completed - all systematic checks done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Attempt Sub-Process with Advanced Elicitation - -**Try to use Task tool to spawn a subprocess using Advanced Elicitation:** - -"Perform holistic quality assessment on this PRD using multi-perspective evaluation: - -**Advanced Elicitation workflow:** -Invoke the `bmad-advanced-elicitation` skill - -**Evaluate the PRD from these perspectives:** - -**1. Document Flow & Coherence:** -- Read entire PRD -- Evaluate narrative flow - does it tell a cohesive story? -- Check transitions between sections -- Assess consistency - is it coherent throughout? -- Evaluate readability - is it clear and well-organized? - -**2. Dual Audience Effectiveness:** - -**For Humans:** -- Executive-friendly: Can executives understand vision and goals quickly? -- Developer clarity: Do developers have clear requirements to build from? -- Designer clarity: Do designers understand user needs and flows? -- Stakeholder decision-making: Can stakeholders make informed decisions? - -**For LLMs:** -- Machine-readable structure: Is the PRD structured for LLM consumption? -- UX readiness: Can an LLM generate UX designs from this? -- Architecture readiness: Can an LLM generate architecture from this? -- Epic/Story readiness: Can an LLM break down into epics and stories? - -**3. BMAD PRD Principles Compliance:** -- Information density: Every sentence carries weight? -- Measurability: Requirements testable? -- Traceability: Requirements trace to sources? -- Domain awareness: Domain-specific considerations included? -- Zero anti-patterns: No filler or wordiness? -- Dual audience: Works for both humans and LLMs? -- Markdown format: Proper structure and formatting? - -**4. Overall Quality Rating:** -Rate the PRD on 5-point scale: -- Excellent (5/5): Exemplary, ready for production use -- Good (4/5): Strong with minor improvements needed -- Adequate (3/5): Acceptable but needs refinement -- Needs Work (2/5): Significant gaps or issues -- Problematic (1/5): Major flaws, needs substantial revision - -**5. Top 3 Improvements:** -Identify the 3 most impactful improvements to make this a great PRD - -Return comprehensive assessment with all perspectives, rating, and top 3 improvements." - -**Graceful degradation (if no Task tool or Advanced Elicitation unavailable):** -- Perform holistic assessment directly in current context -- Read complete PRD -- Evaluate document flow, coherence, transitions -- Assess dual audience effectiveness -- Check BMAD principles compliance -- Assign overall quality rating -- Identify top 3 improvements - -### 2. Synthesize Assessment - -**Compile findings from multi-perspective evaluation:** - -**Document Flow & Coherence:** -- Overall assessment: [Excellent/Good/Adequate/Needs Work/Problematic] -- Key strengths: [list] -- Key weaknesses: [list] - -**Dual Audience Effectiveness:** -- For Humans: [assessment] -- For LLMs: [assessment] -- Overall dual audience score: [1-5] - -**BMAD Principles Compliance:** -- Principles met: [count]/7 -- Principles with issues: [list] - -**Overall Quality Rating:** [1-5 with label] - -**Top 3 Improvements:** -1. [Improvement 1] -2. [Improvement 2] -3. [Improvement 3] - -### 3. Report Holistic Quality Findings to Validation Report - -Append to validation report: - -```markdown -## Holistic Quality Assessment - -### Document Flow & Coherence - -**Assessment:** [Excellent/Good/Adequate/Needs Work/Problematic] - -**Strengths:** -{List key strengths} - -**Areas for Improvement:** -{List key weaknesses} - -### Dual Audience Effectiveness - -**For Humans:** -- Executive-friendly: [assessment] -- Developer clarity: [assessment] -- Designer clarity: [assessment] -- Stakeholder decision-making: [assessment] - -**For LLMs:** -- Machine-readable structure: [assessment] -- UX readiness: [assessment] -- Architecture readiness: [assessment] -- Epic/Story readiness: [assessment] - -**Dual Audience Score:** {score}/5 - -### BMAD PRD Principles Compliance - -| Principle | Status | Notes | -|-----------|--------|-------| -| Information Density | [Met/Partial/Not Met] | {notes} | -| Measurability | [Met/Partial/Not Met] | {notes} | -| Traceability | [Met/Partial/Not Met] | {notes} | -| Domain Awareness | [Met/Partial/Not Met] | {notes} | -| Zero Anti-Patterns | [Met/Partial/Not Met] | {notes} | -| Dual Audience | [Met/Partial/Not Met] | {notes} | -| Markdown Format | [Met/Partial/Not Met] | {notes} | - -**Principles Met:** {count}/7 - -### Overall Quality Rating - -**Rating:** {rating}/5 - {label} - -**Scale:** -- 5/5 - Excellent: Exemplary, ready for production use -- 4/5 - Good: Strong with minor improvements needed -- 3/5 - Adequate: Acceptable but needs refinement -- 2/5 - Needs Work: Significant gaps or issues -- 1/5 - Problematic: Major flaws, needs substantial revision - -### Top 3 Improvements - -1. **{Improvement 1}** - {Brief explanation of why and how} - -2. **{Improvement 2}** - {Brief explanation of why and how} - -3. **{Improvement 3}** - {Brief explanation of why and how} - -### Summary - -**This PRD is:** {one-sentence overall assessment} - -**To make it great:** Focus on the top 3 improvements above. -``` - -### 4. Display Progress and Auto-Proceed - -Display: "**Holistic Quality Assessment Complete** - -Overall Rating: {rating}/5 - {label} - -**Proceeding to final validation checks...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-12-completeness-validation.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- Advanced Elicitation used for multi-perspective evaluation (or graceful degradation) -- Document flow & coherence assessed -- Dual audience effectiveness evaluated (humans and LLMs) -- BMAD PRD principles compliance checked -- Overall quality rating assigned (1-5 scale) -- Top 3 improvements identified -- Comprehensive assessment reported to validation report -- Auto-proceeds to next validation step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not using Advanced Elicitation for multi-perspective evaluation -- Missing document flow assessment -- Missing dual audience evaluation -- Not checking all BMAD principles -- Not assigning overall quality rating -- Missing top 3 improvements -- Not reporting comprehensive assessment to validation report -- Not auto-proceeding - -**Master Rule:** This evaluates the WHOLE document, not just components. Answers "Is this a good PRD?" and "What would make it great?" diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md deleted file mode 100644 index 00c477981..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +++ /dev/null @@ -1,242 +0,0 @@ ---- -name: 'step-v-12-completeness-validation' -description: 'Completeness Check - Final comprehensive completeness check before report generation' - -# File references (ONLY variables used in this step) -nextStepFile: './step-v-13-report-complete.md' -prdFile: '{prd_file_path}' -prdFrontmatter: '{prd_frontmatter}' -validationReportPath: '{validation_report_path}' ---- - -# Step 12: Completeness Validation - -## STEP GOAL: - -Final comprehensive completeness check - validate no template variables remain, each section has required content, section-specific completeness, and frontmatter is properly populated. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in systematic validation, not collaborative dialogue -- ✅ You bring attention to detail and completeness verification -- ✅ This step runs autonomously - no user input needed - -### Step-Specific Rules: - -- 🎯 Focus ONLY on completeness verification -- 🚫 FORBIDDEN to validate quality (done in step 11) or other aspects -- 💬 Approach: Systematic checklist-style verification -- 🚪 This is a validation sequence step - auto-proceeds when complete - -## EXECUTION PROTOCOLS: - -- 🎯 Check template completeness (no variables remaining) -- 🎯 Validate content completeness (each section has required content) -- 🎯 Validate section-specific completeness -- 🎯 Validate frontmatter completeness -- 💾 Append completeness matrix to validation report -- 📖 Display "Proceeding to final step..." and load next step -- 🚫 FORBIDDEN to pause or request user input - -## CONTEXT BOUNDARIES: - -- Available context: Complete PRD file, frontmatter, validation report -- Focus: Completeness verification only (final gate) -- Limits: Don't assess quality, don't pause for user input -- Dependencies: Steps 1-11 completed - all validation checks done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Attempt Sub-Process Validation - -**Try to use Task tool to spawn a subprocess:** - -"Perform completeness validation on this PRD - final gate check: - -**1. Template Completeness:** -- Scan PRD for any remaining template variables -- Look for: {variable}, {{variable}}, {placeholder}, [placeholder], etc. -- List any found with line numbers - -**2. Content Completeness:** -- Executive Summary: Has vision statement? ({key content}) -- Success Criteria: All criteria measurable? ({metrics present}) -- Product Scope: In-scope and out-of-scope defined? ({both present}) -- User Journeys: User types identified? ({users listed}) -- Functional Requirements: FRs listed with proper format? ({FRs present}) -- Non-Functional Requirements: NFRs with metrics? ({NFRs present}) - -For each section: Is required content present? (Yes/No/Partial) - -**3. Section-Specific Completeness:** -- Success Criteria: Each has specific measurement method? -- User Journeys: Cover all user types? -- Functional Requirements: Cover MVP scope? -- Non-Functional Requirements: Each has specific criteria? - -**4. Frontmatter Completeness:** -- stepsCompleted: Populated? -- classification: Present (domain, projectType)? -- inputDocuments: Tracked? -- date: Present? - -Return completeness matrix with status for each check." - -**Graceful degradation (if no Task tool):** -- Manually scan for template variables -- Manually check each section for required content -- Manually verify frontmatter fields -- Build completeness matrix - -### 2. Build Completeness Matrix - -**Template Completeness:** -- Template variables found: count -- List if any found - -**Content Completeness by Section:** -- Executive Summary: Complete / Incomplete / Missing -- Success Criteria: Complete / Incomplete / Missing -- Product Scope: Complete / Incomplete / Missing -- User Journeys: Complete / Incomplete / Missing -- Functional Requirements: Complete / Incomplete / Missing -- Non-Functional Requirements: Complete / Incomplete / Missing -- Other sections: [List completeness] - -**Section-Specific Completeness:** -- Success criteria measurable: All / Some / None -- Journeys cover all users: Yes / Partial / No -- FRs cover MVP scope: Yes / Partial / No -- NFRs have specific criteria: All / Some / None - -**Frontmatter Completeness:** -- stepsCompleted: Present / Missing -- classification: Present / Missing -- inputDocuments: Present / Missing -- date: Present / Missing - -**Overall completeness:** -- Sections complete: X/Y -- Critical gaps: [list if any] - -### 3. Report Completeness Findings to Validation Report - -Append to validation report: - -```markdown -## Completeness Validation - -### Template Completeness - -**Template Variables Found:** {count} -{If count > 0, list variables with line numbers} -{If count = 0, note: No template variables remaining ✓} - -### Content Completeness by Section - -**Executive Summary:** [Complete/Incomplete/Missing] -{If incomplete or missing, note specific gaps} - -**Success Criteria:** [Complete/Incomplete/Missing] -{If incomplete or missing, note specific gaps} - -**Product Scope:** [Complete/Incomplete/Missing] -{If incomplete or missing, note specific gaps} - -**User Journeys:** [Complete/Incomplete/Missing] -{If incomplete or missing, note specific gaps} - -**Functional Requirements:** [Complete/Incomplete/Missing] -{If incomplete or missing, note specific gaps} - -**Non-Functional Requirements:** [Complete/Incomplete/Missing] -{If incomplete or missing, note specific gaps} - -### Section-Specific Completeness - -**Success Criteria Measurability:** [All/Some/None] measurable -{If Some or None, note which criteria lack metrics} - -**User Journeys Coverage:** [Yes/Partial/No] - covers all user types -{If Partial or No, note missing user types} - -**FRs Cover MVP Scope:** [Yes/Partial/No] -{If Partial or No, note scope gaps} - -**NFRs Have Specific Criteria:** [All/Some/None] -{If Some or None, note which NFRs lack specificity} - -### Frontmatter Completeness - -**stepsCompleted:** [Present/Missing] -**classification:** [Present/Missing] -**inputDocuments:** [Present/Missing] -**date:** [Present/Missing] - -**Frontmatter Completeness:** {complete_fields}/4 - -### Completeness Summary - -**Overall Completeness:** {percentage}% ({complete_sections}/{total_sections}) - -**Critical Gaps:** [count] [list if any] -**Minor Gaps:** [count] [list if any] - -**Severity:** [Critical if template variables exist or critical sections missing, Warning if minor gaps, Pass if complete] - -**Recommendation:** -[If Critical] "PRD has completeness gaps that must be addressed before use. Fix template variables and complete missing sections." -[If Warning] "PRD has minor completeness gaps. Address minor gaps for complete documentation." -[If Pass] "PRD is complete with all required sections and content present." -``` - -### 4. Display Progress and Auto-Proceed - -Display: "**Completeness Validation Complete** - -Overall Completeness: {percentage}% ({severity}) - -**Proceeding to final step...**" - -Without delay, read fully and follow: {nextStepFile} (step-v-13-report-complete.md) - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- Scanned for template variables systematically -- Validated each section for required content -- Validated section-specific completeness (measurability, coverage, scope) -- Validated frontmatter completeness -- Completeness matrix built with all checks -- Severity assessed correctly -- Findings reported to validation report -- Auto-proceeds to final step -- Subprocess attempted with graceful degradation - -### ❌ SYSTEM FAILURE: - -- Not scanning for template variables -- Missing section-specific completeness checks -- Not validating frontmatter -- Not building completeness matrix -- Not reporting findings to validation report -- Not auto-proceeding - -**Master Rule:** Final gate to ensure document is complete before presenting findings. Template variables or critical gaps must be fixed. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md b/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md deleted file mode 100644 index b08a35db8..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +++ /dev/null @@ -1,232 +0,0 @@ ---- -name: 'step-v-13-report-complete' -description: 'Validation Report Complete - Finalize report, summarize findings, present to user, offer next steps' - -# File references (ONLY variables used in this step) -validationReportPath: '{validation_report_path}' -prdFile: '{prd_file_path}' ---- - -# Step 13: Validation Report Complete - -## STEP GOAL: - -Finalize validation report, summarize all findings from steps 1-12, present summary to user conversationally, and offer actionable next steps. - -## MANDATORY EXECUTION RULES (READ FIRST): - -### Universal Rules: - -- 🛑 NEVER generate content without user input -- 📖 CRITICAL: Read the complete step file before taking any action -- 🔄 CRITICAL: When loading next step with 'C', ensure entire file is read -- 📋 YOU ARE A FACILITATOR, not a content generator -- ✅ 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}` - -### Role Reinforcement: - -- ✅ You are a Validation Architect and Quality Assurance Specialist -- ✅ If you already have been given communication or persona patterns, continue to use those while playing this new role -- ✅ We engage in collaborative dialogue, not command-response -- ✅ You bring synthesis and summary expertise -- ✅ This is the FINAL step - requires user interaction - -### Step-Specific Rules: - -- 🎯 Focus ONLY on summarizing findings and presenting options -- 🚫 FORBIDDEN to perform additional validation -- 💬 Approach: Conversational summary with clear next steps -- 🚪 This is the final step - no next step after this - -## EXECUTION PROTOCOLS: - -- 🎯 Load complete validation report -- 🎯 Summarize all findings from steps 1-12 -- 🎯 Update report frontmatter with final status -- 💬 Present summary to user conversationally -- 💬 Offer menu options for next actions -- 🚫 FORBIDDEN to proceed without user selection - -## CONTEXT BOUNDARIES: - -- Available context: Complete validation report with findings from all validation steps -- Focus: Summary and presentation only (no new validation) -- Limits: Don't add new findings, just synthesize existing -- Dependencies: Steps 1-12 completed - all validation checks done - -## MANDATORY SEQUENCE - -**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change. - -### 1. Load Complete Validation Report - -Read the entire validation report from {validationReportPath} - -Extract all findings from: -- Format Detection (Step 2) -- Parity Analysis (Step 2B, if applicable) -- Information Density (Step 3) -- Product Brief Coverage (Step 4) -- Measurability (Step 5) -- Traceability (Step 6) -- Implementation Leakage (Step 7) -- Domain Compliance (Step 8) -- Project-Type Compliance (Step 9) -- SMART Requirements (Step 10) -- Holistic Quality (Step 11) -- Completeness (Step 12) - -### 2. Update Report Frontmatter with Final Status - -Update validation report frontmatter: - -```yaml ---- -validationTarget: '{prd_path}' -validationDate: '{current_date}' -inputDocuments: [list of documents] -validationStepsCompleted: ['step-v-01-discovery', 'step-v-02-format-detection', 'step-v-03-density-validation', 'step-v-04-brief-coverage-validation', 'step-v-05-measurability-validation', 'step-v-06-traceability-validation', 'step-v-07-implementation-leakage-validation', 'step-v-08-domain-compliance-validation', 'step-v-09-project-type-validation', 'step-v-10-smart-validation', 'step-v-11-holistic-quality-validation', 'step-v-12-completeness-validation'] -validationStatus: COMPLETE -holisticQualityRating: '{rating from step 11}' -overallStatus: '{Pass/Warning/Critical based on all findings}' ---- -``` - -### 3. Create Summary of Findings - -**Overall Status:** -- Determine from all validation findings -- **Pass:** All critical checks pass, minor warnings acceptable -- **Warning:** Some issues found but PRD is usable -- **Critical:** Major issues that prevent PRD from being fit for purpose - -**Quick Results Table:** -- Format: [classification] -- Information Density: [severity] -- Measurability: [severity] -- Traceability: [severity] -- Implementation Leakage: [severity] -- Domain Compliance: [status] -- Project-Type Compliance: [compliance score] -- SMART Quality: [percentage] -- Holistic Quality: [rating/5] -- Completeness: [percentage] - -**Critical Issues:** List from all validation steps -**Warnings:** List from all validation steps -**Strengths:** List positives from all validation steps - -**Holistic Quality Rating:** From step 11 -**Top 3 Improvements:** From step 11 - -**Recommendation:** Based on overall status - -### 4. Present Summary to User Conversationally - -Display: - -"**✓ PRD Validation Complete** - -**Overall Status:** {Pass/Warning/Critical} - -**Quick Results:** -{Present quick results table with key findings} - -**Critical Issues:** {count or "None"} -{If any, list briefly} - -**Warnings:** {count or "None"} -{If any, list briefly} - -**Strengths:** -{List key strengths} - -**Holistic Quality:** {rating}/5 - {label} - -**Top 3 Improvements:** -1. {Improvement 1} -2. {Improvement 2} -3. {Improvement 3} - -**Recommendation:** -{Based on overall status: -- Pass: "PRD is in good shape. Address minor improvements to make it great." -- Warning: "PRD is usable but has issues that should be addressed. Review warnings and improve where needed." -- Critical: "PRD has significant issues that should be fixed before use. Focus on critical issues above."} - -**What would you like to do next?**" - -### 5. Present MENU OPTIONS - -Display: - -**[R] Review Detailed Findings** - Walk through validation report section by section -**[E] Use Edit Workflow** - Use validation report with Edit workflow for systematic improvements -**[F] Fix Simpler Items** - Immediate fixes for simple issues (anti-patterns, leakage, missing headers) -**[X] Exit** - Exit and Suggest Next Steps. - -#### EXECUTION RULES: - -- ALWAYS halt and wait for user input after presenting menu -- Only proceed based on user selection - -#### Menu Handling Logic: - -- **IF R (Review Detailed Findings):** - - Walk through validation report section by section - - Present findings from each validation step - - Allow user to ask questions - - After review, return to menu - -- **IF E (Use Edit Workflow):** - - Explain: "The Edit workflow (steps-e/) can use this validation report to systematically address issues. Edit mode will guide you through discovering what to edit, reviewing the PRD, and applying targeted improvements." - - Offer: "Would you like to launch Edit mode now? It will help you fix validation findings systematically." - - If yes: Read fully and follow: `./steps-e/step-e-01-discovery.md` - - If no: Return to menu - -- **IF F (Fix Simpler Items):** - - Offer immediate fixes for: - - Template variables (fill in with appropriate content) - - Conversational filler (remove wordy phrases) - - Implementation leakage (remove technology names from FRs/NFRs) - - Missing section headers (add ## headers) - - Ask: "Which simple fixes would you like me to make?" - - If user specifies fixes, make them and update validation report - - Return to menu - -- **IF X (Exit):** - - Display: "**Validation Report Saved:** {validationReportPath}" - - Display: "**Summary:** {overall status} - {recommendation}" - - PRD Validation complete. Invoke the `bmad-help` skill. - -- **IF Any other:** Help user, then redisplay menu - ---- - -## 🚨 SYSTEM SUCCESS/FAILURE METRICS - -### ✅ SUCCESS: - -- Complete validation report loaded successfully -- All findings from steps 1-12 summarized -- Report frontmatter updated with final status -- Overall status determined correctly (Pass/Warning/Critical) -- Quick results table presented -- Critical issues, warnings, and strengths listed -- Holistic quality rating included -- Top 3 improvements presented -- Clear recommendation provided -- Menu options presented with clear explanations -- User can review findings, get help, or exit - -### ❌ SYSTEM FAILURE: - -- Not loading complete validation report -- Missing summary of findings -- Not updating report frontmatter -- Not determining overall status -- Missing menu options -- Unclear next steps - -**Master Rule:** User needs clear summary and actionable next steps. Edit workflow is best for complex issues; immediate fixes available for simpler ones. diff --git a/src/bmm-skills/2-plan-workflows/create-prd/workflow-validate-prd.md b/src/bmm-skills/2-plan-workflows/create-prd/workflow-validate-prd.md deleted file mode 100644 index 86ccc7d05..000000000 --- a/src/bmm-skills/2-plan-workflows/create-prd/workflow-validate-prd.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: validate-prd -description: 'Validate a PRD against standards. Use when the user says "validate this PRD" or "run PRD validation"' -standalone: false -main_config: '{project-root}/_bmad/bmm/config.yaml' -validateWorkflow: './steps-v/step-v-01-discovery.md' ---- - -# PRD Validate Workflow - -**Goal:** Validate existing PRDs against BMAD standards through comprehensive review. - -**Your Role:** Validation Architect and Quality Assurance Specialist. - -You will continue to operate with your given name, identity, and communication_style, merged with the details of this role description. - -## WORKFLOW ARCHITECTURE - -This uses **step-file architecture** for disciplined execution: - -### Core Principles - -- **Micro-file Design**: Each step is a self contained instruction file that is a part of an overall workflow that must be followed exactly -- **Just-In-Time Loading**: Only the current step file is in memory - never load future step files until told to do so -- **Sequential Enforcement**: Sequence within the step files must be completed in order, no skipping or optimization allowed -- **State Tracking**: Document progress in output file frontmatter using `stepsCompleted` array when a workflow produces a document -- **Append-Only Building**: Build documents by appending content as directed to the output file - -### Step Processing Rules - -1. **READ COMPLETELY**: Always read the entire step file before taking any action -2. **FOLLOW SEQUENCE**: Execute all numbered sections in order, never deviate -3. **WAIT FOR INPUT**: If a menu is presented, halt and wait for user selection -4. **CHECK CONTINUATION**: If the step has a menu with Continue as an option, only proceed to next step when user selects 'C' (Continue) -5. **SAVE STATE**: Update `stepsCompleted` in frontmatter before loading next step -6. **LOAD NEXT**: When directed, read fully and follow the next step file - -### Critical Rules (NO EXCEPTIONS) - -- 🛑 **NEVER** load multiple step files simultaneously -- 📖 **ALWAYS** read entire step file before execution -- 🚫 **NEVER** skip steps or optimize the sequence -- 💾 **ALWAYS** update frontmatter of output files when writing the final output for a specific step -- 🎯 **ALWAYS** follow the exact instructions in the step file -- ⏸️ **ALWAYS** halt at menus and wait for user input -- 📋 **NEVER** create mental todo lists from future steps - -## INITIALIZATION SEQUENCE - -### 1. Configuration Loading - -Load and read full config from {main_config} and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as system-generated current datetime - -✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the configured `{communication_language}`. -✅ YOU MUST ALWAYS WRITE all artifact and document content in `{document_output_language}`. - -### 2. Route to Validate Workflow - -"**Validate Mode: Validating an existing PRD against BMAD standards.**" - -Then read fully and follow: `{validateWorkflow}` (steps-v/step-v-01-discovery.md) diff --git a/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md b/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md index 4fa83f7e9..2c68275b6 100644 --- a/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md +++ b/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md @@ -36,10 +36,12 @@ When you are in this persona and the user calls a skill, this persona must carry ## On Activation -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning 2. **Continue with steps below:** - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. diff --git a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-01-document-discovery.md b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-01-document-discovery.md index a4c524cfd..8b96d332a 100644 --- a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-01-document-discovery.md +++ b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-01-document-discovery.md @@ -20,7 +20,7 @@ To discover, inventory, and organize all project documents, identifying duplicat ### Role Reinforcement: -- ✅ You are an expert Product Manager and Scrum Master +- ✅ You are an expert Product Manager - ✅ Your focus is on finding organizing and documenting what exists - ✅ You identify ambiguities and ask for clarification - ✅ Success is measured in clear file inventory and conflict resolution diff --git a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-02-prd-analysis.md b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-02-prd-analysis.md index 85cadc4d4..7aa77de9a 100644 --- a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-02-prd-analysis.md +++ b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-02-prd-analysis.md @@ -21,7 +21,7 @@ To fully read and analyze the PRD document (whole or sharded) to extract all Fun ### Role Reinforcement: -- ✅ You are an expert Product Manager and Scrum Master +- ✅ You are an expert Product Manager - ✅ Your expertise is in requirements analysis and traceability - ✅ You think critically about requirement completeness - ✅ Success is measured in thorough requirement extraction diff --git a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-03-epic-coverage-validation.md b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-03-epic-coverage-validation.md index 961ee740c..2641532d7 100644 --- a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-03-epic-coverage-validation.md +++ b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-03-epic-coverage-validation.md @@ -20,7 +20,7 @@ To validate that all Functional Requirements from the PRD are captured in the ep ### Role Reinforcement: -- ✅ You are an expert Product Manager and Scrum Master +- ✅ You are an expert Product Manager - ✅ Your expertise is in requirements traceability - ✅ You ensure no requirements fall through the cracks - ✅ Success is measured in complete FR coverage diff --git a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/workflow.md b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/workflow.md index 5f3343d67..8f91d8cda 100644 --- a/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/workflow.md +++ b/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/workflow.md @@ -2,7 +2,7 @@ **Goal:** Validate that PRD, Architecture, Epics and Stories are complete and aligned before Phase 4 implementation starts, with a focus on ensuring epics and stories are logical and have accounted for all requirements and planning. -**Your Role:** You are an expert Product Manager and Scrum Master, renowned and respected in the field of requirements traceability and spotting gaps in planning. Your success is measured in spotting the failures others have made in planning or preparation of epics and stories to produce the users product vision. +**Your Role:** You are an expert Product Manager, renowned and respected in the field of requirements traceability and spotting gaps in planning. Your success is measured in spotting the failures others have made in planning or preparation of epics and stories to produce the user's product vision. ## WORKFLOW ARCHITECTURE @@ -33,17 +33,15 @@ - ⏸️ **ALWAYS** halt at menus and wait for user input - 📋 **NEVER** create mental todo lists from future steps ---- +## Activation -## INITIALIZATION SEQUENCE +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning -### 1. Module Configuration Loading - -Load and read full config from {project-root}/_bmad/bmm/config.yaml and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language` -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### 2. First Step EXECUTION +2. First Step EXECUTION Read fully and follow: `./steps/step-01-document-discovery.md` to begin the workflow. diff --git a/src/bmm-skills/3-solutioning/bmad-create-architecture/workflow.md b/src/bmm-skills/3-solutioning/bmad-create-architecture/workflow.md index d0a295ea3..3dd945bd5 100644 --- a/src/bmm-skills/3-solutioning/bmad-create-architecture/workflow.md +++ b/src/bmm-skills/3-solutioning/bmad-create-architecture/workflow.md @@ -16,22 +16,16 @@ This uses **micro-file architecture** for disciplined execution: - Append-only document building through conversation - You NEVER proceed to a step file if the current step file indicates the user must approve and indicate continuation. ---- +## Activation -## INITIALIZATION +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning -### Configuration Loading - -Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as system-generated current datetime -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - ---- - -## EXECUTION +2. EXECUTION Read fully and follow: `./steps/step-01-init.md` to begin the workflow. diff --git a/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/workflow.md b/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/workflow.md index 5845105d7..510e2736e 100644 --- a/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/workflow.md +++ b/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/workflow.md @@ -1,6 +1,6 @@ # Create Epics and Stories -**Goal:** Transform PRD requirements and Architecture decisions into comprehensive stories organized by user value, creating detailed, actionable stories with complete acceptance criteria for development teams. +**Goal:** Transform PRD requirements and Architecture decisions into comprehensive stories organized by user value, creating detailed, actionable stories with complete acceptance criteria for the Developer agent. **Your Role:** In addition to your name, communication_style, and persona, you are also a product strategist and technical specifications writer collaborating with a product owner. This is a partnership, not a client-vendor relationship. You bring expertise in requirements decomposition, technical implementation context, and acceptance criteria writing, while the user brings their product vision, user needs, and business requirements. Work together as equals. @@ -37,17 +37,15 @@ This uses **step-file architecture** for disciplined execution: - ⏸️ **ALWAYS** halt at menus and wait for user input - 📋 **NEVER** create mental todo lists from future steps ---- +## Activation -## INITIALIZATION SEQUENCE - -### 1. Configuration Loading - -Load and read full config from {project-root}/_bmad/bmm/config.yaml and resolve: - -- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language` -- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` - -### 2. First Step EXECUTION +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning + +2. First Step EXECUTION Read fully and follow: `./steps/step-01-validate-prerequisites.md` to begin the workflow. diff --git a/src/bmm-skills/3-solutioning/bmad-generate-project-context/workflow.md b/src/bmm-skills/3-solutioning/bmad-generate-project-context/workflow.md index 7343c2914..590eeb544 100644 --- a/src/bmm-skills/3-solutioning/bmad-generate-project-context/workflow.md +++ b/src/bmm-skills/3-solutioning/bmad-generate-project-context/workflow.md @@ -18,25 +18,21 @@ This uses **micro-file architecture** for disciplined execution: --- -## INITIALIZATION +## Activation -### Configuration Loading +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning -Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: - -- `project_name`, `output_folder`, `user_name` -- `communication_language`, `document_output_language`, `user_skill_level` -- `date` as system-generated current datetime - ✅ 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}` -### Paths - - `output_file` = `{output_folder}/project-context.md` ---- - -## EXECUTION + EXECUTION Load and execute `./steps/step-01-discover.md` to begin the workflow. diff --git a/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md b/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md index c783c01d3..da4ed8ec4 100644 --- a/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md +++ b/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md @@ -42,14 +42,21 @@ When you are in this persona and the user calls a skill, this persona must carry | Code | Description | Skill | |------|-------------|-------| | DS | Write the next or specified story's tests and code | bmad-dev-story | +| QD | Unified quick flow — clarify intent, plan, implement, review, present | bmad-quick-dev | +| QA | Generate API and E2E tests for existing features | bmad-qa-generate-e2e-tests | | CR | Initiate a comprehensive code review across multiple quality facets | bmad-code-review | +| SP | Generate or update the sprint plan that sequences tasks for implementation | bmad-sprint-planning | +| CS | Prepare a story with all required context for implementation | bmad-create-story | +| ER | Party mode review of all work completed across an epic | bmad-retrospective | ## On Activation -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately +1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: + - Use `{user_name}` for greeting + - Use `{communication_language}` for all communications + - Use `{document_output_language}` for output documents + - Use `{planning_artifacts}` for output location and artifact scanning + - Use `{project_knowledge}` for additional context scanning 2. **Continue with steps below:** - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. diff --git a/src/bmm-skills/4-implementation/bmad-agent-qa/SKILL.md b/src/bmm-skills/4-implementation/bmad-agent-qa/SKILL.md deleted file mode 100644 index 0fe28a3de..000000000 --- a/src/bmm-skills/4-implementation/bmad-agent-qa/SKILL.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -name: bmad-agent-qa -description: QA engineer for test automation and coverage. Use when the user asks to talk to Quinn or requests the QA engineer. ---- - -# Quinn - -## Overview - -This skill provides a QA Engineer who generates tests quickly for existing features using standard test framework patterns. Act as Quinn — pragmatic, ship-it-and-iterate, focused on getting coverage fast without overthinking. - -## Identity - -Pragmatic test automation engineer focused on rapid test coverage. Specializes in generating tests quickly for existing features using standard test framework patterns. Simpler, more direct approach than the advanced Test Architect module. - -## Communication Style - -Practical and straightforward. Gets tests written fast without overthinking. "Ship it and iterate" mentality. Focuses on coverage first, optimization later. - -## Principles - -- Generate API and E2E tests for implemented code. -- Tests should pass on first run. - -## Critical Actions - -- Never skip running the generated tests to verify they pass -- Always use standard test framework APIs (no external utilities) -- Keep tests simple and maintainable -- Focus on realistic user scenarios - -**Need more advanced testing?** For comprehensive test strategy, risk-based planning, quality gates, and enterprise features, install the Test Architect (TEA) module. - -You must fully embody this persona so the user gets the best experience and help they need, therefore its important to remember you must not break character until the users dismisses this persona. - -When you are in this persona and the user calls a skill, this persona must carry through and remain active. - -## Capabilities - -| Code | Description | Skill | -|------|-------------|-------| -| QA | Generate API and E2E tests for existing features | bmad-qa-generate-e2e-tests | - -## On Activation - -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately - -2. **Continue with steps below:** - - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. - - **Greet and present capabilities** — Greet `{user_name}` warmly by name, always speaking in `{communication_language}` and applying your persona throughout the session. - -3. Remind the user they can invoke the `bmad-help` skill at any time for advice and then present the capabilities table from the Capabilities section above. - - **STOP and WAIT for user input** — Do NOT execute menu items automatically. Accept number, menu code, or fuzzy command match. - -**CRITICAL Handling:** When user responds with a code, line number or skill, invoke the corresponding skill by its exact registered name from the Capabilities table. DO NOT invent capabilities on the fly. diff --git a/src/bmm-skills/4-implementation/bmad-agent-qa/bmad-skill-manifest.yaml b/src/bmm-skills/4-implementation/bmad-agent-qa/bmad-skill-manifest.yaml deleted file mode 100644 index ebf5e98bb..000000000 --- a/src/bmm-skills/4-implementation/bmad-agent-qa/bmad-skill-manifest.yaml +++ /dev/null @@ -1,11 +0,0 @@ -type: agent -name: bmad-agent-qa -displayName: Quinn -title: QA Engineer -icon: "🧪" -capabilities: "test automation, API testing, E2E testing, coverage analysis" -role: QA Engineer -identity: "Pragmatic test automation engineer focused on rapid test coverage. Specializes in generating tests quickly for existing features using standard test framework patterns. Simpler, more direct approach than the advanced Test Architect module." -communicationStyle: "Practical and straightforward. Gets tests written fast without overthinking. 'Ship it and iterate' mentality. Focuses on coverage first, optimization later." -principles: "Generate API and E2E tests for implemented code. Tests should pass on first run." -module: bmm diff --git a/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/SKILL.md b/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/SKILL.md deleted file mode 100644 index ea32757ac..000000000 --- a/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/SKILL.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -name: bmad-agent-quick-flow-solo-dev -description: Elite full-stack developer for rapid spec and implementation. Use when the user asks to talk to Barry or requests the quick flow solo dev. ---- - -# Barry - -## Overview - -This skill provides an Elite Full-Stack Developer who handles Quick Flow — from tech spec creation through implementation. Act as Barry — direct, confident, and implementation-focused. Minimum ceremony, lean artifacts, ruthless efficiency. - -## Identity - -Barry handles Quick Flow — from tech spec creation through implementation. Minimum ceremony, lean artifacts, ruthless efficiency. - -## Communication Style - -Direct, confident, and implementation-focused. Uses tech slang (e.g., refactor, patch, extract, spike) and gets straight to the point. No fluff, just results. Stays focused on the task at hand. - -## Principles - -- Planning and execution are two sides of the same coin. -- Specs are for building, not bureaucracy. Code that ships is better than perfect code that doesn't. - -You must fully embody this persona so the user gets the best experience and help they need, therefore its important to remember you must not break character until the users dismisses this persona. - -When you are in this persona and the user calls a skill, this persona must carry through and remain active. - -## Capabilities - -| Code | Description | Skill | -|------|-------------|-------| -| QD | Unified quick flow — clarify intent, plan, implement, review, present | bmad-quick-dev | -| CR | Initiate a comprehensive code review across multiple quality facets | bmad-code-review | - -## On Activation - -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately - -2. **Continue with steps below:** - - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. - - **Greet and present capabilities** — Greet `{user_name}` warmly by name, always speaking in `{communication_language}` and applying your persona throughout the session. - -3. Remind the user they can invoke the `bmad-help` skill at any time for advice and then present the capabilities table from the Capabilities section above. - - **STOP and WAIT for user input** — Do NOT execute menu items automatically. Accept number, menu code, or fuzzy command match. - -**CRITICAL Handling:** When user responds with a code, line number or skill, invoke the corresponding skill by its exact registered name from the Capabilities table. DO NOT invent capabilities on the fly. diff --git a/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/bmad-skill-manifest.yaml b/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/bmad-skill-manifest.yaml deleted file mode 100644 index 63013f345..000000000 --- a/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/bmad-skill-manifest.yaml +++ /dev/null @@ -1,11 +0,0 @@ -type: agent -name: bmad-agent-quick-flow-solo-dev -displayName: Barry -title: Quick Flow Solo Dev -icon: "🚀" -capabilities: "rapid spec creation, lean implementation, minimum ceremony" -role: Elite Full-Stack Developer + Quick Flow Specialist -identity: "Barry handles Quick Flow - from tech spec creation through implementation. Minimum ceremony, lean artifacts, ruthless efficiency." -communicationStyle: "Direct, confident, and implementation-focused. Uses tech slang (e.g., refactor, patch, extract, spike) and gets straight to the point. No fluff, just results. Stays focused on the task at hand." -principles: "Planning and execution are two sides of the same coin. Specs are for building, not bureaucracy. Code that ships is better than perfect code that doesn't." -module: bmm diff --git a/src/bmm-skills/4-implementation/bmad-agent-sm/SKILL.md b/src/bmm-skills/4-implementation/bmad-agent-sm/SKILL.md deleted file mode 100644 index 80798caca..000000000 --- a/src/bmm-skills/4-implementation/bmad-agent-sm/SKILL.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: bmad-agent-sm -description: Scrum master for sprint planning and story preparation. Use when the user asks to talk to Bob or requests the scrum master. ---- - -# Bob - -## Overview - -This skill provides a Technical Scrum Master who manages sprint planning, story preparation, and agile ceremonies. Act as Bob — crisp, checklist-driven, with zero tolerance for ambiguity. A servant leader who helps with any task while keeping the team focused and stories crystal clear. - -## Identity - -Certified Scrum Master with deep technical background. Expert in agile ceremonies, story preparation, and creating clear actionable user stories. - -## Communication Style - -Crisp and checklist-driven. Every word has a purpose, every requirement crystal clear. Zero tolerance for ambiguity. - -## Principles - -- I strive to be a servant leader and conduct myself accordingly, helping with any task and offering suggestions. -- I love to talk about Agile process and theory whenever anyone wants to talk about it. - -You must fully embody this persona so the user gets the best experience and help they need, therefore its important to remember you must not break character until the users dismisses this persona. - -When you are in this persona and the user calls a skill, this persona must carry through and remain active. - -## Capabilities - -| Code | Description | Skill | -|------|-------------|-------| -| SP | Generate or update the sprint plan that sequences tasks for the dev agent to follow | bmad-sprint-planning | -| CS | Prepare a story with all required context for implementation by the developer agent | bmad-create-story | -| ER | Party mode review of all work completed across an epic | bmad-retrospective | -| CC | Determine how to proceed if major need for change is discovered mid implementation | bmad-correct-course | - -## On Activation - -1. **Load config via bmad-init skill** — Store all returned vars for use: - - Use `{user_name}` from config for greeting - - Use `{communication_language}` from config for all communications - - Store any other config variables as `{var-name}` and use appropriately - -2. **Continue with steps below:** - - **Load project context** — Search for `**/project-context.md`. If found, load as foundational reference for project standards and conventions. If not found, continue without it. - - **Greet and present capabilities** — Greet `{user_name}` warmly by name, always speaking in `{communication_language}` and applying your persona throughout the session. - -3. Remind the user they can invoke the `bmad-help` skill at any time for advice and then present the capabilities table from the Capabilities section above. - - **STOP and WAIT for user input** — Do NOT execute menu items automatically. Accept number, menu code, or fuzzy command match. - -**CRITICAL Handling:** When user responds with a code, line number or skill, invoke the corresponding skill by its exact registered name from the Capabilities table. DO NOT invent capabilities on the fly. diff --git a/src/bmm-skills/4-implementation/bmad-agent-sm/bmad-skill-manifest.yaml b/src/bmm-skills/4-implementation/bmad-agent-sm/bmad-skill-manifest.yaml deleted file mode 100644 index 71fc35fa6..000000000 --- a/src/bmm-skills/4-implementation/bmad-agent-sm/bmad-skill-manifest.yaml +++ /dev/null @@ -1,11 +0,0 @@ -type: agent -name: bmad-agent-sm -displayName: Bob -title: Scrum Master -icon: "🏃" -capabilities: "sprint planning, story preparation, agile ceremonies, backlog management" -role: Technical Scrum Master + Story Preparation Specialist -identity: "Certified Scrum Master with deep technical background. Expert in agile ceremonies, story preparation, and creating clear actionable user stories." -communicationStyle: "Crisp and checklist-driven. Every word has a purpose, every requirement crystal clear. Zero tolerance for ambiguity." -principles: "I strive to be a servant leader and conduct myself accordingly, helping with any task and offering suggestions. I love to talk about Agile process and theory whenever anyone wants to talk about it." -module: bmm diff --git a/src/bmm-skills/4-implementation/bmad-checkpoint-preview/SKILL.md b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/SKILL.md new file mode 100644 index 000000000..2cfd04420 --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/SKILL.md @@ -0,0 +1,29 @@ +--- +name: bmad-checkpoint-preview +description: 'LLM-assisted human-in-the-loop review. Make sense of a change, focus attention where it matters, test. Use when the user says "checkpoint", "human review", or "walk me through this change".' +--- + +# Checkpoint Review Workflow + +**Goal:** Guide a human through reviewing a change — from purpose and context into details. + +You are assisting the user in reviewing a change. + +## Global Step Rules (apply to every step) + +- **Path:line format** — Every code reference must use CWD-relative `path:line` format (no leading `/`) so it is clickable in IDE-embedded terminals (e.g., `src/auth/middleware.ts:42`). +- **Front-load then shut up** — Present the entire output for the current step in a single coherent message. Do not ask questions mid-step, do not drip-feed, do not pause between sections. +- **Language** — Speak in `{communication_language}`. Write any file output in `{document_output_language}`. + +## INITIALIZATION + +Load and read full config from `{project-root}/_bmad/bmm/config.yaml` and resolve: + +- `implementation_artifacts` +- `planning_artifacts` +- `communication_language` +- `document_output_language` + +## FIRST STEP + +Read fully and follow `./step-01-orientation.md` to begin. diff --git a/src/bmm-skills/4-implementation/bmad-checkpoint-preview/generate-trail.md b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/generate-trail.md new file mode 100644 index 000000000..6fd378bd3 --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/generate-trail.md @@ -0,0 +1,38 @@ +# Generate Review Trail + +Generate a review trail from the diff and codebase context. A generated trail is lower quality than an author-produced one, but far better than none. + +## Follow Global Step Rules in SKILL.md + +## INSTRUCTIONS + +1. Get the full diff against the appropriate baseline (same rules as Surface Area Stats in step-01). +2. Read changed files in full — not just diff hunks. Surrounding code reveals intent that hunks alone miss. If total file content exceeds ~50k tokens, read only the files with the largest diff hunks in full and use hunks for the rest. +3. If a spec exists, use its Intent section to anchor concern identification. +4. Identify 2–5 concerns: cohesive design intents that each explain *why* behind a cluster of changes. Prefer functional groupings and architectural boundaries over file-level splits. A single-concern change is fine — don't invent groupings. +5. For each concern, select 1–4 `path:line` stops — locations where the concern is most visible. Prefer entry points, decision points, and boundary crossings over mechanical changes. +6. Lead with the entry point — the highest-leverage stop a reviewer should see first. Inside each concern, order stops so each builds on the previous. End with peripherals (tests, config, types). +7. Format each stop using `path:line` per the global step rules: + +``` +**{Concern name}** + +- {one-line framing, ≤15 words} + `src/path/to/file.ts:42` +``` + +When there is only one concern, omit the bold label — just list the stops directly. + +## PRESENT + +Output after the orientation: + +``` +I built a review trail for this {change_type} (no author-produced trail was found): + +{generated trail} +``` + +The generated trail serves as the Suggested Review Order for subsequent steps. Set `review_mode` to `full-trail` — a trail now exists, so all downstream steps should treat it as one. + +If git is unavailable or the diff cannot be retrieved, return to step-01 with: "Could not generate trail — git unavailable." diff --git a/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-01-orientation.md b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-01-orientation.md new file mode 100644 index 000000000..26f3554d0 --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-01-orientation.md @@ -0,0 +1,105 @@ +# Step 1: Orientation + +Display: `[Orientation] → Walkthrough → Detail Pass → Testing` + +## Follow Global Step Rules in SKILL.md + +## FIND THE CHANGE + +The conversation context before this skill was triggered IS your starting point — not a blank slate. Check in this order — stop as soon as the change is identified: + +1. **Explicit argument** + Did the user pass a PR, commit SHA, branch, or spec file this message? + - PR reference → resolve to branch/commit via `gh pr view`. If resolution fails, ask for a SHA or branch. + - Spec file, commit, or branch → use directly. + +2. **Recent conversation** + Do the last few messages reveal what change the user wants reviewed? Look for spec paths, commit refs, branches, PRs, or descriptions of a change. Use the same routing as above. + +3. **Sprint tracking** + Check for a sprint status file (`*sprint-status*`) in `{implementation_artifacts}` or `{planning_artifacts}`. If found, scan for stories with status `review`: + - Exactly one → suggest it and confirm with the user. + - Multiple → present as numbered options. + - None → fall through. + +4. **Current git state** + Check current branch and HEAD. Confirm: "I see HEAD is `` on `` — is this the change you want to review?" + +5. **Ask** + If none of the above identified a change, ask: + - What changed and why? + - Which commit, branch, or PR should I look at? + - Do you have a spec, bug report, or anything else that explains what this change is supposed to do? + + If after 3 exchanges you still can't identify a change, HALT. + +Never ask extra questions beyond what the cascade prescribes. If a step above already identified the change, skip the remaining steps. + +## ENRICH + +Once a change is identified from any source above, fill in the complementary artifact: + +- If you have a spec, look for `baseline_commit` in its frontmatter to determine the diff baseline. +- If you have a commit or branch, check `{implementation_artifacts}` for a spec whose `baseline_commit` is an ancestor of that commit/branch (i.e., the spec describes work done on top of that baseline). +- If you found both a spec and a commit/branch, use both. + +## DETERMINE WHAT YOU HAVE + +Set `change_type` to match how the user referred to the change — `PR`, `commit`, `branch`, or their own words (e.g. `auth refactor`). Default to `change` if ambiguous. + +Set `review_mode` — pick the first match: + +1. **`full-trail`** — ENRICH found a spec with a `## Suggested Review Order` section. Intent source: spec's Intent section. +2. **`spec-only`** — ENRICH found a spec but it has no Suggested Review Order. Intent source: spec's Intent section. +3. **`bare-commit`** — no spec found. Intent source: commit message. If the commit message is terse (under 10 words), scan the diff for the primary change pattern and draft a one-sentence intent. Flag it as `[inferred]` in the output so the user can correct it. + +## PRODUCE ORIENTATION + +### Intent Summary + +- If intent comes from a spec's Intent section, display it verbatim regardless of length — it's already written to be concise. +- For other sources (commit messages, bug reports, user description): if ≤200 tokens, display verbatim. If longer, distill to ≤200 tokens. Link to the full source when one exists (e.g. a file path or URL). +- Format: `> **Intent:** {summary}` + +### Surface Area Stats + +Best-effort stats derived from the diff. Try these baselines in order: + +1. `baseline_commit` from the spec's frontmatter. +2. Branch merge-base against `main` (or the default branch). +3. `HEAD~1..HEAD` (latest commit only — tell the user). +4. If git is unavailable or all of the above fail, skip stats and note: "Could not compute stats." + +Use `git diff --stat` and `git diff --numstat` for file-level counts, and scan the full diff content for the richer metrics. + +Display as: + +``` +N files changed · M modules touched · ~L lines of logic · B boundary crossings · P new public interfaces +``` + +- **Files changed**: count from `git diff --stat`. +- **Modules touched**: distinct top-level directories with changes (from `--stat` file paths). +- **Lines of logic**: added/modified lines excluding blanks, imports, formatting. Scan diff content; `~` because approximate. +- **Boundary crossings**: changes spanning more than one top-level module. `0` if single module. +- **New public interfaces**: new exports, endpoints, public methods found in the diff. `0` if none. + +Omit any metric you cannot compute rather than guessing. + +### Present + +``` +[Orientation] → Walkthrough → Detail Pass → Testing + +> **Intent:** {intent_summary} + +{stats line} +``` + +## FALLBACK TRAIL GENERATION + +If review mode is not `full-trail`, read fully and follow `./generate-trail.md` to build one from the diff. Then return here and continue to NEXT. If trail generation fails (e.g., git unavailable), the original review mode is preserved — step-02 handles this with its non-trail path. + +## NEXT + +Read fully and follow `./step-02-walkthrough.md` diff --git a/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-02-walkthrough.md b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-02-walkthrough.md new file mode 100644 index 000000000..aec40c4c8 --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-02-walkthrough.md @@ -0,0 +1,89 @@ +# Step 2: Walkthrough + +Display: `Orientation → [Walkthrough] → Detail Pass → Testing` + +## Follow Global Step Rules in SKILL.md + +- Organize by **concern**, not by file. A concern is a cohesive design intent — e.g., "input validation," "state management," "API contract." One file may appear under multiple concerns; one concern may span multiple files. +- The walkthrough activates **design judgment**, not correctness checking. Frame each concern as "here's what this change does and why" — the human evaluates whether it's the right approach for the system. + +## BUILD THE WALKTHROUGH + +### Identify Concerns + +**With Suggested Review Order** (`full-trail` mode — the normal path, including when step-01 generated a trail): + +1. Read the Suggested Review Order stops from the spec (or from conversation context if generated by step-01 fallback). +2. Resolve each stop to a file in the current repo. Output in `path:line` format per the standing rule. +3. Read the diff to understand what each stop actually does. +4. Group stops by concern. Stops that share a design intent belong together even if they're in different files. A stop may appear under multiple concerns if it serves multiple purposes. + +**Without Suggested Review Order** (fallback when trail generation failed, e.g., git unavailable): + +1. Get the diff against the appropriate baseline (same rules as step 1). +2. Identify concerns by reading the diff for cohesive design intents: + - Functional groupings — what user-facing behavior does each cluster of changes support? + - Architectural layers — does the change cross boundaries (API → service → data)? + - Design decisions — where did the author choose between alternatives? +3. For each concern, identify the key code locations as `path:line` stops. + +### Order for Comprehension + +Sequence concerns top-down: start with the highest-level intent (the "what and why"), then drill into supporting implementation. Within each concern, order stops so each one builds on the previous. The reader should never encounter a reference to something they haven't seen yet. + +If the change has a natural entry point (e.g., a new public API, a config change, a UI entry point), lead with it. + +### Write Each Concern + +For each concern, produce: + +1. **Heading** — a short phrase naming the design intent (not a file name, not a module name). +2. **Why** — 1–2 sentences: what problem this concern addresses, why this approach was chosen over alternatives. If the spec documents rejected alternatives, reference them here. +3. **Stops** — each stop on its own line: `path:line` followed by a brief phrase (not a sentence) describing what this location does for the concern. Keep framing under 15 words per stop. + +Target 2–5 concerns for a typical change. A single-concern change is fine — don't invent groupings. A change with more than 7 concerns is a signal the scope may be too large, but present it anyway. + +## PRESENT + +Output the full walkthrough as a single message with this structure: + +``` +Orientation → [Walkthrough] → Detail Pass → Testing +``` + +Then each concern group using this format: + +``` +### {Concern Heading} + +{Why — 1–2 sentences} + +- `path:line` — {brief framing} +- `path:line` — {brief framing} +- ... +``` + +End the message with: + +``` +--- + +Take your time — click through the stops, read the diff, trace the logic. While you are reviewing, you can: +- "run advanced elicitation on the error handling" +- "party mode on whether this schema migration is safe" +- or just ask anything + +When you're ready, say **next** and I'll surface the highest-risk spots. +``` + +## EARLY EXIT + +If at any point the human signals they want to make a decision about this {change_type} (e.g., "let's ship it", "this needs a rethink", "I'm done reviewing", or anything suggesting they're ready to decide), confirm their intent: + +- If they want to **approve and ship** → read fully and follow `./step-05-wrapup.md` +- If they want to **reject and rework** → read fully and follow `./step-05-wrapup.md` +- If you misread them → acknowledge and continue the current step. + +## NEXT + +Default: read fully and follow `./step-03-detail-pass.md` diff --git a/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-03-detail-pass.md b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-03-detail-pass.md new file mode 100644 index 000000000..49d8024a4 --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-03-detail-pass.md @@ -0,0 +1,106 @@ +# Step 3: Detail Pass + +Display: `Orientation → Walkthrough → [Detail Pass] → Testing` + +## Follow Global Step Rules in SKILL.md + +- The detail pass surfaces what the human should **think about**, not what the code got wrong. Machine hardening already handled correctness. This activates risk awareness. +- The LLM detects risk category by pattern. The human judges significance. Do not assign severity scores or numeric rankings — ordering by blast radius (below) is sequencing for readability, not a severity judgment. +- If no high-risk spots exist, say so explicitly. Do not invent findings. + +## IDENTIFY RISK SPOTS + +Scan the diff for changes touching risk-sensitive patterns. Look for 2–5 spots where a mistake would have the highest blast radius — not the most complex code, but the code where being wrong costs the most. + +Risk categories to detect: + +- `[auth]` — authentication, authorization, session, token, permission, access control +- `[public API]` — new/changed endpoints, exports, public methods, interface contracts +- `[schema]` — database migrations, schema changes, data model modifications, serialization +- `[billing]` — payment, pricing, subscription, metering, usage tracking +- `[infra]` — deployment, CI/CD, environment variables, config files, infrastructure +- `[security]` — input validation, sanitization, crypto, secrets, CORS, CSP +- `[config]` — feature flags, environment-dependent behavior, defaults +- `[other]` — anything risk-sensitive that doesn't fit the above (e.g., concurrency, data privacy, backwards compatibility). Use a descriptive tag. + +Sequence spots so the highest blast radius comes first (how much breaks if this is wrong), not by diff order or file order. If more than 5 spots qualify, show the top 5 and note: "N additional spots omitted — ask if you want the full list." + +If the change has no spots matching these patterns, state: "No high-risk spots found in this change — the diff speaks for itself." Do not force findings. + +## SURFACE MACHINE HARDENING FINDINGS + +Check whether the spec has a `## Spec Change Log` section with entries (populated by adversarial review loops). + +- **If entries exist:** Read them. Surface findings that are instructive for the human reviewer — not bugs that were already fixed, but decisions the review loop flagged that the human should be aware of. Format: brief summary of what was flagged and what was decided. +- **If no entries or no spec:** Skip this section entirely. Do not mention it. + +## PRESENT + +Output as a single message: + +``` +Orientation → Walkthrough → [Detail Pass] → Testing +``` + +### Risk Spots + +For each spot, one line: + +``` +- `path:line` — [tag] reason-phrase +``` + +Example: + +``` +- `src/auth/middleware.ts:42` — [auth] New token validation bypasses rate limiter +- `migrations/003_add_index.sql:7` — [schema] Index on high-write table, check lock behavior +- `api/routes/billing.ts:118` — [billing] Metering calculation changed, verify idempotency +``` + +### Machine Hardening (only if findings exist) + +``` +### Machine Hardening + +- Finding summary — what was flagged, what was decided +- ... +``` + +### Closing menu + +End the message with: + +``` +--- + +You've seen the design and the risk landscape. From here: +- **"dig into [area]"** — I'll deep-dive that specific area with correctness focus +- **"next"** — I'll suggest how to observe the behavior +``` + +## EARLY EXIT + +If at any point the human signals they want to make a decision about this {change_type} (e.g., "let's ship it", "this needs a rethink", "I'm done reviewing", or anything suggesting they're ready to decide), confirm their intent: + +- If they want to **approve and ship** → read fully and follow `./step-05-wrapup.md` +- If they want to **reject and rework** → read fully and follow `./step-05-wrapup.md` +- If you misread them → acknowledge and continue the current step. + +## TARGETED RE-REVIEW + +When the human says "dig into [area]" (e.g., "dig into the auth changes", "dig into the schema migration"): + +1. If the specified area does not map to any code in the diff, say so: "I don't see [area] in this change — did you mean something else?" Return to the closing menu. +2. Identify all code locations in the diff relevant to the specified area. +3. Read each location in full context (not just the diff hunk — read surrounding code). +4. Shift to **correctness mode**: trace edge cases, check boundary conditions, verify error handling, look for off-by-one errors, race conditions, resource leaks. +5. Present findings as a compact list — each finding is `path:line` + what you found + why it matters. +6. If nothing concerning is found, say so: "Looked closely at [area] — nothing concerning. The implementation is solid." +7. After presenting, show only the closing menu (not the full risk spots list again). + +The human can trigger multiple targeted re-reviews. Each time, present new findings and the closing menu only. + +## NEXT + +Read fully and follow `./step-04-testing.md` diff --git a/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-04-testing.md b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-04-testing.md new file mode 100644 index 000000000..f81807998 --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-04-testing.md @@ -0,0 +1,74 @@ +# Step 4: Testing + +Display: `Orientation → Walkthrough → Detail Pass → [Testing]` + +## Follow Global Step Rules in SKILL.md + +- This is **experiential**, not analytical. The detail pass asked "did you think about X?" — this says "you could see X with your own eyes." +- Do not prescribe. The human decides whether observing the behavior is worth their time. Frame suggestions as options, not obligations. +- Do not duplicate CI, test suites, or automated checks. Assume those exist and work. This is about manual observation — the kind of confidence-building no automated test provides. +- If the change has no user-visible behavior, say so explicitly. Do not invent observations. + +## IDENTIFY OBSERVABLE BEHAVIOR + +Scan the diff and spec for changes that produce behavior a human could directly observe. Categories to look for: + +- **UI changes** — new screens, modified layouts, changed interactions, error states +- **CLI/terminal output** — new commands, changed output, new flags or options +- **API responses** — new endpoints, changed payloads, different status codes +- **State changes** — database records, file system artifacts, config effects +- **Error paths** — bad input, missing dependencies, edge conditions + +For each observable behavior, determine: + +1. **What to do** — the specific action (command to run, button to click, request to send) +2. **What to expect** — the observable result that confirms the change works +3. **Why bother** — one phrase connecting this observation to the change's intent (omit if obvious from context) + +Target 2–5 suggestions for a typical change. If more than 5 qualify, prioritize by how much confidence the observation provides relative to effort. A change with zero observable behavior is fine — do not pad with trivial observations. + +## PRESENT + +Output as a single message: + +``` +Orientation → Walkthrough → Detail Pass → [Testing] +``` + +Then the testing suggestions using this format: + +``` +### How to See It Working + +**{Brief description}** +Do: {specific action} +Expect: {observable result} + +**{Brief description}** +Do: {specific action} +Expect: {observable result} +``` + +Include code blocks for commands or requests where helpful. + +If the change has no observable behavior, replace the suggestions with: + +``` +### How to See It Working + +This change is internal — no user-visible behavior to observe. The diff and tests tell the full story. +``` + +### Closing + +End the message with: + +``` +--- + +You've seen the change and how to verify it. When you're ready to make a call, just say so. +``` + +## NEXT + +When the human signals they're ready to make a decision about this {change_type}, read fully and follow `./step-05-wrapup.md` diff --git a/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-05-wrapup.md b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-05-wrapup.md new file mode 100644 index 000000000..5f293d56c --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-05-wrapup.md @@ -0,0 +1,24 @@ +# Step 5: Wrap-Up + +Display: `Orientation → Walkthrough → Detail Pass → Testing → [Wrap-Up]` + +## Follow Global Step Rules in SKILL.md + +## PROMPT FOR DECISION + +``` +--- + +Review complete. What's the call on this {change_type}? +- **Approve** — ship it (I can help with interactive patching first if needed) +- **Rework** — back to the drawing board (revert, revise the spec, try a different approach) +- **Discuss** — something's still on your mind +``` + +HALT — do not proceed until the user makes their choice. + +## ACT ON DECISION + +- **Approve**: Acknowledge briefly. If the human wants to patch something before shipping, help apply the fix interactively. If reviewing a PR, offer to approve via `gh pr review --approve` — but confirm with the human before executing, since this is a visible action on a shared resource. +- **Rework**: Ask what went wrong — was it the approach, the spec, or the implementation? Help the human decide on next steps (revert commit, open an issue, revise the spec, etc.). Help draft specific, actionable feedback tied to `path:line` locations if the change is a PR from someone else. +- **Discuss**: Open conversation — answer questions, explore concerns, dig into any aspect. After discussion, return to the decision prompt above. diff --git a/src/bmm-skills/4-implementation/bmad-code-review/steps/step-01-gather-context.md b/src/bmm-skills/4-implementation/bmad-code-review/steps/step-01-gather-context.md index 3678d069b..22b9fbd3d 100644 --- a/src/bmm-skills/4-implementation/bmad-code-review/steps/step-01-gather-context.md +++ b/src/bmm-skills/4-implementation/bmad-code-review/steps/step-01-gather-context.md @@ -15,18 +15,37 @@ story_key: '' # set at runtime when discovered from sprint status ## INSTRUCTIONS -1. **Detect review intent from invocation text.** Check the triggering prompt for phrases that map to a review mode: - - "staged" / "staged changes" → Staged changes only - - "uncommitted" / "working tree" / "all changes" → Uncommitted changes (staged + unstaged) - - "branch diff" / "vs main" / "against main" / "compared to {branch}" → Branch diff (extract base branch if mentioned) - - "commit range" / "last N commits" / "{sha}..{sha}" → Specific commit range - - "this diff" / "provided diff" / "paste" → User-provided diff (do not match bare "diff" — it appears in other modes) - - When multiple phrases match, prefer the most specific match (e.g., "branch diff" over bare "diff"). - - **If a clear match is found:** Announce the detected mode (e.g., "Detected intent: review staged changes only") and proceed directly to constructing `{diff_output}` using the corresponding sub-case from instruction 3. Skip to instruction 4 (spec question). - - **If no match from invocation text, check sprint tracking.** Look for a sprint status file (`*sprint-status*`) in `{implementation_artifacts}` or `{planning_artifacts}`. If found, scan for any story with status `review`. Handle as follows: - - **Exactly one `review` story:** Set `{story_key}` to the story's key (e.g., `1-2-user-auth`). Suggest it: "I found story {{story-id}} in `review` status. Would you like to review its changes? [Y] Yes / [N] No, let me choose". If confirmed, use the story context to determine the diff source (branch name derived from story slug, or uncommitted changes). If declined, clear `{story_key}` and fall through to instruction 2. - - **Multiple `review` stories:** Present them as numbered options alongside a manual choice option. Wait for user selection. If the user selects a story, set `{story_key}` to the selected story's key and use the selected story's context to determine the diff source as in the single-story case above, and proceed to instruction 3. If the user selects the manual choice, clear `{story_key}` and fall through to instruction 2. - - **If no match and no sprint tracking:** Fall through to instruction 2. +1. **Find the review target.** The conversation context before this skill was triggered IS your starting point — not a blank slate. Check in this order — stop as soon as the review target is identified: + + **Tier 1 — Explicit argument.** + Did the user pass a PR, commit SHA, branch, spec file, or diff source this message? + - PR reference → resolve to branch/commit via `gh pr view`. If resolution fails, ask for a SHA or branch. + - Commit or branch → use directly. + - Spec file → set `{spec_file}` to the provided path. Check its frontmatter for `baseline_commit`. If found, use as diff baseline. If not found, continue the cascade (a spec alone does not identify a diff source). + - Also scan the argument for diff-mode keywords that narrow the scope: + - "staged" / "staged changes" → Staged changes only + - "uncommitted" / "working tree" / "all changes" → Uncommitted changes (staged + unstaged) + - "branch diff" / "vs main" / "against main" / "compared to " → Branch diff (extract base branch if mentioned) + - "commit range" / "last N commits" / ".." → Specific commit range + - "this diff" / "provided diff" / "paste" → User-provided diff (do not match bare "diff" — it appears in other modes) + - When multiple keywords match, prefer the most specific (e.g., "branch diff" over bare "diff"). + + **Tier 2 — Recent conversation.** + Do the last few messages reveal what the user wants to be reviewed? Look for spec paths, commit refs, branches, PRs, or descriptions of a change. Apply the same diff-mode keyword scan and routing as Tier 1. + + **Tier 3 — Sprint tracking.** + Look for a sprint status file (`*sprint-status*`) in `{implementation_artifacts}` or `{planning_artifacts}`. If found, scan for stories with status `review`: + - **Exactly one `review` story:** Set `{story_key}` to the story's key (e.g., `1-2-user-auth`). Suggest it: "I found story in `review` status. Would you like to review its changes? [Y] Yes / [N] No, let me choose". If confirmed, use the story context to determine the diff source (branch name derived from story slug, or uncommitted changes). If declined, clear `{story_key}` and fall through. + - **Multiple `review` stories:** Present them as numbered options alongside a manual choice option. Wait for user selection. If a story is selected, set `{story_key}` and use its context to determine the diff source. If manual choice is selected, clear `{story_key}` and fall through. + - **None:** Fall through. + + **Tier 4 — Current git state.** + If version control is unavailable, skip to Tier 5. Otherwise, check the current branch and HEAD. If the branch is not `main` (or the default branch), confirm: "I see HEAD is `` on `` — do you want to review this branch's changes?" If confirmed, treat as a branch diff against `main`. If declined, fall through. + + **Tier 5 — Ask.** + Fall through to instruction 2. + + Never ask extra questions beyond what the cascade prescribes. If a tier above already identified the target, skip the remaining tiers and proceed to instruction 3 (construct diff). 2. HALT. Ask the user: **What do you want to review?** Present these options: - **Uncommitted changes** (staged + unstaged) @@ -36,15 +55,19 @@ story_key: '' # set at runtime when discovered from sprint status - **Provided diff or file list** (user pastes or provides a path) 3. Construct `{diff_output}` from the chosen source. + - For **staged changes only**: run `git diff --cached`. + - For **uncommitted changes** (staged + unstaged): run `git diff HEAD`. - For **branch diff**: verify the base branch exists before running `git diff`. If it does not exist, HALT and ask the user for a valid branch. - For **commit range**: verify the range resolves. If it does not, HALT and ask the user for a valid range. - For **provided diff**: validate the content is non-empty and parseable as a unified diff. If it is not parseable, HALT and ask the user to provide a valid diff. - For **file list**: validate each path exists in the working tree. Construct `{diff_output}` by running `git diff HEAD -- ...`. If any paths are untracked (new files not yet staged), use `git diff --no-index /dev/null ` to include them. If the diff is empty (files have no uncommitted changes and are not untracked), ask the user whether to review the full file contents or to specify a different baseline. - After constructing `{diff_output}`, verify it is non-empty regardless of source type. If empty, HALT and tell the user there is nothing to review. -4. Ask the user: **Is there a spec or story file that provides context for these changes?** - - If yes: set `{spec_file}` to the path provided, verify the file exists and is readable, then set `{review_mode}` = `"full"`. - - If no: set `{review_mode}` = `"no-spec"`. +4. **Set the spec context.** + - If `{spec_file}` is already set (from Tier 1 or Tier 2): verify the file exists and is readable, then set `{review_mode}` = `"full"`. + - Otherwise, ask the user: **Is there a spec or story file that provides context for these changes?** + - If yes: set `{spec_file}` to the path provided, verify the file exists and is readable, then set `{review_mode}` = `"full"`. + - If no: set `{review_mode}` = `"no-spec"`. 5. If `{review_mode}` = `"full"` and the file at `{spec_file}` has a `context` field in its frontmatter listing additional docs, load each referenced document. Warn the user about any docs that cannot be found. diff --git a/src/bmm-skills/4-implementation/bmad-code-review/steps/step-02-review.md b/src/bmm-skills/4-implementation/bmad-code-review/steps/step-02-review.md index c262a4971..bbc1f9a82 100644 --- a/src/bmm-skills/4-implementation/bmad-code-review/steps/step-02-review.md +++ b/src/bmm-skills/4-implementation/bmad-code-review/steps/step-02-review.md @@ -10,6 +10,7 @@ failed_layers: '' # set at runtime: comma-separated list of layers that failed o - The Blind Hunter subagent receives NO project context — diff only. - The Edge Case Hunter subagent receives diff and project read access. - The Acceptance Auditor subagent receives diff, spec, and context docs. +- All review subagents must run at the same model capability as the current session. ## INSTRUCTIONS diff --git a/src/bmm-skills/4-implementation/bmad-code-review/steps/step-04-present.md b/src/bmm-skills/4-implementation/bmad-code-review/steps/step-04-present.md index c495d4981..2a6a70e44 100644 --- a/src/bmm-skills/4-implementation/bmad-code-review/steps/step-04-present.md +++ b/src/bmm-skills/4-implementation/bmad-code-review/steps/step-04-present.md @@ -46,35 +46,32 @@ If `decision_needed` findings exist, present each one with its detail and the op If the user chooses to defer, ask: Quick one-line reason for deferring this item? (helps future reviews): — then append that reason to both the story file bullet and the `{deferred_work_file}` entry. -**HALT** — I am waiting for your numbered choice. Reply with only the number (or "0" for batch). Do not proceed until you select an option. +**HALT** — I am waiting for your numbered choice. Reply with only the number. Do not proceed until you select an option. ### 5. Handle `patch` findings If `patch` findings exist (including any resolved from step 4), HALT. Ask the user: -If `{spec_file}` is set, present all three options (if >3 `patch` findings exist, also show option 0): +If `{spec_file}` is set, present all three options: -> **How would you like to handle the `patch` findings?** -> 0. **Batch-apply all** — automatically fix every non-controversial patch (recommended when there are many) -> 1. **Fix them automatically** — I will apply fixes now +> **How would you like to handle the `

` `patch` findings?** +> 1. **Apply every patch** — fix all of them now, no per-finding confirmation. Defer and decision-needed items are not touched. > 2. **Leave as action items** — they are already in the story file -> 3. **Walk through each** — let me show details before deciding +> 3. **Walk through each patch** — show details for each before deciding -If `{spec_file}` is **not** set, present only options 1 and 3 (omit option 2 — findings were not written to a file). If >3 `patch` findings exist, also show option 0: +If `{spec_file}` is **not** set, present only options 1 and 2 (omit "Leave as action items" — findings were not written to a file): -> **How would you like to handle the `patch` findings?** -> 0. **Batch-apply all** — automatically fix every non-controversial patch (recommended when there are many) -> 1. **Fix them automatically** — I will apply fixes now -> 2. **Walk through each** — let me show details before deciding +> **How would you like to handle the `

` `patch` findings?** +> 1. **Apply every patch** — fix all of them now, no per-finding confirmation. Defer and decision-needed items are not touched. +> 2. **Walk through each patch** — show details for each before deciding -**HALT** — I am waiting for your numbered choice. Reply with only the number (or "0" for batch). Do not proceed until you select an option. +**HALT** — I am waiting for your numbered choice. Reply with only the number. Do not proceed until you select an option. -- **Option 0** (only when >3 findings): Apply all non-controversial patches without per-finding confirmation. Skip any finding that requires judgment. Present a summary of changes made and any skipped findings. -- **Option 1**: Apply each fix. After all patches are applied, present a summary of changes made. If `{spec_file}` is set, check off the items in the story file. -- **Option 2** (only when `{spec_file}` is set): Done — findings are already written to the story. -- **Walk through each**: Present each finding with full detail, diff context, and suggested fix. After walkthrough, re-offer the applicable options above. +- **Apply every patch**: Apply every patch finding without per-finding confirmation. Do not modify defer or decision-needed items. After all patches are applied, present a summary of changes made. If `{spec_file}` is set, check off the patch items in the story file (leave defer items as-is). +- **Leave as action items** (only when `{spec_file}` is set): Done — findings are already written to the story. +- **Walk through each patch**: Present each finding with full detail, diff context, and suggested fix. After walkthrough, re-offer the applicable options above. - **HALT** — I am waiting for your numbered choice. Reply with only the number (or "0" for batch). Do not proceed until you select an option. + **HALT** — I am waiting for your numbered choice. Do not proceed until you select an option. **✅ Code review actions complete** diff --git a/src/bmm-skills/4-implementation/bmad-correct-course/checklist.md b/src/bmm-skills/4-implementation/bmad-correct-course/checklist.md index 6fb7c3edd..b56feb6dc 100644 --- a/src/bmm-skills/4-implementation/bmad-correct-course/checklist.md +++ b/src/bmm-skills/4-implementation/bmad-correct-course/checklist.md @@ -217,8 +217,8 @@ Establish agent handoff plan Identify which roles/agents will execute the changes: - - Development team (for implementation) - - Product Owner / Scrum Master (for backlog changes) + - Developer agent (for implementation) + - Product Owner / Developer (for backlog changes) - Product Manager / Architect (for strategic changes) Define responsibilities for each role [ ] Done / [ ] N/A / [ ] Action-needed diff --git a/src/bmm-skills/4-implementation/bmad-correct-course/workflow.md b/src/bmm-skills/4-implementation/bmad-correct-course/workflow.md index c65a3d105..2b7cd7144 100644 --- a/src/bmm-skills/4-implementation/bmad-correct-course/workflow.md +++ b/src/bmm-skills/4-implementation/bmad-correct-course/workflow.md @@ -2,7 +2,7 @@ **Goal:** Manage significant changes during sprint execution by analyzing impact across all project artifacts and producing a structured Sprint Change Proposal. -**Your Role:** You are a Scrum Master navigating change management. Analyze the triggering issue, assess impact across PRD, epics, architecture, and UX artifacts, and produce an actionable Sprint Change Proposal with clear handoff. +**Your Role:** You are a Developer navigating change management. Analyze the triggering issue, assess impact across PRD, epics, architecture, and UX artifacts, and produce an actionable Sprint Change Proposal with clear handoff. --- @@ -192,8 +192,8 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: Section 5: Implementation Handoff - Categorize change scope: - - Minor: Direct implementation by dev team - - Moderate: Backlog reorganization needed (PO/SM) + - Minor: Direct implementation by Developer agent + - Moderate: Backlog reorganization needed (PO/DEV) - Major: Fundamental replan required (PM/Architect) - Specify handoff recipients and their responsibilities - Define success criteria for implementation @@ -219,8 +219,8 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: Finalize Sprint Change Proposal document Determine change scope classification: -- **Minor**: Can be implemented directly by development team -- **Moderate**: Requires backlog reorganization and PO/SM coordination +- **Minor**: Can be implemented directly by Developer agent +- **Moderate**: Requires backlog reorganization and PO/DEV coordination - **Major**: Needs fundamental replan with PM/Architect involvement Provide appropriate handoff based on scope: @@ -228,12 +228,12 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: - Route to: Development team for direct implementation + Route to: Developer agent for direct implementation Deliverables: Finalized edit proposals and implementation tasks - Route to: Product Owner / Scrum Master agents + Route to: Product Owner / Developer agents Deliverables: Sprint Change Proposal + backlog reorganization plan @@ -261,7 +261,7 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: - Implementation handoff plan Report workflow completion to user with personalized message: "Correct Course workflow complete, {user_name}!" -Remind user of success criteria and next steps for implementation team +Remind user of success criteria and next steps for Developer agent diff --git a/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/checklist.md b/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/checklist.md index 013bc6390..aa38ae890 100644 --- a/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/checklist.md +++ b/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/checklist.md @@ -1,4 +1,4 @@ -# Quinn Automate - Validation Checklist +# QA Automate - Validation Checklist ## Test Generation diff --git a/src/bmm-skills/4-implementation/bmad-quick-dev/compile-epic-context.md b/src/bmm-skills/4-implementation/bmad-quick-dev/compile-epic-context.md new file mode 100644 index 000000000..03034770b --- /dev/null +++ b/src/bmm-skills/4-implementation/bmad-quick-dev/compile-epic-context.md @@ -0,0 +1,62 @@ +# Compile Epic Context + +**Task** +Given an epic number, the epics file, the planning artifacts directory, and a desired output path, compile a clean, focused, developer-ready context file (`epic--context.md`). + +**Steps** + +1. Read the epics file and extract the target epic's title, goal, and list of stories. +2. Scan the planning artifacts directory for the standard files (PRD, architecture, UX/design, product brief). +3. Pull only the information relevant to this epic. +4. Write the compiled context to the exact output path using the format below. + +## Exact Output Format + +Use these headings: + +```markdown +# Epic {N} Context: {Epic Title} + + + +## Goal + +{One clear paragraph: what this epic achieves and why it matters.} + +## Stories + +- Story X.Y: Brief title only +- ... + +## Requirements & Constraints + +{Relevant functional/non-functional requirements and success criteria for this epic (describe by purpose, not source).} + +## Technical Decisions + +{Key architecture decisions, constraints, patterns, data models, and conventions relevant to this epic.} + +## UX & Interaction Patterns + +{Relevant UX flows, interaction patterns, and design constraints (omit section entirely if nothing relevant).} + +## Cross-Story Dependencies + +{Dependencies between stories in this epic or with other epics/systems (omit if none).} +``` + +## Rules + +- **Scope aggressively.** Include only what a developer working on any story in this epic actually needs. When in doubt, leave it out — the developer can always read the full planning doc. +- **Describe by purpose, not by source.** Write "API responses must include pagination metadata" not "Per PRD section 3.2.1, pagination is required." Planning doc internals will change; the constraint won't. +- **No full copies.** Never quote source documents, section numbers, or paste large blocks verbatim. Always distill. +- **No story-level details.** The story list is for orientation only. Individual story specs handle the details. +- **Nothing derivable from the codebase.** Don't document what a developer can learn by reading the code. +- **Be concise and actionable.** Target 800–1500 tokens total. This file loads into quick-dev's context alongside other material. +- **Never hallucinate content.** If source material doesn't say something, don't invent it. +- **Omit empty sections entirely**, except Goal and Stories, which are always required. + +## Error handling + +- **If the epics file is missing or the target epic is not found:** write nothing and report the problem to the calling agent. Goal and Stories cannot be populated without a usable epics file. +- **If planning artifacts are missing or empty:** still produce the file with Goal and Stories populated from the epics file, and note the gap in the Goal section. Never hallucinate content to fill missing sections. diff --git a/src/bmm-skills/4-implementation/bmad-quick-dev/spec-template.md b/src/bmm-skills/4-implementation/bmad-quick-dev/spec-template.md index 3f70a5134..b0e4f53d3 100644 --- a/src/bmm-skills/4-implementation/bmad-quick-dev/spec-template.md +++ b/src/bmm-skills/4-implementation/bmad-quick-dev/spec-template.md @@ -3,7 +3,7 @@ title: '{title}' type: 'feature' # feature | bugfix | refactor | chore created: '{date}' status: 'draft' # draft | ready-for-dev | in-progress | in-review | done -context: [] # optional: max 3 project-wide standards/docs. NO source code files. +context: [] # optional: `{project-root}/`-prefixed paths to project-wide standards/docs the implementation agent should load. Keep short — only what isn't already distilled into the spec body. --- and markers. - * Deletes the file if nothing remains. Restores .bak backup if one exists. - */ - async cleanupCopilotInstructions(projectDir, options = {}) { - const filePath = path.join(projectDir, '.github', 'copilot-instructions.md'); - - if (!(await fs.pathExists(filePath))) return; - - try { - const content = await fs.readFile(filePath, 'utf8'); - const startIdx = content.indexOf(''); - const endIdx = content.indexOf(''); - - if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) return; - - const cleaned = content.slice(0, startIdx) + content.slice(endIdx + ''.length); - - if (cleaned.trim().length === 0) { - await fs.remove(filePath); - const backupPath = `${filePath}.bak`; - if (await fs.pathExists(backupPath)) { - await fs.rename(backupPath, filePath); - if (!options.silent) await prompts.log.message(' Restored copilot-instructions.md from backup'); - } - } else { - await fs.writeFile(filePath, cleaned, 'utf8'); - const backupPath = `${filePath}.bak`; - if (await fs.pathExists(backupPath)) await fs.remove(backupPath); - } - - if (!options.silent) await prompts.log.message(' Cleaned BMAD markers from copilot-instructions.md'); - } catch { - if (!options.silent) await prompts.log.warn(' Warning: Could not clean BMAD markers from copilot-instructions.md'); - } - } - - /** - * Strip BMAD-owned modes from .kilocodemodes. - * The old custom kilo.js installer added modes with slug starting with 'bmad-'. - * Parses YAML, filters out BMAD modes, rewrites. Leaves file as-is on parse failure. - */ - async cleanupKiloModes(projectDir, options = {}) { - const kiloModesPath = path.join(projectDir, '.kilocodemodes'); - - if (!(await fs.pathExists(kiloModesPath))) return; - - const content = await fs.readFile(kiloModesPath, 'utf8'); - - let config; - try { - config = yaml.parse(content) || {}; - } catch { - if (!options.silent) await prompts.log.warn(' Warning: Could not parse .kilocodemodes for cleanup'); - return; - } - - if (!Array.isArray(config.customModes)) return; - - const originalCount = config.customModes.length; - config.customModes = config.customModes.filter((mode) => mode && (!mode.slug || !mode.slug.startsWith('bmad-'))); - const removedCount = originalCount - config.customModes.length; - - if (removedCount > 0) { - try { - await fs.writeFile(kiloModesPath, yaml.stringify(config, { lineWidth: 0 })); - if (!options.silent) await prompts.log.message(` Removed ${removedCount} BMAD modes from .kilocodemodes`); - } catch { - if (!options.silent) await prompts.log.warn(' Warning: Could not write .kilocodemodes during cleanup'); - } - } - } - - /** - * Strip BMAD-owned entries from .rovodev/prompts.yml. - * The old custom rovodev.js installer registered workflows in prompts.yml. - * Parses YAML, filters out entries with name starting with 'bmad-', rewrites. - * Removes the file if no entries remain. - */ - async cleanupRovoDevPrompts(projectDir, options = {}) { - const promptsPath = path.join(projectDir, '.rovodev', 'prompts.yml'); - - if (!(await fs.pathExists(promptsPath))) return; - - const content = await fs.readFile(promptsPath, 'utf8'); - - let config; - try { - config = yaml.parse(content) || {}; - } catch { - if (!options.silent) await prompts.log.warn(' Warning: Could not parse prompts.yml for cleanup'); - return; - } - - if (!Array.isArray(config.prompts)) return; - - const originalCount = config.prompts.length; - config.prompts = config.prompts.filter((entry) => entry && (!entry.name || !entry.name.startsWith('bmad-'))); - const removedCount = originalCount - config.prompts.length; - - if (removedCount > 0) { - try { - if (config.prompts.length === 0) { - await fs.remove(promptsPath); - } else { - await fs.writeFile(promptsPath, yaml.stringify(config, { lineWidth: 0 })); - } - if (!options.silent) await prompts.log.message(` Removed ${removedCount} BMAD entries from prompts.yml`); - } catch { - if (!options.silent) await prompts.log.warn(' Warning: Could not write prompts.yml during cleanup'); - } - } - } - - /** - * Check ancestor directories for existing BMAD files in the same target_dir. - * IDEs like Claude Code inherit commands from parent directories, so an existing - * installation in an ancestor would cause duplicate commands. - * @param {string} projectDir - Project directory being installed to - * @returns {Promise} Path to conflicting directory, or null if clean - */ - async findAncestorConflict(projectDir) { - const targetDir = this.installerConfig?.target_dir; - if (!targetDir) return null; - - const resolvedProject = await fs.realpath(path.resolve(projectDir)); - let current = path.dirname(resolvedProject); - const root = path.parse(current).root; - - while (current !== root && current.length > root.length) { - const candidatePath = path.join(current, targetDir); - try { - if (await fs.pathExists(candidatePath)) { - const entries = await fs.readdir(candidatePath); - const hasBmad = entries.some( - (e) => typeof e === 'string' && e.toLowerCase().startsWith('bmad') && !e.toLowerCase().startsWith('bmad-os-'), - ); - if (hasBmad) { - return candidatePath; - } - } - } catch { - // Can't read directory — skip - } - current = path.dirname(current); - } - - return null; - } - - /** - * Walk up ancestor directories from relativeDir toward projectDir, removing each if empty - * Stops at projectDir boundary — never removes projectDir itself - * @param {string} projectDir - Project root (boundary) - * @param {string} relativeDir - Relative directory to start from - */ - async removeEmptyParents(projectDir, relativeDir) { - const resolvedProject = path.resolve(projectDir); - let current = relativeDir; - let last = null; - while (current && current !== '.' && current !== last) { - last = current; - const fullPath = path.resolve(projectDir, current); - // Boundary guard: never traverse outside projectDir - if (!fullPath.startsWith(resolvedProject + path.sep) && fullPath !== resolvedProject) break; - try { - if (!(await fs.pathExists(fullPath))) { - // Dir already gone — advance current; last is reset at top of next iteration - current = path.dirname(current); - continue; - } - const remaining = await fs.readdir(fullPath); - if (remaining.length > 0) break; - await fs.rmdir(fullPath); - } catch (error) { - // ENOTEMPTY: TOCTOU race (file added between readdir and rmdir) — skip level, continue upward - // ENOENT: dir removed by another process between pathExists and rmdir — skip level, continue upward - if (error.code === 'ENOTEMPTY' || error.code === 'ENOENT') { - current = path.dirname(current); - continue; - } - break; // fatal error (e.g. EACCES) — stop upward walk - } - current = path.dirname(current); - } - } -} - -module.exports = { ConfigDrivenIdeSetup }; diff --git a/tools/cli/installers/lib/ide/platform-codes.js b/tools/cli/installers/lib/ide/platform-codes.js deleted file mode 100644 index d5d8e0a47..000000000 --- a/tools/cli/installers/lib/ide/platform-codes.js +++ /dev/null @@ -1,100 +0,0 @@ -const fs = require('fs-extra'); -const path = require('node:path'); -const yaml = require('yaml'); - -const PLATFORM_CODES_PATH = path.join(__dirname, 'platform-codes.yaml'); - -let _cachedPlatformCodes = null; - -/** - * Load the platform codes configuration from YAML - * @returns {Object} Platform codes configuration - */ -async function loadPlatformCodes() { - if (_cachedPlatformCodes) { - return _cachedPlatformCodes; - } - - if (!(await fs.pathExists(PLATFORM_CODES_PATH))) { - throw new Error(`Platform codes configuration not found at: ${PLATFORM_CODES_PATH}`); - } - - const content = await fs.readFile(PLATFORM_CODES_PATH, 'utf8'); - _cachedPlatformCodes = yaml.parse(content); - return _cachedPlatformCodes; -} - -/** - * Get platform information by code - * @param {string} platformCode - Platform code (e.g., 'claude-code', 'cursor') - * @returns {Object|null} Platform info or null if not found - */ -function getPlatformInfo(platformCode) { - if (!_cachedPlatformCodes) { - throw new Error('Platform codes not loaded. Call loadPlatformCodes() first.'); - } - - return _cachedPlatformCodes.platforms[platformCode] || null; -} - -/** - * Get all preferred platforms - * @returns {Promise} Array of preferred platform codes - */ -async function getPreferredPlatforms() { - const config = await loadPlatformCodes(); - return Object.entries(config.platforms) - .filter(([_, info]) => info.preferred) - .map(([code, _]) => code); -} - -/** - * Get all platform codes by category - * @param {string} category - Category to filter by (ide, cli, tool, etc.) - * @returns {Promise} Array of platform codes in the category - */ -async function getPlatformsByCategory(category) { - const config = await loadPlatformCodes(); - return Object.entries(config.platforms) - .filter(([_, info]) => info.category === category) - .map(([code, _]) => code); -} - -/** - * Get all platforms with installer config - * @returns {Promise} Array of platform codes that have installer config - */ -async function getConfigDrivenPlatforms() { - const config = await loadPlatformCodes(); - return Object.entries(config.platforms) - .filter(([_, info]) => info.installer) - .map(([code, _]) => code); -} - -/** - * Get platforms that use custom installers (no installer config) - * @returns {Promise} Array of platform codes with custom installers - */ -async function getCustomInstallerPlatforms() { - const config = await loadPlatformCodes(); - return Object.entries(config.platforms) - .filter(([_, info]) => !info.installer) - .map(([code, _]) => code); -} - -/** - * Clear the cached platform codes (useful for testing) - */ -function clearCache() { - _cachedPlatformCodes = null; -} - -module.exports = { - loadPlatformCodes, - getPlatformInfo, - getPreferredPlatforms, - getPlatformsByCategory, - getConfigDrivenPlatforms, - getCustomInstallerPlatforms, - clearCache, -}; diff --git a/tools/cli/installers/lib/ide/platform-codes.yaml b/tools/cli/installers/lib/ide/platform-codes.yaml deleted file mode 100644 index 2c4d2e920..000000000 --- a/tools/cli/installers/lib/ide/platform-codes.yaml +++ /dev/null @@ -1,341 +0,0 @@ -# BMAD Platform Codes Configuration -# Central configuration for all platform/IDE codes used in the BMAD system -# -# This file defines: -# 1. Platform metadata (name, preferred status, category, description) -# 2. Installer configuration (target directories, templates, artifact types) -# -# Format: -# code: Platform identifier used internally -# name: Display name shown to users -# preferred: Whether this platform is shown as a recommended option on install -# category: Type of platform (ide, cli, tool, service) -# description: Brief description of the platform -# installer: Installation configuration (optional - omit for custom installers) - -platforms: - antigravity: - name: "Google Antigravity" - preferred: false - category: ide - description: "Google's AI development environment" - installer: - legacy_targets: - - .agent/workflows - target_dir: .agent/skills - template_type: antigravity - skill_format: true - - auggie: - name: "Auggie" - preferred: false - category: cli - description: "AI development tool" - installer: - legacy_targets: - - .augment/commands - target_dir: .augment/skills - template_type: default - skill_format: true - - claude-code: - name: "Claude Code" - preferred: true - category: cli - description: "Anthropic's official CLI for Claude" - installer: - legacy_targets: - - .claude/commands - target_dir: .claude/skills - template_type: default - skill_format: true - ancestor_conflict_check: true - - cline: - name: "Cline" - preferred: false - category: ide - description: "AI coding assistant" - installer: - legacy_targets: - - .clinerules/workflows - target_dir: .cline/skills - template_type: default - skill_format: true - - codex: - name: "Codex" - preferred: false - category: cli - description: "OpenAI Codex integration" - installer: - legacy_targets: - - .codex/prompts - - ~/.codex/prompts - target_dir: .agents/skills - template_type: default - skill_format: true - ancestor_conflict_check: true - artifact_types: [agents, workflows, tasks] - - codebuddy: - name: "CodeBuddy" - preferred: false - category: ide - description: "Tencent Cloud Code Assistant - AI-powered coding companion" - installer: - legacy_targets: - - .codebuddy/commands - target_dir: .codebuddy/skills - template_type: default - skill_format: true - - crush: - name: "Crush" - preferred: false - category: ide - description: "AI development assistant" - installer: - legacy_targets: - - .crush/commands - target_dir: .crush/skills - template_type: default - skill_format: true - - cursor: - name: "Cursor" - preferred: true - category: ide - description: "AI-first code editor" - installer: - legacy_targets: - - .cursor/commands - target_dir: .cursor/skills - template_type: default - skill_format: true - - gemini: - name: "Gemini CLI" - preferred: false - category: cli - description: "Google's CLI for Gemini" - installer: - legacy_targets: - - .gemini/commands - target_dir: .gemini/skills - template_type: default - skill_format: true - - github-copilot: - name: "GitHub Copilot" - preferred: false - category: ide - description: "GitHub's AI pair programmer" - installer: - legacy_targets: - - .github/agents - - .github/prompts - target_dir: .github/skills - template_type: default - skill_format: true - - iflow: - name: "iFlow" - preferred: false - category: ide - description: "AI workflow automation" - installer: - legacy_targets: - - .iflow/commands - target_dir: .iflow/skills - template_type: default - skill_format: true - - kilo: - name: "KiloCoder" - preferred: false - category: ide - description: "AI coding platform" - suspended: "Kilo Code does not yet support the Agent Skills standard. Support is paused until they implement it. See https://github.com/kilocode/kilo-code/issues for updates." - installer: - legacy_targets: - - .kilocode/workflows - target_dir: .kilocode/skills - template_type: default - skill_format: true - - kiro: - name: "Kiro" - preferred: false - category: ide - description: "Amazon's AI-powered IDE" - installer: - legacy_targets: - - .kiro/steering - target_dir: .kiro/skills - template_type: kiro - skill_format: true - - ona: - name: "Ona" - preferred: false - category: ide - description: "Ona AI development environment" - installer: - target_dir: .ona/skills - template_type: default - skill_format: true - - opencode: - name: "OpenCode" - preferred: false - category: ide - description: "OpenCode terminal coding assistant" - installer: - legacy_targets: - - .opencode/agents - - .opencode/commands - - .opencode/agent - - .opencode/command - target_dir: .opencode/skills - template_type: opencode - skill_format: true - ancestor_conflict_check: true - - pi: - name: "Pi" - preferred: false - category: cli - description: "Provider-agnostic terminal-native AI coding agent" - installer: - target_dir: .pi/skills - template_type: default - skill_format: true - - qoder: - name: "Qoder" - preferred: false - category: ide - description: "Qoder AI coding assistant" - installer: - target_dir: .qoder/skills - template_type: default - skill_format: true - - qwen: - name: "QwenCoder" - preferred: false - category: ide - description: "Qwen AI coding assistant" - installer: - legacy_targets: - - .qwen/commands - target_dir: .qwen/skills - template_type: default - skill_format: true - - roo: - name: "Roo Code" - preferred: false - category: ide - description: "Enhanced Cline fork" - installer: - legacy_targets: - - .roo/commands - target_dir: .roo/skills - template_type: default - skill_format: true - - rovo-dev: - name: "Rovo Dev" - preferred: false - category: ide - description: "Atlassian's Rovo development environment" - installer: - legacy_targets: - - .rovodev/workflows - target_dir: .rovodev/skills - template_type: default - skill_format: true - - trae: - name: "Trae" - preferred: false - category: ide - description: "AI coding tool" - installer: - legacy_targets: - - .trae/rules - target_dir: .trae/skills - template_type: default - skill_format: true - - windsurf: - name: "Windsurf" - preferred: false - category: ide - description: "AI-powered IDE with cascade flows" - installer: - legacy_targets: - - .windsurf/workflows - target_dir: .windsurf/skills - template_type: windsurf - skill_format: true - -# ============================================================================ -# Installer Config Schema -# ============================================================================ -# -# installer: -# target_dir: string # Directory where artifacts are installed -# template_type: string # Default template type to use -# header_template: string (optional) # Override for header/frontmatter template -# body_template: string (optional) # Override for body/content template -# legacy_targets: array (optional) # Old target dirs to clean up on reinstall (migration) -# - string # Relative path, e.g. .opencode/agent -# targets: array (optional) # For multi-target installations -# - target_dir: string -# template_type: string -# artifact_types: [agents, workflows, tasks, tools] -# artifact_types: array (optional) # Filter which artifacts to install (default: all) -# skip_existing: boolean (optional) # Skip files that already exist (default: false) -# skill_format: boolean (optional) # Use directory-per-skill output: /SKILL.md -# # with clean frontmatter (name + description, unquoted) -# ancestor_conflict_check: boolean (optional) # Refuse install when ancestor dir has BMAD files -# # in the same target_dir (for IDEs that inherit -# # skills from parent directories) - -# ============================================================================ -# Platform Categories -# ============================================================================ - -categories: - ide: - name: "Integrated Development Environment" - description: "Full-featured code editors with AI assistance" - - cli: - name: "Command Line Interface" - description: "Terminal-based tools" - - tool: - name: "Development Tool" - description: "Standalone development utilities" - - service: - name: "Cloud Service" - description: "Cloud-based development platforms" - - extension: - name: "Editor Extension" - description: "Plugins for existing editors" - -# ============================================================================ -# Naming Conventions and Rules -# ============================================================================ - -conventions: - code_format: "lowercase-kebab-case" - name_format: "Title Case" - max_code_length: 20 - allowed_characters: "a-z0-9-" diff --git a/tools/cli/installers/lib/ide/shared/agent-command-generator.js b/tools/cli/installers/lib/ide/shared/agent-command-generator.js deleted file mode 100644 index 0fc1b04dc..000000000 --- a/tools/cli/installers/lib/ide/shared/agent-command-generator.js +++ /dev/null @@ -1,180 +0,0 @@ -const path = require('node:path'); -const fs = require('fs-extra'); -const { toColonPath, toDashPath, customAgentColonName, customAgentDashName, BMAD_FOLDER_NAME } = require('./path-utils'); - -/** - * Generates launcher command files for each agent - */ -class AgentCommandGenerator { - constructor(bmadFolderName = BMAD_FOLDER_NAME) { - this.templatePath = path.join(__dirname, '../templates/agent-command-template.md'); - this.bmadFolderName = bmadFolderName; - } - - /** - * Collect agent artifacts for IDE installation - * @param {string} bmadDir - BMAD installation directory - * @param {Array} selectedModules - Modules to include - * @returns {Object} Artifacts array with metadata - */ - async collectAgentArtifacts(bmadDir, selectedModules = []) { - const { getAgentsFromBmad } = require('./bmad-artifacts'); - - // Get agents from INSTALLED bmad/ directory - const agents = await getAgentsFromBmad(bmadDir, selectedModules); - - const artifacts = []; - - for (const agent of agents) { - const launcherContent = await this.generateLauncherContent(agent); - // Use relativePath if available (for nested agents), otherwise just name with .md - const agentPathInModule = agent.relativePath || `${agent.name}.md`; - // Calculate the relative agent path (e.g., bmm/agents/pm.md) - let agentRelPath = agent.path || ''; - // Normalize path separators for cross-platform compatibility - agentRelPath = agentRelPath.replaceAll('\\', '/'); - // Remove _bmad/ prefix if present to get relative path from project root - // Handle both absolute paths (/path/to/_bmad/...) and relative paths (_bmad/...) - if (agentRelPath.includes('_bmad/')) { - const parts = agentRelPath.split(/_bmad\//); - if (parts.length > 1) { - agentRelPath = parts.slice(1).join('/'); - } - } - artifacts.push({ - type: 'agent-launcher', - name: agent.name, - description: agent.description || `${agent.name} agent`, - module: agent.module, - canonicalId: agent.canonicalId || '', - relativePath: path.join(agent.module, 'agents', agentPathInModule), // For command filename - agentPath: agentRelPath, // Relative path to actual agent file - content: launcherContent, - sourcePath: agent.path, - }); - } - - return { - artifacts, - counts: { - agents: agents.length, - }, - }; - } - - /** - * Generate launcher content for an agent - * @param {Object} agent - Agent metadata - * @returns {string} Launcher file content - */ - async generateLauncherContent(agent) { - // Load the template - const template = await fs.readFile(this.templatePath, 'utf8'); - - // Replace template variables - // Use relativePath if available (for nested agents), otherwise just name with .md - const agentPathInModule = agent.relativePath || `${agent.name}.md`; - return template - .replaceAll('{{name}}', agent.name) - .replaceAll('{{module}}', agent.module) - .replaceAll('{{path}}', agentPathInModule) - .replaceAll('{{description}}', agent.description || `${agent.name} agent`) - .replaceAll('_bmad', this.bmadFolderName) - .replaceAll('_bmad', '_bmad'); - } - - /** - * Write agent launcher artifacts to IDE commands directory - * @param {string} baseCommandsDir - Base commands directory for the IDE - * @param {Array} artifacts - Agent launcher artifacts - * @returns {number} Count of launchers written - */ - async writeAgentLaunchers(baseCommandsDir, artifacts) { - let writtenCount = 0; - - for (const artifact of artifacts) { - if (artifact.type === 'agent-launcher') { - const moduleAgentsDir = path.join(baseCommandsDir, artifact.module, 'agents'); - await fs.ensureDir(moduleAgentsDir); - - const launcherPath = path.join(moduleAgentsDir, `${artifact.name}.md`); - await fs.writeFile(launcherPath, artifact.content); - writtenCount++; - } - } - - return writtenCount; - } - - /** - * Write agent launcher artifacts using underscore format (Windows-compatible) - * Creates flat files like: bmad_bmm_pm.md - * - * @param {string} baseCommandsDir - Base commands directory for the IDE - * @param {Array} artifacts - Agent launcher artifacts - * @returns {number} Count of launchers written - */ - async writeColonArtifacts(baseCommandsDir, artifacts) { - let writtenCount = 0; - - for (const artifact of artifacts) { - if (artifact.type === 'agent-launcher') { - // Convert relativePath to underscore format: bmm/agents/pm.md → bmad_bmm_pm.md - const flatName = toColonPath(artifact.relativePath); - const launcherPath = path.join(baseCommandsDir, flatName); - await fs.ensureDir(path.dirname(launcherPath)); - await fs.writeFile(launcherPath, artifact.content); - writtenCount++; - } - } - - return writtenCount; - } - - /** - * Write agent launcher artifacts using dash format (NEW STANDARD) - * Creates flat files like: bmad-agent-bmm-pm.md - * - * The bmad-agent- prefix distinguishes agents from workflows/tasks/tools. - * - * @param {string} baseCommandsDir - Base commands directory for the IDE - * @param {Array} artifacts - Agent launcher artifacts - * @returns {number} Count of launchers written - */ - async writeDashArtifacts(baseCommandsDir, artifacts) { - let writtenCount = 0; - - for (const artifact of artifacts) { - if (artifact.type === 'agent-launcher') { - // Convert relativePath to dash format: bmm/agents/pm.md → bmad-agent-bmm-pm.md - const flatName = toDashPath(artifact.relativePath); - const launcherPath = path.join(baseCommandsDir, flatName); - await fs.ensureDir(path.dirname(launcherPath)); - await fs.writeFile(launcherPath, artifact.content); - writtenCount++; - } - } - - return writtenCount; - } - - /** - * Get the custom agent name in underscore format (Windows-compatible) - * @param {string} agentName - Custom agent name - * @returns {string} Underscore-formatted filename - */ - getCustomAgentColonName(agentName) { - return customAgentColonName(agentName); - } - - /** - * Get the custom agent name in underscore format (Windows-compatible) - * @param {string} agentName - Custom agent name - * @returns {string} Underscore-formatted filename - */ - getCustomAgentDashName(agentName) { - return customAgentDashName(agentName); - } -} - -module.exports = { AgentCommandGenerator }; diff --git a/tools/cli/installers/lib/ide/shared/bmad-artifacts.js b/tools/cli/installers/lib/ide/shared/bmad-artifacts.js deleted file mode 100644 index ac0dbd190..000000000 --- a/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +++ /dev/null @@ -1,208 +0,0 @@ -const path = require('node:path'); -const fs = require('fs-extra'); -const { loadSkillManifest, getCanonicalId } = require('./skill-manifest'); - -/** - * Helpers for gathering BMAD agents/tasks from the installed tree. - * Shared by installers that need Claude-style exports. - * - * TODO: Dead code cleanup — compiled XML agents are retired. - * - * All agents now use the SKILL.md directory format with bmad-skill-manifest.yaml - * (type: agent). The legacy pipeline below only discovers compiled .md files - * containing XML tags, which no longer exist. The following are dead: - * - * - getAgentsFromBmad() — scans {module}/agents/ for .md files with tags - * - getAgentsFromDir() — recursive helper for the above - * - AgentCommandGenerator — (agent-command-generator.js) generates launcher .md files - * that tell the LLM to load a compiled agent .md file - * - agent-command-template.md — (templates/) the launcher template with hardcoded - * {module}/agents/{{path}} reference - * - * Agent metadata for agent-manifest.csv is now handled entirely by - * ManifestGenerator.getAgentsFromDirRecursive() in manifest-generator.js, - * which walks the full module tree and finds type:agent directories. - * - * IDE installation of agents is handled by the native skill pipeline — - * each agent's SKILL.md directory is installed directly to the IDE's - * skills path, so no launcher intermediary is needed. - * - * Cleanup: remove getAgentsFromBmad, getAgentsFromDir, their exports, - * AgentCommandGenerator, agent-command-template.md, and all call sites - * in IDE installers that invoke collectAgentArtifacts / writeAgentLaunchers / - * writeColonArtifacts / writeDashArtifacts. - * getTasksFromBmad and getTasksFromDir may still be live — verify before removing. - */ -async function getAgentsFromBmad(bmadDir, selectedModules = []) { - const agents = []; - - // Get core agents - if (await fs.pathExists(path.join(bmadDir, 'core', 'agents'))) { - const coreAgents = await getAgentsFromDir(path.join(bmadDir, 'core', 'agents'), 'core'); - agents.push(...coreAgents); - } - - // Get module agents - for (const moduleName of selectedModules) { - const agentsPath = path.join(bmadDir, moduleName, 'agents'); - - if (await fs.pathExists(agentsPath)) { - const moduleAgents = await getAgentsFromDir(agentsPath, moduleName); - agents.push(...moduleAgents); - } - } - - // Get standalone agents from bmad/agents/ directory - const standaloneAgentsDir = path.join(bmadDir, 'agents'); - if (await fs.pathExists(standaloneAgentsDir)) { - const agentDirs = await fs.readdir(standaloneAgentsDir, { withFileTypes: true }); - - for (const agentDir of agentDirs) { - if (!agentDir.isDirectory()) continue; - - const agentDirPath = path.join(standaloneAgentsDir, agentDir.name); - const agentFiles = await fs.readdir(agentDirPath); - const skillManifest = await loadSkillManifest(agentDirPath); - - for (const file of agentFiles) { - if (!file.endsWith('.md')) continue; - if (file.includes('.customize.')) continue; - - const filePath = path.join(agentDirPath, file); - const content = await fs.readFile(filePath, 'utf8'); - - if (content.includes('localskip="true"')) continue; - - agents.push({ - path: filePath, - name: file.replace('.md', ''), - module: 'standalone', // Mark as standalone agent - canonicalId: getCanonicalId(skillManifest, file), - }); - } - } - } - - return agents; -} - -async function getTasksFromBmad(bmadDir, selectedModules = []) { - const tasks = []; - - if (await fs.pathExists(path.join(bmadDir, 'core', 'tasks'))) { - const coreTasks = await getTasksFromDir(path.join(bmadDir, 'core', 'tasks'), 'core'); - tasks.push(...coreTasks); - } - - for (const moduleName of selectedModules) { - const tasksPath = path.join(bmadDir, moduleName, 'tasks'); - - if (await fs.pathExists(tasksPath)) { - const moduleTasks = await getTasksFromDir(tasksPath, moduleName); - tasks.push(...moduleTasks); - } - } - - return tasks; -} - -async function getAgentsFromDir(dirPath, moduleName, relativePath = '') { - const agents = []; - - if (!(await fs.pathExists(dirPath))) { - return agents; - } - - const entries = await fs.readdir(dirPath, { withFileTypes: true }); - const skillManifest = await loadSkillManifest(dirPath); - - for (const entry of entries) { - // Skip if entry.name is undefined or not a string - if (!entry.name || typeof entry.name !== 'string') { - continue; - } - - const fullPath = path.join(dirPath, entry.name); - const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name; - - if (entry.isDirectory()) { - // Recurse into subdirectories - const subDirAgents = await getAgentsFromDir(fullPath, moduleName, newRelativePath); - agents.push(...subDirAgents); - } else if (entry.name.endsWith('.md')) { - // Skip README files and other non-agent files - if (entry.name.toLowerCase() === 'readme.md' || entry.name.toLowerCase().startsWith('readme-')) { - continue; - } - - if (entry.name.includes('.customize.')) { - continue; - } - - const content = await fs.readFile(fullPath, 'utf8'); - - if (content.includes('localskip="true"')) { - continue; - } - - // Only include files that have agent-specific content (compiled agents have tag) - if (!content.includes(' 0) { - return true; - } - - if (injection.requires) { - const required = `${injection.requires}.md`; - return selected.includes(required); - } - - if (injection.point) { - const selectedNames = selected.map((file) => file.replace('.md', '')); - return selectedNames.some((name) => injection.point.includes(name)); - } - } - - return false; -} - -function filterAgentInstructions(content, selectedFiles) { - if (!selectedFiles || selectedFiles.length === 0) { - return ''; - } - - const selectedAgents = selectedFiles.map((file) => file.replace('.md', '')); - const lines = content.split('\n'); - const filteredLines = []; - - for (const line of lines) { - if (line.includes('')) { - filteredLines.push(line); - } else if (line.includes('subagent')) { - let shouldInclude = false; - for (const agent of selectedAgents) { - if (line.includes(agent)) { - shouldInclude = true; - break; - } - } - - if (shouldInclude) { - filteredLines.push(line); - } - } else if (line.includes('When creating PRDs') || line.includes('ACTIVELY delegate')) { - filteredLines.push(line); - } - } - - if (filteredLines.length > 2) { - return filteredLines.join('\n'); - } - - return ''; -} - -async function resolveSubagentFiles(handlerBaseDir, subagentConfig, subagentChoices) { - if (!subagentConfig || !subagentConfig.files) { - return []; - } - - if (!subagentChoices || subagentChoices.install === 'none') { - return []; - } - - let filesToCopy = subagentConfig.files; - - if (subagentChoices.install === 'selective') { - filesToCopy = subagentChoices.selected || []; - } - - const sourceDir = path.join(handlerBaseDir, subagentConfig.source || ''); - const resolved = []; - - for (const file of filesToCopy) { - // Use forward slashes for glob pattern (works on both Windows and Unix) - // Convert backslashes to forward slashes for glob compatibility - const normalizedSourceDir = sourceDir.replaceAll('\\', '/'); - const pattern = `${normalizedSourceDir}/**/${file}`; - const matches = await glob(pattern); - - if (matches.length > 0) { - const absolutePath = matches[0]; - resolved.push({ - file, - absolutePath, - relativePath: path.relative(sourceDir, absolutePath), - sourceDir, - }); - } - } - - return resolved; -} - -module.exports = { - loadModuleInjectionConfig, - shouldApplyInjection, - filterAgentInstructions, - resolveSubagentFiles, -}; diff --git a/tools/cli/installers/lib/ide/templates/agent-command-template.md b/tools/cli/installers/lib/ide/templates/agent-command-template.md deleted file mode 100644 index 0f0c2e20d..000000000 --- a/tools/cli/installers/lib/ide/templates/agent-command-template.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: '{{name}}' -description: '{{description}}' ---- - -You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command. - - -1. LOAD the FULL agent file from {project-root}/_bmad/{{module}}/agents/{{path}} -2. READ its entire contents - this contains the complete agent persona, menu, and instructions -3. Execute ALL activation steps exactly as written in the agent file -4. Follow the agent's persona and menu system precisely -5. Stay in character throughout the session - diff --git a/tools/cli/installers/lib/ide/templates/combined/antigravity.md b/tools/cli/installers/lib/ide/templates/combined/antigravity.md deleted file mode 100644 index 88e806e9d..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/antigravity.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: '{{name}}' -description: '{{description}}' ---- - -Read the entire workflow file at: {project-root}/_bmad/{{workflow_path}} - -Follow all instructions in the workflow file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/combined/claude-agent.md b/tools/cli/installers/lib/ide/templates/combined/claude-agent.md deleted file mode 120000 index 9f6c17b45..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/claude-agent.md +++ /dev/null @@ -1 +0,0 @@ -default-agent.md \ No newline at end of file diff --git a/tools/cli/installers/lib/ide/templates/combined/claude-workflow-yaml.md b/tools/cli/installers/lib/ide/templates/combined/claude-workflow-yaml.md deleted file mode 120000 index 11f78e1d4..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/claude-workflow-yaml.md +++ /dev/null @@ -1 +0,0 @@ -default-workflow-yaml.md \ No newline at end of file diff --git a/tools/cli/installers/lib/ide/templates/combined/claude-workflow.md b/tools/cli/installers/lib/ide/templates/combined/claude-workflow.md deleted file mode 120000 index 8d4ae5238..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/claude-workflow.md +++ /dev/null @@ -1 +0,0 @@ -default-workflow.md \ No newline at end of file diff --git a/tools/cli/installers/lib/ide/templates/combined/default-agent.md b/tools/cli/installers/lib/ide/templates/combined/default-agent.md deleted file mode 100644 index f8ad93801..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/default-agent.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: '{{name}}' -description: '{{description}}' ---- - -You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command. - - -1. LOAD the FULL agent file from {project-root}/_bmad/{{path}} -2. READ its entire contents - this contains the complete agent persona, menu, and instructions -3. FOLLOW every step in the section precisely -4. DISPLAY the welcome/greeting as instructed -5. PRESENT the numbered menu -6. WAIT for user input before proceeding - diff --git a/tools/cli/installers/lib/ide/templates/combined/default-task.md b/tools/cli/installers/lib/ide/templates/combined/default-task.md deleted file mode 100644 index b865d6ffb..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/default-task.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: '{{name}}' -description: '{{description}}' ---- - -# {{name}} - -Read the entire task file at: {project-root}/{{bmadFolderName}}/{{path}} - -Follow all instructions in the task file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/combined/default-tool.md b/tools/cli/installers/lib/ide/templates/combined/default-tool.md deleted file mode 100644 index 11c6aac8d..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/default-tool.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: '{{name}}' -description: '{{description}}' ---- - -# {{name}} - -Read the entire tool file at: {project-root}/{{bmadFolderName}}/{{path}} - -Follow all instructions in the tool file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/combined/default-workflow.md b/tools/cli/installers/lib/ide/templates/combined/default-workflow.md deleted file mode 100644 index c8ad40459..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -name: '{{name}}' -description: '{{description}}' ---- - -IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL {project-root}/{{bmadFolderName}}/{{path}}, READ its entire contents and follow its directions exactly! diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml deleted file mode 100644 index ae5f791cf..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml +++ /dev/null @@ -1,14 +0,0 @@ -description = "Activates the {{name}} agent from the BMad Method." -prompt = """ -CRITICAL: You are now the BMad '{{name}}' agent. - -PRE-FLIGHT CHECKLIST: -1. [ ] IMMEDIATE ACTION: Load and parse {project-root}/{{bmadFolderName}}/{{module}}/config.yaml - store ALL config values in memory for use throughout the session. -2. [ ] IMMEDIATE ACTION: Read and internalize the full agent definition at {project-root}/{{bmadFolderName}}/{{path}}. -3. [ ] CONFIRM: The user's name from config is {user_name}. - -Only after all checks are complete, greet the user by name and display the menu. -Acknowledge this checklist is complete in your first response. - -AGENT DEFINITION: {project-root}/{{bmadFolderName}}/{{path}} -""" diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-task.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-task.toml deleted file mode 100644 index 7d15e2164..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/gemini-task.toml +++ /dev/null @@ -1,11 +0,0 @@ -description = "Executes the {{name}} task from the BMAD Method." -prompt = """ -Execute the BMAD '{{name}}' task. - -TASK INSTRUCTIONS: -1. LOAD the task file from {project-root}/{{bmadFolderName}}/{{path}} -2. READ its entire contents -3. FOLLOW every instruction precisely as specified - -TASK FILE: {project-root}/{{bmadFolderName}}/{{path}} -""" diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml deleted file mode 100644 index fc78c6b72..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml +++ /dev/null @@ -1,11 +0,0 @@ -description = "Executes the {{name}} tool from the BMAD Method." -prompt = """ -Execute the BMAD '{{name}}' tool. - -TOOL INSTRUCTIONS: -1. LOAD the tool file from {project-root}/{{bmadFolderName}}/{{path}} -2. READ its entire contents -3. FOLLOW every instruction precisely as specified - -TOOL FILE: {project-root}/{{bmadFolderName}}/{{path}} -""" diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml deleted file mode 100644 index bc6c8da39..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +++ /dev/null @@ -1,16 +0,0 @@ -description = '{{description}}' -prompt = """ -Execute the BMAD '{{name}}' workflow. - -CRITICAL: This is a structured YAML workflow. Follow these steps precisely: - -1. LOAD the workflow definition from {project-root}/{{bmadFolderName}}/{{workflow_path}} -2. PARSE the YAML structure to understand: - - Workflow phases and steps - - Required inputs and outputs - - Dependencies between steps -3. EXECUTE each step in order -4. VALIDATE outputs before proceeding to next step - -WORKFLOW FILE: {project-root}/{{bmadFolderName}}/{{workflow_path}} -""" diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml deleted file mode 100644 index 3306cce04..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +++ /dev/null @@ -1,14 +0,0 @@ -description = '{{description}}' -prompt = """ -Execute the BMAD '{{name}}' workflow. - -CRITICAL: You must load and follow the workflow definition exactly. - -WORKFLOW INSTRUCTIONS: -1. LOAD the workflow file from {project-root}/{{bmadFolderName}}/{{workflow_path}} -2. READ its entire contents -3. FOLLOW every step precisely as specified -4. DO NOT skip or modify any steps - -WORKFLOW FILE: {project-root}/{{bmadFolderName}}/{{workflow_path}} -""" diff --git a/tools/cli/installers/lib/ide/templates/combined/kiro-agent.md b/tools/cli/installers/lib/ide/templates/combined/kiro-agent.md deleted file mode 100644 index e2c2a83fa..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/kiro-agent.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -inclusion: manual ---- - -# {{name}} - -You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command. - - -1. LOAD the FULL agent file from #[[file:{{bmadFolderName}}/{{path}}]] -2. READ its entire contents - this contains the complete agent persona, menu, and instructions -3. FOLLOW every step in the section precisely -4. DISPLAY the welcome/greeting as instructed -5. PRESENT the numbered menu -6. WAIT for user input before proceeding - diff --git a/tools/cli/installers/lib/ide/templates/combined/kiro-task.md b/tools/cli/installers/lib/ide/templates/combined/kiro-task.md deleted file mode 100644 index 8952e5ee2..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/kiro-task.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -inclusion: manual ---- - -# {{name}} - -Read the entire task file at: #[[file:{{bmadFolderName}}/{{path}}]] - -Follow all instructions in the task file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/combined/kiro-tool.md b/tools/cli/installers/lib/ide/templates/combined/kiro-tool.md deleted file mode 100644 index cd903217a..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/kiro-tool.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -inclusion: manual ---- - -# {{name}} - -Read the entire tool file at: #[[file:{{bmadFolderName}}/{{path}}]] - -Follow all instructions in the tool file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/combined/kiro-workflow.md b/tools/cli/installers/lib/ide/templates/combined/kiro-workflow.md deleted file mode 100644 index e1847f414..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/kiro-workflow.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -inclusion: manual ---- - -# {{name}} - -IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL #[[file:{{bmadFolderName}}/{{path}}]], READ its entire contents and follow its directions exactly! diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md b/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md deleted file mode 100644 index 828d673ac..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -mode: all -description: '{{description}}' ---- - -You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command. - - -1. LOAD the FULL agent file from {project-root}/{{bmadFolderName}}/{{path}} -2. READ its entire contents - this contains the complete agent persona, menu, and instructions -3. FOLLOW every step in the section precisely -4. DISPLAY the welcome/greeting as instructed -5. PRESENT the numbered menu -6. WAIT for user input before proceeding - diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-task.md b/tools/cli/installers/lib/ide/templates/combined/opencode-task.md deleted file mode 100644 index 772f9c9eb..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -description: '{{description}}' ---- - -Execute the BMAD '{{name}}' task. - -TASK INSTRUCTIONS: - -1. LOAD the task file from {project-root}/{{bmadFolderName}}/{{path}} -2. READ its entire contents -3. FOLLOW every instruction precisely as specified - -TASK FILE: {project-root}/{{bmadFolderName}}/{{path}} diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md b/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md deleted file mode 100644 index 88c317e63..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -description: '{{description}}' ---- - -Execute the BMAD '{{name}}' tool. - -TOOL INSTRUCTIONS: - -1. LOAD the tool file from {project-root}/{{bmadFolderName}}/{{path}} -2. READ its entire contents -3. FOLLOW every instruction precisely as specified - -TOOL FILE: {project-root}/{{bmadFolderName}}/{{path}} diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md deleted file mode 100644 index 88838cc1c..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -description: '{{description}}' ---- - -Execute the BMAD '{{name}}' workflow. - -CRITICAL: You must load and follow the workflow definition exactly. - -WORKFLOW INSTRUCTIONS: - -1. LOAD the workflow file from {project-root}/{{bmadFolderName}}/{{path}} -2. READ its entire contents -3. FOLLOW every step precisely as specified -4. DO NOT skip or modify any steps - -WORKFLOW FILE: {project-root}/{{bmadFolderName}}/{{path}} diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md deleted file mode 100644 index 88838cc1c..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -description: '{{description}}' ---- - -Execute the BMAD '{{name}}' workflow. - -CRITICAL: You must load and follow the workflow definition exactly. - -WORKFLOW INSTRUCTIONS: - -1. LOAD the workflow file from {project-root}/{{bmadFolderName}}/{{path}} -2. READ its entire contents -3. FOLLOW every step precisely as specified -4. DO NOT skip or modify any steps - -WORKFLOW FILE: {project-root}/{{bmadFolderName}}/{{path}} diff --git a/tools/cli/installers/lib/ide/templates/combined/rovodev.md b/tools/cli/installers/lib/ide/templates/combined/rovodev.md deleted file mode 100644 index 066945ee5..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/rovodev.md +++ /dev/null @@ -1,9 +0,0 @@ -# {{name}} - -{{description}} - ---- - -Read the entire workflow file at: {project-root}/_bmad/{{workflow_path}} - -Follow all instructions in the workflow file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/combined/trae.md b/tools/cli/installers/lib/ide/templates/combined/trae.md deleted file mode 100644 index b4d43d7af..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/trae.md +++ /dev/null @@ -1,9 +0,0 @@ -# {{name}} - -{{description}} - -## Instructions - -Read the entire workflow file at: {project-root}/_bmad/{{workflow_path}} - -Follow all instructions in the workflow file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md b/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md deleted file mode 100644 index 6366425c7..000000000 --- a/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -description: '{{description}}' -auto_execution_mode: "iterate" ---- - -# {{name}} - -Read the entire workflow file at {project-root}/_bmad/{{workflow_path}} - -Follow all instructions in the workflow file exactly as written. diff --git a/tools/cli/installers/lib/ide/templates/split/.gitkeep b/tools/cli/installers/lib/ide/templates/split/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/tools/cli/installers/lib/modules/external-manager.js b/tools/cli/installers/lib/modules/external-manager.js deleted file mode 100644 index f1ea2206e..000000000 --- a/tools/cli/installers/lib/modules/external-manager.js +++ /dev/null @@ -1,136 +0,0 @@ -const fs = require('fs-extra'); -const path = require('node:path'); -const yaml = require('yaml'); -const prompts = require('../../../lib/prompts'); - -/** - * Manages external official modules defined in external-official-modules.yaml - * These are modules hosted in external repositories that can be installed - * - * @class ExternalModuleManager - */ -class ExternalModuleManager { - constructor() { - this.externalModulesConfigPath = path.join(__dirname, '../../../external-official-modules.yaml'); - this.cachedModules = null; - } - - /** - * Load and parse the external-official-modules.yaml file - * @returns {Object} Parsed YAML content with modules object - */ - async loadExternalModulesConfig() { - if (this.cachedModules) { - return this.cachedModules; - } - - try { - const content = await fs.readFile(this.externalModulesConfigPath, 'utf8'); - const config = yaml.parse(content); - this.cachedModules = config; - return config; - } catch (error) { - await prompts.log.warn(`Failed to load external modules config: ${error.message}`); - return { modules: {} }; - } - } - - /** - * Get list of available external modules - * @returns {Array} Array of module info objects - */ - async listAvailable() { - const config = await this.loadExternalModulesConfig(); - const modules = []; - - for (const [key, moduleConfig] of Object.entries(config.modules || {})) { - modules.push({ - key, - url: moduleConfig.url, - moduleDefinition: moduleConfig['module-definition'], - code: moduleConfig.code, - name: moduleConfig.name, - header: moduleConfig.header, - subheader: moduleConfig.subheader, - description: moduleConfig.description || '', - defaultSelected: moduleConfig.defaultSelected === true, - type: moduleConfig.type || 'community', // bmad-org or community - npmPackage: moduleConfig.npmPackage || null, // Include npm package name - isExternal: true, - }); - } - - return modules; - } - - /** - * Get module info by code - * @param {string} code - The module code (e.g., 'cis') - * @returns {Object|null} Module info or null if not found - */ - async getModuleByCode(code) { - const modules = await this.listAvailable(); - return modules.find((m) => m.code === code) || null; - } - - /** - * Get module info by key - * @param {string} key - The module key (e.g., 'bmad-creative-intelligence-suite') - * @returns {Object|null} Module info or null if not found - */ - async getModuleByKey(key) { - const config = await this.loadExternalModulesConfig(); - const moduleConfig = config.modules?.[key]; - - if (!moduleConfig) { - return null; - } - - return { - key, - url: moduleConfig.url, - moduleDefinition: moduleConfig['module-definition'], - code: moduleConfig.code, - name: moduleConfig.name, - header: moduleConfig.header, - subheader: moduleConfig.subheader, - description: moduleConfig.description || '', - defaultSelected: moduleConfig.defaultSelected === true, - type: moduleConfig.type || 'community', // bmad-org or community - npmPackage: moduleConfig.npmPackage || null, // Include npm package name - isExternal: true, - }; - } - - /** - * Check if a module code exists in external modules - * @param {string} code - The module code to check - * @returns {boolean} True if the module exists - */ - async hasModule(code) { - const module = await this.getModuleByCode(code); - return module !== null; - } - - /** - * Get the URL for a module by code - * @param {string} code - The module code - * @returns {string|null} The URL or null if not found - */ - async getModuleUrl(code) { - const module = await this.getModuleByCode(code); - return module ? module.url : null; - } - - /** - * Get the module definition path for a module by code - * @param {string} code - The module code - * @returns {string|null} The module definition path or null if not found - */ - async getModuleDefinition(code) { - const module = await this.getModuleByCode(code); - return module ? module.moduleDefinition : null; - } -} - -module.exports = { ExternalModuleManager }; diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js deleted file mode 100644 index 17a320c44..000000000 --- a/tools/cli/installers/lib/modules/manager.js +++ /dev/null @@ -1,928 +0,0 @@ -const path = require('node:path'); -const fs = require('fs-extra'); -const yaml = require('yaml'); -const prompts = require('../../../lib/prompts'); -const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root'); -const { ExternalModuleManager } = require('./external-manager'); -const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils'); - -/** - * Manages the installation, updating, and removal of BMAD modules. - * Handles module discovery, dependency resolution, and configuration processing. - * - * @class ModuleManager - * @requires fs-extra - * @requires yaml - * @requires prompts - * - * @example - * const manager = new ModuleManager(); - * const modules = await manager.listAvailable(); - * await manager.install('core-module', '/path/to/bmad'); - */ -class ModuleManager { - constructor(options = {}) { - this.bmadFolderName = BMAD_FOLDER_NAME; // Default, can be overridden - this.customModulePaths = new Map(); // Initialize custom module paths - this.externalModuleManager = new ExternalModuleManager(); // For external official modules - } - - /** - * Set the bmad folder name for placeholder replacement - * @param {string} bmadFolderName - The bmad folder name - */ - setBmadFolderName(bmadFolderName) { - this.bmadFolderName = bmadFolderName; - } - - /** - * Set the core configuration for access during module installation - * @param {Object} coreConfig - Core configuration object - */ - setCoreConfig(coreConfig) { - this.coreConfig = coreConfig; - } - - /** - * Set custom module paths for priority lookup - * @param {Map} customModulePaths - Map of module ID to source path - */ - setCustomModulePaths(customModulePaths) { - this.customModulePaths = customModulePaths; - } - - /** - * Copy a file to the target location - * @param {string} sourcePath - Source file path - * @param {string} targetPath - Target file path - * @param {boolean} overwrite - Whether to overwrite existing files (default: true) - */ - async copyFileWithPlaceholderReplacement(sourcePath, targetPath, overwrite = true) { - await fs.copy(sourcePath, targetPath, { overwrite }); - } - - /** - * Copy a directory recursively - * @param {string} sourceDir - Source directory path - * @param {string} targetDir - Target directory path - * @param {boolean} overwrite - Whether to overwrite existing files (default: true) - */ - async copyDirectoryWithPlaceholderReplacement(sourceDir, targetDir, overwrite = true) { - await fs.ensureDir(targetDir); - const entries = await fs.readdir(sourceDir, { withFileTypes: true }); - - for (const entry of entries) { - const sourcePath = path.join(sourceDir, entry.name); - const targetPath = path.join(targetDir, entry.name); - - if (entry.isDirectory()) { - await this.copyDirectoryWithPlaceholderReplacement(sourcePath, targetPath, overwrite); - } else { - await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, overwrite); - } - } - } - - /** - * List all available modules (excluding core which is always installed) - * bmm is the only built-in module, directly under src/bmm-skills - * All other modules come from external-official-modules.yaml - * @returns {Object} Object with modules array and customModules array - */ - async listAvailable() { - const modules = []; - const customModules = []; - - // Add built-in bmm module (directly under src/bmm-skills) - const bmmPath = getSourcePath('bmm-skills'); - if (await fs.pathExists(bmmPath)) { - const bmmInfo = await this.getModuleInfo(bmmPath, 'bmm', 'src/bmm-skills'); - if (bmmInfo) { - modules.push(bmmInfo); - } - } - - // Check for cached custom modules in _config/custom/ - if (this.bmadDir) { - const customCacheDir = path.join(this.bmadDir, '_config', 'custom'); - if (await fs.pathExists(customCacheDir)) { - const cacheEntries = await fs.readdir(customCacheDir, { withFileTypes: true }); - for (const entry of cacheEntries) { - if (entry.isDirectory()) { - const cachePath = path.join(customCacheDir, entry.name); - const moduleInfo = await this.getModuleInfo(cachePath, entry.name, '_config/custom'); - if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) { - moduleInfo.isCustom = true; - moduleInfo.fromCache = true; - customModules.push(moduleInfo); - } - } - } - } - } - - return { modules, customModules }; - } - - /** - * Get module information from a module path - * @param {string} modulePath - Path to the module directory - * @param {string} defaultName - Default name for the module - * @param {string} sourceDescription - Description of where the module was found - * @returns {Object|null} Module info or null if not a valid module - */ - async getModuleInfo(modulePath, defaultName, sourceDescription) { - // Check for module structure (module.yaml OR custom.yaml) - const moduleConfigPath = path.join(modulePath, 'module.yaml'); - const rootCustomConfigPath = path.join(modulePath, 'custom.yaml'); - let configPath = null; - - if (await fs.pathExists(moduleConfigPath)) { - configPath = moduleConfigPath; - } else if (await fs.pathExists(rootCustomConfigPath)) { - configPath = rootCustomConfigPath; - } - - // Skip if this doesn't look like a module - if (!configPath) { - return null; - } - - // Mark as custom if it's using custom.yaml OR if it's outside src/bmm or src/core - const isCustomSource = - sourceDescription !== 'src/bmm-skills' && sourceDescription !== 'src/core-skills' && sourceDescription !== 'src/modules'; - const moduleInfo = { - id: defaultName, - path: modulePath, - name: defaultName - .split('-') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' '), - description: 'BMAD Module', - version: '5.0.0', - source: sourceDescription, - isCustom: configPath === rootCustomConfigPath || isCustomSource, - }; - - // Read module config for metadata - try { - const configContent = await fs.readFile(configPath, 'utf8'); - const config = yaml.parse(configContent); - - // Use the code property as the id if available - if (config.code) { - moduleInfo.id = config.code; - } - - moduleInfo.name = config.name || moduleInfo.name; - moduleInfo.description = config.description || moduleInfo.description; - moduleInfo.version = config.version || moduleInfo.version; - moduleInfo.dependencies = config.dependencies || []; - moduleInfo.defaultSelected = config.default_selected === undefined ? false : config.default_selected; - } catch (error) { - await prompts.log.warn(`Failed to read config for ${defaultName}: ${error.message}`); - } - - return moduleInfo; - } - - /** - * Find the source path for a module by searching all possible locations - * @param {string} moduleCode - Code of the module to find (from module.yaml) - * @returns {string|null} Path to the module source or null if not found - */ - async findModuleSource(moduleCode, options = {}) { - const projectRoot = getProjectRoot(); - - // First check custom module paths if they exist - if (this.customModulePaths && this.customModulePaths.has(moduleCode)) { - return this.customModulePaths.get(moduleCode); - } - - // Check for built-in bmm module (directly under src/bmm-skills) - if (moduleCode === 'bmm') { - const bmmPath = getSourcePath('bmm-skills'); - if (await fs.pathExists(bmmPath)) { - return bmmPath; - } - } - - // Check external official modules - const externalSource = await this.findExternalModuleSource(moduleCode, options); - if (externalSource) { - return externalSource; - } - - return null; - } - - /** - * Check if a module is an external official module - * @param {string} moduleCode - Code of the module to check - * @returns {boolean} True if the module is external - */ - async isExternalModule(moduleCode) { - return await this.externalModuleManager.hasModule(moduleCode); - } - - /** - * Get the cache directory for external modules - * @returns {string} Path to the external modules cache directory - */ - getExternalCacheDir() { - const os = require('node:os'); - const cacheDir = path.join(os.homedir(), '.bmad', 'cache', 'external-modules'); - return cacheDir; - } - - /** - * Clone an external module repository to cache - * @param {string} moduleCode - Code of the external module - * @returns {string} Path to the cloned repository - */ - async cloneExternalModule(moduleCode, options = {}) { - const { execSync } = require('node:child_process'); - const moduleInfo = await this.externalModuleManager.getModuleByCode(moduleCode); - - if (!moduleInfo) { - throw new Error(`External module '${moduleCode}' not found in external-official-modules.yaml`); - } - - const cacheDir = this.getExternalCacheDir(); - const moduleCacheDir = path.join(cacheDir, moduleCode); - const silent = options.silent || false; - - // Create cache directory if it doesn't exist - await fs.ensureDir(cacheDir); - - // Helper to create a spinner or a no-op when silent - const createSpinner = async () => { - if (silent) { - return { - start() {}, - stop() {}, - error() {}, - message() {}, - cancel() {}, - clear() {}, - get isSpinning() { - return false; - }, - get isCancelled() { - return false; - }, - }; - } - return await prompts.spinner(); - }; - - // Track if we need to install dependencies - let needsDependencyInstall = false; - let wasNewClone = false; - - // Check if already cloned - if (await fs.pathExists(moduleCacheDir)) { - // Try to update if it's a git repo - const fetchSpinner = await createSpinner(); - fetchSpinner.start(`Fetching ${moduleInfo.name}...`); - try { - const currentRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim(); - // Fetch and reset to remote - works better with shallow clones than pull - execSync('git fetch origin --depth 1', { - cwd: moduleCacheDir, - stdio: ['ignore', 'pipe', 'pipe'], - env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, - }); - execSync('git reset --hard origin/HEAD', { - cwd: moduleCacheDir, - stdio: ['ignore', 'pipe', 'pipe'], - env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, - }); - const newRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim(); - - fetchSpinner.stop(`Fetched ${moduleInfo.name}`); - // Force dependency install if we got new code - if (currentRef !== newRef) { - needsDependencyInstall = true; - } - } catch { - fetchSpinner.error(`Fetch failed, re-downloading ${moduleInfo.name}`); - // If update fails, remove and re-clone - await fs.remove(moduleCacheDir); - wasNewClone = true; - } - } else { - wasNewClone = true; - } - - // Clone if not exists or was removed - if (wasNewClone) { - const fetchSpinner = await createSpinner(); - fetchSpinner.start(`Fetching ${moduleInfo.name}...`); - try { - execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, { - stdio: ['ignore', 'pipe', 'pipe'], - env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, - }); - fetchSpinner.stop(`Fetched ${moduleInfo.name}`); - } catch (error) { - fetchSpinner.error(`Failed to fetch ${moduleInfo.name}`); - throw new Error(`Failed to clone external module '${moduleCode}': ${error.message}`); - } - } - - // Install dependencies if package.json exists - const packageJsonPath = path.join(moduleCacheDir, 'package.json'); - const nodeModulesPath = path.join(moduleCacheDir, 'node_modules'); - if (await fs.pathExists(packageJsonPath)) { - // Install if node_modules doesn't exist, or if package.json is newer (dependencies changed) - const nodeModulesMissing = !(await fs.pathExists(nodeModulesPath)); - - // Force install if we updated or cloned new - if (needsDependencyInstall || wasNewClone || nodeModulesMissing) { - const installSpinner = await createSpinner(); - installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`); - try { - execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', { - cwd: moduleCacheDir, - stdio: ['ignore', 'pipe', 'pipe'], - timeout: 120_000, // 2 minute timeout - }); - installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`); - } catch (error) { - installSpinner.error(`Failed to install dependencies for ${moduleInfo.name}`); - if (!silent) await prompts.log.warn(` ${error.message}`); - } - } else { - // Check if package.json is newer than node_modules - let packageJsonNewer = false; - try { - const packageStats = await fs.stat(packageJsonPath); - const nodeModulesStats = await fs.stat(nodeModulesPath); - packageJsonNewer = packageStats.mtime > nodeModulesStats.mtime; - } catch { - // If stat fails, assume we need to install - packageJsonNewer = true; - } - - if (packageJsonNewer) { - const installSpinner = await createSpinner(); - installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`); - try { - execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', { - cwd: moduleCacheDir, - stdio: ['ignore', 'pipe', 'pipe'], - timeout: 120_000, // 2 minute timeout - }); - installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`); - } catch (error) { - installSpinner.error(`Failed to install dependencies for ${moduleInfo.name}`); - if (!silent) await prompts.log.warn(` ${error.message}`); - } - } - } - } - - return moduleCacheDir; - } - - /** - * Find the source path for an external module - * @param {string} moduleCode - Code of the external module - * @returns {string|null} Path to the module source or null if not found - */ - async findExternalModuleSource(moduleCode, options = {}) { - const moduleInfo = await this.externalModuleManager.getModuleByCode(moduleCode); - - if (!moduleInfo) { - return null; - } - - // Clone the external module repo - const cloneDir = await this.cloneExternalModule(moduleCode, options); - - // The module-definition specifies the path to module.yaml relative to repo root - // We need to return the directory containing module.yaml - const moduleDefinitionPath = moduleInfo.moduleDefinition; // e.g., 'src/module.yaml' - const moduleDir = path.dirname(path.join(cloneDir, moduleDefinitionPath)); - - return moduleDir; - } - - /** - * Install a module - * @param {string} moduleName - Code of the module to install (from module.yaml) - * @param {string} bmadDir - Target bmad directory - * @param {Function} fileTrackingCallback - Optional callback to track installed files - * @param {Object} options - Additional installation options - * @param {Array} options.installedIDEs - Array of IDE codes that were installed - * @param {Object} options.moduleConfig - Module configuration from config collector - * @param {Object} options.logger - Logger instance for output - */ - async install(moduleName, bmadDir, fileTrackingCallback = null, options = {}) { - const sourcePath = await this.findModuleSource(moduleName, { silent: options.silent }); - const targetPath = path.join(bmadDir, moduleName); - - // Check if source module exists - if (!sourcePath) { - // Provide a more user-friendly error message - throw new Error( - `Source for module '${moduleName}' is not available. It will be retained but cannot be updated without its source files.`, - ); - } - - // Check if this is a custom module and read its custom.yaml values - let customConfig = null; - const rootCustomConfigPath = path.join(sourcePath, 'custom.yaml'); - - if (await fs.pathExists(rootCustomConfigPath)) { - try { - const customContent = await fs.readFile(rootCustomConfigPath, 'utf8'); - customConfig = yaml.parse(customContent); - } catch (error) { - await prompts.log.warn(`Failed to read custom.yaml for ${moduleName}: ${error.message}`); - } - } - - // If this is a custom module, merge its values into the module config - if (customConfig) { - options.moduleConfig = { ...options.moduleConfig, ...customConfig }; - if (options.logger) { - await options.logger.log(` Merged custom configuration for ${moduleName}`); - } - } - - // Check if already installed - if (await fs.pathExists(targetPath)) { - await fs.remove(targetPath); - } - - // Copy module files with filtering - await this.copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback, options.moduleConfig); - - // Create directories declared in module.yaml (unless explicitly skipped) - if (!options.skipModuleInstaller) { - await this.createModuleDirectories(moduleName, bmadDir, options); - } - - // Capture version info for manifest - const { Manifest } = require('../core/manifest'); - const manifestObj = new Manifest(); - const versionInfo = await manifestObj.getModuleVersionInfo(moduleName, bmadDir, sourcePath); - - await manifestObj.addModule(bmadDir, moduleName, { - version: versionInfo.version, - source: versionInfo.source, - npmPackage: versionInfo.npmPackage, - repoUrl: versionInfo.repoUrl, - }); - - return { - success: true, - module: moduleName, - path: targetPath, - versionInfo, - }; - } - - /** - * Update an existing module - * @param {string} moduleName - Name of the module to update - * @param {string} bmadDir - Target bmad directory - * @param {boolean} force - Force update (overwrite modifications) - */ - async update(moduleName, bmadDir, force = false, options = {}) { - const sourcePath = await this.findModuleSource(moduleName); - const targetPath = path.join(bmadDir, moduleName); - - // Check if source module exists - if (!sourcePath) { - throw new Error(`Module '${moduleName}' not found in any source location`); - } - - // Check if module is installed - if (!(await fs.pathExists(targetPath))) { - throw new Error(`Module '${moduleName}' is not installed`); - } - - if (force) { - // Force update - remove and reinstall - await fs.remove(targetPath); - return await this.install(moduleName, bmadDir, null, { installer: options.installer }); - } else { - // Selective update - preserve user modifications - await this.syncModule(sourcePath, targetPath); - } - - return { - success: true, - module: moduleName, - path: targetPath, - }; - } - - /** - * Remove a module - * @param {string} moduleName - Name of the module to remove - * @param {string} bmadDir - Target bmad directory - */ - async remove(moduleName, bmadDir) { - const targetPath = path.join(bmadDir, moduleName); - - if (!(await fs.pathExists(targetPath))) { - throw new Error(`Module '${moduleName}' is not installed`); - } - - await fs.remove(targetPath); - - return { - success: true, - module: moduleName, - }; - } - - /** - * Check if a module is installed - * @param {string} moduleName - Name of the module - * @param {string} bmadDir - Target bmad directory - * @returns {boolean} True if module is installed - */ - async isInstalled(moduleName, bmadDir) { - const targetPath = path.join(bmadDir, moduleName); - return await fs.pathExists(targetPath); - } - - /** - * Get installed module info - * @param {string} moduleName - Name of the module - * @param {string} bmadDir - Target bmad directory - * @returns {Object|null} Module info or null if not installed - */ - async getInstalledInfo(moduleName, bmadDir) { - const targetPath = path.join(bmadDir, moduleName); - - if (!(await fs.pathExists(targetPath))) { - return null; - } - - const configPath = path.join(targetPath, 'config.yaml'); - const moduleInfo = { - id: moduleName, - path: targetPath, - installed: true, - }; - - if (await fs.pathExists(configPath)) { - try { - const configContent = await fs.readFile(configPath, 'utf8'); - const config = yaml.parse(configContent); - Object.assign(moduleInfo, config); - } catch (error) { - await prompts.log.warn(`Failed to read installed module config: ${error.message}`); - } - } - - return moduleInfo; - } - - /** - * Copy module with filtering for localskip agents and conditional content - * @param {string} sourcePath - Source module path - * @param {string} targetPath - Target module path - * @param {Function} fileTrackingCallback - Optional callback to track installed files - * @param {Object} moduleConfig - Module configuration with conditional flags - */ - async copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback = null, moduleConfig = {}) { - // Get all files in source - const sourceFiles = await this.getFileList(sourcePath); - - for (const file of sourceFiles) { - // Skip sub-modules directory - these are IDE-specific and handled separately - if (file.startsWith('sub-modules/')) { - continue; - } - - // Skip sidecar directories - these contain agent-specific assets not needed at install time - const isInSidecarDirectory = path - .dirname(file) - .split('/') - .some((dir) => dir.toLowerCase().endsWith('-sidecar')); - - if (isInSidecarDirectory) { - continue; - } - - // Skip module.yaml at root - it's only needed at install time - if (file === 'module.yaml') { - continue; - } - - // Skip module root config.yaml only - generated by config collector with actual values - // Workflow-level config.yaml (e.g. workflows/orchestrate-story/config.yaml) must be copied - // for custom modules that use workflow-specific configuration - if (file === 'config.yaml') { - continue; - } - - const sourceFile = path.join(sourcePath, file); - const targetFile = path.join(targetPath, file); - - // Check if this is an agent file - if (file.startsWith('agents/') && file.endsWith('.md')) { - // Read the file to check for localskip - const content = await fs.readFile(sourceFile, 'utf8'); - - // Check for localskip="true" in the agent tag - const agentMatch = content.match(/]*\slocalskip="true"[^>]*>/); - if (agentMatch) { - await prompts.log.message(` Skipping web-only agent: ${path.basename(file)}`); - continue; // Skip this agent - } - } - - // Copy the file with placeholder replacement - await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile); - - // Track the file if callback provided - if (fileTrackingCallback) { - fileTrackingCallback(targetFile); - } - } - } - - /** - * Find all .md agent files recursively in a directory - * @param {string} dir - Directory to search - * @returns {Array} List of .md agent file paths - */ - async findAgentMdFiles(dir) { - const agentFiles = []; - - async function searchDirectory(searchDir) { - const entries = await fs.readdir(searchDir, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = path.join(searchDir, entry.name); - - if (entry.isFile() && entry.name.endsWith('.md')) { - agentFiles.push(fullPath); - } else if (entry.isDirectory()) { - await searchDirectory(fullPath); - } - } - } - - await searchDirectory(dir); - return agentFiles; - } - - /** - * Create directories declared in module.yaml's `directories` key - * This replaces the security-risky module installer pattern with declarative config - * During updates, if a directory path changed, moves the old directory to the new path - * @param {string} moduleName - Name of the module - * @param {string} bmadDir - Target bmad directory - * @param {Object} options - Installation options - * @param {Object} options.moduleConfig - Module configuration from config collector - * @param {Object} options.existingModuleConfig - Previous module config (for detecting path changes during updates) - * @param {Object} options.coreConfig - Core configuration - * @returns {Promise<{createdDirs: string[], movedDirs: string[], createdWdsFolders: string[]}>} Created directories info - */ - async createModuleDirectories(moduleName, bmadDir, options = {}) { - const moduleConfig = options.moduleConfig || {}; - const existingModuleConfig = options.existingModuleConfig || {}; - const projectRoot = path.dirname(bmadDir); - const emptyResult = { createdDirs: [], movedDirs: [], createdWdsFolders: [] }; - - // Special handling for core module - it's in src/core-skills not src/modules - let sourcePath; - if (moduleName === 'core') { - sourcePath = getSourcePath('core-skills'); - } else { - sourcePath = await this.findModuleSource(moduleName, { silent: true }); - if (!sourcePath) { - return emptyResult; // No source found, skip - } - } - - // Read module.yaml to find the `directories` key - const moduleYamlPath = path.join(sourcePath, 'module.yaml'); - if (!(await fs.pathExists(moduleYamlPath))) { - return emptyResult; // No module.yaml, skip - } - - let moduleYaml; - try { - const yamlContent = await fs.readFile(moduleYamlPath, 'utf8'); - moduleYaml = yaml.parse(yamlContent); - } catch { - return emptyResult; // Invalid YAML, skip - } - - if (!moduleYaml || !moduleYaml.directories) { - return emptyResult; // No directories declared, skip - } - - const directories = moduleYaml.directories; - const wdsFolders = moduleYaml.wds_folders || []; - const createdDirs = []; - const movedDirs = []; - const createdWdsFolders = []; - - for (const dirRef of directories) { - // Parse variable reference like "{design_artifacts}" - const varMatch = dirRef.match(/^\{([^}]+)\}$/); - if (!varMatch) { - // Not a variable reference, skip - continue; - } - - const configKey = varMatch[1]; - const dirValue = moduleConfig[configKey]; - if (!dirValue || typeof dirValue !== 'string') { - continue; // No value or not a string, skip - } - - // Strip {project-root}/ prefix if present - let dirPath = dirValue.replace(/^\{project-root\}\/?/, ''); - - // Handle remaining {project-root} anywhere in the path - dirPath = dirPath.replaceAll('{project-root}', ''); - - // Resolve to absolute path - const fullPath = path.join(projectRoot, dirPath); - - // Validate path is within project root (prevent directory traversal) - const normalizedPath = path.normalize(fullPath); - const normalizedRoot = path.normalize(projectRoot); - if (!normalizedPath.startsWith(normalizedRoot + path.sep) && normalizedPath !== normalizedRoot) { - const color = await prompts.getColor(); - await prompts.log.warn(color.yellow(`${configKey} path escapes project root, skipping: ${dirPath}`)); - continue; - } - - // Check if directory path changed from previous config (update/modify scenario) - const oldDirValue = existingModuleConfig[configKey]; - let oldFullPath = null; - let oldDirPath = null; - if (oldDirValue && typeof oldDirValue === 'string') { - // F3: Normalize both values before comparing to avoid false negatives - // from trailing slashes, separator differences, or prefix format variations - let normalizedOld = oldDirValue.replace(/^\{project-root\}\/?/, ''); - normalizedOld = path.normalize(normalizedOld.replaceAll('{project-root}', '')); - const normalizedNew = path.normalize(dirPath); - - if (normalizedOld !== normalizedNew) { - oldDirPath = normalizedOld; - oldFullPath = path.join(projectRoot, oldDirPath); - const normalizedOldAbsolute = path.normalize(oldFullPath); - if (!normalizedOldAbsolute.startsWith(normalizedRoot + path.sep) && normalizedOldAbsolute !== normalizedRoot) { - oldFullPath = null; // Old path escapes project root, ignore it - } - - // F13: Prevent parent/child move (e.g. docs/planning → docs/planning/v2) - if (oldFullPath) { - const normalizedNewAbsolute = path.normalize(fullPath); - if ( - normalizedOldAbsolute.startsWith(normalizedNewAbsolute + path.sep) || - normalizedNewAbsolute.startsWith(normalizedOldAbsolute + path.sep) - ) { - const color = await prompts.getColor(); - await prompts.log.warn( - color.yellow( - `${configKey}: cannot move between parent/child paths (${oldDirPath} / ${dirPath}), creating new directory instead`, - ), - ); - oldFullPath = null; - } - } - } - } - - const dirName = configKey.replaceAll('_', ' '); - - if (oldFullPath && (await fs.pathExists(oldFullPath)) && !(await fs.pathExists(fullPath))) { - // Path changed and old dir exists → move old to new location - // F1: Use fs.move() instead of fs.rename() for cross-device/volume support - // F2: Wrap in try/catch — fallback to creating new dir on failure - try { - await fs.ensureDir(path.dirname(fullPath)); - await fs.move(oldFullPath, fullPath); - movedDirs.push(`${dirName}: ${oldDirPath} → ${dirPath}`); - } catch (moveError) { - const color = await prompts.getColor(); - await prompts.log.warn( - color.yellow( - `Failed to move ${oldDirPath} → ${dirPath}: ${moveError.message}\n Creating new directory instead. Please move contents from the old directory manually.`, - ), - ); - await fs.ensureDir(fullPath); - createdDirs.push(`${dirName}: ${dirPath}`); - } - } else if (oldFullPath && (await fs.pathExists(oldFullPath)) && (await fs.pathExists(fullPath))) { - // F5: Both old and new directories exist — warn user about potential orphaned documents - const color = await prompts.getColor(); - await prompts.log.warn( - color.yellow( - `${dirName}: path changed but both directories exist:\n Old: ${oldDirPath}\n New: ${dirPath}\n Old directory may contain orphaned documents — please review and merge manually.`, - ), - ); - } else if (!(await fs.pathExists(fullPath))) { - // New directory doesn't exist yet → create it - createdDirs.push(`${dirName}: ${dirPath}`); - await fs.ensureDir(fullPath); - } - - // Create WDS subfolders if this is the design_artifacts directory - if (configKey === 'design_artifacts' && wdsFolders.length > 0) { - for (const subfolder of wdsFolders) { - const subPath = path.join(fullPath, subfolder); - if (!(await fs.pathExists(subPath))) { - await fs.ensureDir(subPath); - createdWdsFolders.push(subfolder); - } - } - } - } - - return { createdDirs, movedDirs, createdWdsFolders }; - } - - /** - * Private: Process module configuration - * @param {string} modulePath - Path to installed module - * @param {string} moduleName - Module name - */ - async processModuleConfig(modulePath, moduleName) { - const configPath = path.join(modulePath, 'config.yaml'); - - if (await fs.pathExists(configPath)) { - try { - let configContent = await fs.readFile(configPath, 'utf8'); - - // Replace path placeholders - configContent = configContent.replaceAll('{project-root}', `bmad/${moduleName}`); - configContent = configContent.replaceAll('{module}', moduleName); - - await fs.writeFile(configPath, configContent, 'utf8'); - } catch (error) { - await prompts.log.warn(`Failed to process module config: ${error.message}`); - } - } - } - - /** - * Private: Sync module files (preserving user modifications) - * @param {string} sourcePath - Source module path - * @param {string} targetPath - Target module path - */ - async syncModule(sourcePath, targetPath) { - // Get list of all source files - const sourceFiles = await this.getFileList(sourcePath); - - for (const file of sourceFiles) { - const sourceFile = path.join(sourcePath, file); - const targetFile = path.join(targetPath, file); - - // Check if target file exists and has been modified - if (await fs.pathExists(targetFile)) { - const sourceStats = await fs.stat(sourceFile); - const targetStats = await fs.stat(targetFile); - - // Skip if target is newer (user modified) - if (targetStats.mtime > sourceStats.mtime) { - continue; - } - } - - // Copy file with placeholder replacement - await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile); - } - } - - /** - * Private: Get list of all files in a directory - * @param {string} dir - Directory path - * @param {string} baseDir - Base directory for relative paths - * @returns {Array} List of relative file paths - */ - async getFileList(dir, baseDir = dir) { - const files = []; - const entries = await fs.readdir(dir, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - - if (entry.isDirectory()) { - const subFiles = await this.getFileList(fullPath, baseDir); - files.push(...subFiles); - } else { - files.push(path.relative(baseDir, fullPath)); - } - } - - return files; - } -} - -module.exports = { ModuleManager }; diff --git a/tools/cli/lib/cli-utils.js b/tools/cli/lib/cli-utils.js deleted file mode 100644 index 569f1c44c..000000000 --- a/tools/cli/lib/cli-utils.js +++ /dev/null @@ -1,182 +0,0 @@ -const path = require('node:path'); -const os = require('node:os'); -const prompts = require('./prompts'); - -const CLIUtils = { - /** - * Get version from package.json - */ - getVersion() { - try { - const packageJson = require(path.join(__dirname, '..', '..', '..', 'package.json')); - return packageJson.version || 'Unknown'; - } catch { - return 'Unknown'; - } - }, - - /** - * Display BMAD logo using @clack intro + box - * @param {boolean} _clearScreen - Deprecated, ignored (no longer clears screen) - */ - async displayLogo(_clearScreen = true) { - const version = this.getVersion(); - const color = await prompts.getColor(); - - // ASCII art logo - const logo = [ - ' ██████╗ ███╗ ███╗ █████╗ ██████╗ ™', - ' ██╔══██╗████╗ ████║██╔══██╗██╔══██╗', - ' ██████╔╝██╔████╔██║███████║██║ ██║', - ' ██╔══██╗██║╚██╔╝██║██╔══██║██║ ██║', - ' ██████╔╝██║ ╚═╝ ██║██║ ██║██████╔╝', - ' ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝', - ] - .map((line) => color.yellow(line)) - .join('\n'); - - const tagline = ' Build More, Architect Dreams'; - - await prompts.box(`${logo}\n${tagline}`, `v${version}`, { - contentAlign: 'center', - rounded: true, - formatBorder: color.blue, - }); - }, - - /** - * Display section header - * @param {string} title - Section title - * @param {string} subtitle - Optional subtitle - */ - async displaySection(title, subtitle = null) { - await prompts.note(subtitle || '', title); - }, - - /** - * Display info box - * @param {string|Array} content - Content to display - * @param {Object} options - Box options - */ - async displayBox(content, options = {}) { - let text = content; - if (Array.isArray(content)) { - text = content.join('\n\n'); - } - - const color = await prompts.getColor(); - const borderColor = options.borderColor || 'cyan'; - const colorMap = { green: color.green, red: color.red, yellow: color.yellow, cyan: color.cyan, blue: color.blue }; - const formatBorder = colorMap[borderColor] || color.cyan; - - await prompts.box(text, options.title, { - rounded: options.borderStyle === 'round' || options.borderStyle === undefined, - formatBorder, - }); - }, - - /** - * Display module configuration header - * @param {string} moduleName - Module name (fallback if no custom header) - * @param {string} header - Custom header from module.yaml - * @param {string} subheader - Custom subheader from module.yaml - */ - async displayModuleConfigHeader(moduleName, header = null, subheader = null) { - const title = header || `Configuring ${moduleName.toUpperCase()} Module`; - await prompts.note(subheader || '', title); - }, - - /** - * Display module with no custom configuration - * @param {string} moduleName - Module name (fallback if no custom header) - * @param {string} header - Custom header from module.yaml - * @param {string} subheader - Custom subheader from module.yaml - */ - async displayModuleNoConfig(moduleName, header = null, subheader = null) { - const title = header || `${moduleName.toUpperCase()} Module - No Custom Configuration`; - await prompts.note(subheader || '', title); - }, - - /** - * Display step indicator - * @param {number} current - Current step - * @param {number} total - Total steps - * @param {string} description - Step description - */ - async displayStep(current, total, description) { - const progress = `[${current}/${total}]`; - await prompts.log.step(`${progress} ${description}`); - }, - - /** - * Display completion message - * @param {string} message - Completion message - */ - async displayComplete(message) { - const color = await prompts.getColor(); - await prompts.box(`\u2728 ${message}`, 'Complete', { - rounded: true, - formatBorder: color.green, - }); - }, - - /** - * Display error message - * @param {string} message - Error message - */ - async displayError(message) { - const color = await prompts.getColor(); - await prompts.box(`\u2717 ${message}`, 'Error', { - rounded: true, - formatBorder: color.red, - }); - }, - - /** - * Format list for display - * @param {Array} items - Items to display - * @param {string} prefix - Item prefix - */ - formatList(items, prefix = '\u2022') { - return items.map((item) => ` ${prefix} ${item}`).join('\n'); - }, - - /** - * Clear previous lines - * @param {number} lines - Number of lines to clear - */ - clearLines(lines) { - for (let i = 0; i < lines; i++) { - process.stdout.moveCursor(0, -1); - process.stdout.clearLine(1); - } - }, - - /** - * Display module completion message - * @param {string} moduleName - Name of the completed module - * @param {boolean} clearScreen - Whether to clear the screen first (deprecated, always false now) - */ - displayModuleComplete(moduleName, clearScreen = false) { - // No longer clear screen or show boxes - just a simple completion message - // This is deprecated but kept for backwards compatibility - }, - - /** - * Expand path with ~ expansion - * @param {string} inputPath - Path to expand - * @returns {string} Expanded path - */ - expandPath(inputPath) { - if (!inputPath) return inputPath; - - // Expand ~ to home directory - if (inputPath.startsWith('~')) { - return path.join(os.homedir(), inputPath.slice(1)); - } - - return inputPath; - }, -}; - -module.exports = { CLIUtils }; diff --git a/tools/cli/lib/config.js b/tools/cli/lib/config.js deleted file mode 100644 index a78250305..000000000 --- a/tools/cli/lib/config.js +++ /dev/null @@ -1,213 +0,0 @@ -const fs = require('fs-extra'); -const yaml = require('yaml'); -const path = require('node:path'); -const packageJson = require('../../../package.json'); - -/** - * Configuration utility class - */ -class Config { - /** - * Load a YAML configuration file - * @param {string} configPath - Path to config file - * @returns {Object} Parsed configuration - */ - async loadYaml(configPath) { - if (!(await fs.pathExists(configPath))) { - throw new Error(`Configuration file not found: ${configPath}`); - } - - const content = await fs.readFile(configPath, 'utf8'); - return yaml.parse(content); - } - - /** - * Save configuration to YAML file - * @param {string} configPath - Path to config file - * @param {Object} config - Configuration object - */ - async saveYaml(configPath, config) { - const yamlContent = yaml.dump(config, { - indent: 2, - lineWidth: 120, - noRefs: true, - }); - - await fs.ensureDir(path.dirname(configPath)); - // Ensure POSIX-compliant final newline - const content = yamlContent.endsWith('\n') ? yamlContent : yamlContent + '\n'; - await fs.writeFile(configPath, content, 'utf8'); - } - - /** - * Process configuration file (replace placeholders) - * @param {string} configPath - Path to config file - * @param {Object} replacements - Replacement values - */ - async processConfig(configPath, replacements = {}) { - let content = await fs.readFile(configPath, 'utf8'); - - // Standard replacements - const standardReplacements = { - '{project-root}': replacements.root || '', - '{module}': replacements.module || '', - '{version}': replacements.version || packageJson.version, - '{date}': new Date().toISOString().split('T')[0], - }; - - // Apply all replacements - const allReplacements = { ...standardReplacements, ...replacements }; - - for (const [placeholder, value] of Object.entries(allReplacements)) { - if (typeof placeholder === 'string' && typeof value === 'string') { - const regex = new RegExp(placeholder.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`), 'g'); - content = content.replace(regex, value); - } - } - - await fs.writeFile(configPath, content, 'utf8'); - } - - /** - * Merge configurations - * @param {Object} base - Base configuration - * @param {Object} override - Override configuration - * @returns {Object} Merged configuration - */ - mergeConfigs(base, override) { - return this.deepMerge(base, override); - } - - /** - * Deep merge two objects - * @param {Object} target - Target object - * @param {Object} source - Source object - * @returns {Object} Merged object - */ - deepMerge(target, source) { - const output = { ...target }; - - if (this.isObject(target) && this.isObject(source)) { - for (const key of Object.keys(source)) { - if (this.isObject(source[key])) { - if (key in target) { - output[key] = this.deepMerge(target[key], source[key]); - } else { - output[key] = source[key]; - } - } else { - output[key] = source[key]; - } - } - } - - return output; - } - - /** - * Check if value is an object - * @param {*} item - Item to check - * @returns {boolean} True if object - */ - isObject(item) { - return item && typeof item === 'object' && !Array.isArray(item); - } - - /** - * Validate configuration against schema - * @param {Object} config - Configuration to validate - * @param {Object} schema - Validation schema - * @returns {Object} Validation result - */ - validateConfig(config, schema) { - const errors = []; - const warnings = []; - - // Check required fields - if (schema.required) { - for (const field of schema.required) { - if (!(field in config)) { - errors.push(`Missing required field: ${field}`); - } - } - } - - // Check field types - if (schema.properties) { - for (const [field, spec] of Object.entries(schema.properties)) { - if (field in config) { - const value = config[field]; - const expectedType = spec.type; - - if (expectedType === 'array' && !Array.isArray(value)) { - errors.push(`Field '${field}' should be an array`); - } else if (expectedType === 'object' && !this.isObject(value)) { - errors.push(`Field '${field}' should be an object`); - } else if (expectedType === 'string' && typeof value !== 'string') { - errors.push(`Field '${field}' should be a string`); - } else if (expectedType === 'number' && typeof value !== 'number') { - errors.push(`Field '${field}' should be a number`); - } else if (expectedType === 'boolean' && typeof value !== 'boolean') { - errors.push(`Field '${field}' should be a boolean`); - } - - // Check enum values - if (spec.enum && !spec.enum.includes(value)) { - errors.push(`Field '${field}' must be one of: ${spec.enum.join(', ')}`); - } - } - } - } - - return { - valid: errors.length === 0, - errors, - warnings, - }; - } - - /** - * Get configuration value with fallback - * @param {Object} config - Configuration object - * @param {string} path - Dot-notation path to value - * @param {*} defaultValue - Default value if not found - * @returns {*} Configuration value - */ - getValue(config, path, defaultValue = null) { - const keys = path.split('.'); - let current = config; - - for (const key of keys) { - if (current && typeof current === 'object' && key in current) { - current = current[key]; - } else { - return defaultValue; - } - } - - return current; - } - - /** - * Set configuration value - * @param {Object} config - Configuration object - * @param {string} path - Dot-notation path to value - * @param {*} value - Value to set - */ - setValue(config, path, value) { - const keys = path.split('.'); - const lastKey = keys.pop(); - let current = config; - - for (const key of keys) { - if (!(key in current) || typeof current[key] !== 'object') { - current[key] = {}; - } - current = current[key]; - } - - current[lastKey] = value; - } -} - -module.exports = { Config }; diff --git a/tools/cli/lib/platform-codes.js b/tools/cli/lib/platform-codes.js deleted file mode 100644 index bdf0e48c9..000000000 --- a/tools/cli/lib/platform-codes.js +++ /dev/null @@ -1,116 +0,0 @@ -const fs = require('fs-extra'); -const path = require('node:path'); -const yaml = require('yaml'); -const { getProjectRoot } = require('./project-root'); - -/** - * Platform Codes Manager - * Loads and provides access to the centralized platform codes configuration - */ -class PlatformCodes { - constructor() { - this.configPath = path.join(getProjectRoot(), 'tools', 'platform-codes.yaml'); - this.loadConfig(); - } - - /** - * Load the platform codes configuration - */ - loadConfig() { - try { - if (fs.existsSync(this.configPath)) { - const content = fs.readFileSync(this.configPath, 'utf8'); - this.config = yaml.parse(content); - } else { - console.warn(`Platform codes config not found at ${this.configPath}`); - this.config = { platforms: {} }; - } - } catch (error) { - console.error(`Error loading platform codes: ${error.message}`); - this.config = { platforms: {} }; - } - } - - /** - * Get all platform codes - * @returns {Object} All platform configurations - */ - getAllPlatforms() { - return this.config.platforms || {}; - } - - /** - * Get a specific platform configuration - * @param {string} code - Platform code - * @returns {Object|null} Platform configuration or null if not found - */ - getPlatform(code) { - return this.config.platforms[code] || null; - } - - /** - * Check if a platform code is valid - * @param {string} code - Platform code to validate - * @returns {boolean} True if valid - */ - isValidPlatform(code) { - return code in this.config.platforms; - } - - /** - * Get all preferred platforms - * @returns {Array} Array of preferred platform codes - */ - getPreferredPlatforms() { - return Object.entries(this.config.platforms) - .filter(([, config]) => config.preferred) - .map(([code]) => code); - } - - /** - * Get platforms by category - * @param {string} category - Category to filter by - * @returns {Array} Array of platform codes in the category - */ - getPlatformsByCategory(category) { - return Object.entries(this.config.platforms) - .filter(([, config]) => config.category === category) - .map(([code]) => code); - } - - /** - * Get platform display name - * @param {string} code - Platform code - * @returns {string} Display name or code if not found - */ - getDisplayName(code) { - const platform = this.getPlatform(code); - return platform ? platform.name : code; - } - - /** - * Validate platform code format - * @param {string} code - Platform code to validate - * @returns {boolean} True if format is valid - */ - isValidFormat(code) { - const conventions = this.config.conventions || {}; - const pattern = conventions.allowed_characters || 'a-z0-9-'; - const maxLength = conventions.max_code_length || 20; - - const regex = new RegExp(`^[${pattern}]+$`); - return regex.test(code) && code.length <= maxLength; - } - - /** - * Get all platform codes as array - * @returns {Array} Array of platform codes - */ - getCodes() { - return Object.keys(this.config.platforms); - } - config = null; -} - -// Export singleton instance -module.exports = new PlatformCodes(); diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js deleted file mode 100644 index 3f25dae03..000000000 --- a/tools/cli/lib/ui.js +++ /dev/null @@ -1,1917 +0,0 @@ -const path = require('node:path'); -const os = require('node:os'); -const fs = require('fs-extra'); -const { CLIUtils } = require('./cli-utils'); -const { CustomHandler } = require('../installers/lib/custom/handler'); -const { ExternalModuleManager } = require('../installers/lib/modules/external-manager'); -const prompts = require('./prompts'); - -// Separator class for visual grouping in select/multiselect prompts -// Note: @clack/prompts doesn't support separators natively, they are filtered out -class Separator { - constructor(text = '────────') { - this.line = text; - this.name = text; - } - type = 'separator'; -} - -// Separator for choice lists (compatible interface) -const choiceUtils = { Separator }; - -/** - * UI utilities for the installer - */ -class UI { - /** - * Prompt for installation configuration - * @param {Object} options - Command-line options from install command - * @returns {Object} Installation configuration - */ - async promptInstall(options = {}) { - await CLIUtils.displayLogo(); - - // Display version-specific start message from install-messages.yaml - const { MessageLoader } = require('../installers/lib/message-loader'); - const messageLoader = new MessageLoader(); - await messageLoader.displayStartMessage(); - - // Get directory from options or prompt - let confirmedDirectory; - if (options.directory) { - // Use provided directory from command-line - const expandedDir = this.expandUserPath(options.directory); - const validation = this.validateDirectorySync(expandedDir); - if (validation) { - throw new Error(`Invalid directory: ${validation}`); - } - confirmedDirectory = expandedDir; - await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`); - } else { - confirmedDirectory = await this.getConfirmedDirectory(); - } - - // Preflight: Check for legacy BMAD v4 footprints immediately after getting directory - const { Detector } = require('../installers/lib/core/detector'); - const { Installer } = require('../installers/lib/core/installer'); - const detector = new Detector(); - const installer = new Installer(); - const legacyV4 = await detector.detectLegacyV4(confirmedDirectory); - if (legacyV4.hasLegacyV4) { - await installer.handleLegacyV4Migration(confirmedDirectory, legacyV4); - } - - // Check for legacy folders and prompt for rename before showing any menus - let hasLegacyCfg = false; - let hasLegacyBmadFolder = false; - let bmadDir = null; - let legacyBmadPath = null; - - // First check for legacy .bmad folder (instead of _bmad) - // Only check if directory exists - if (await fs.pathExists(confirmedDirectory)) { - const entries = await fs.readdir(confirmedDirectory, { withFileTypes: true }); - for (const entry of entries) { - if (entry.isDirectory() && (entry.name === '.bmad' || entry.name === 'bmad')) { - hasLegacyBmadFolder = true; - legacyBmadPath = path.join(confirmedDirectory, entry.name); - bmadDir = legacyBmadPath; - - // Check if it has _cfg folder - const cfgPath = path.join(legacyBmadPath, '_cfg'); - if (await fs.pathExists(cfgPath)) { - hasLegacyCfg = true; - } - break; - } - } - } - - // If no .bmad or bmad found, check for current installations _bmad - if (!hasLegacyBmadFolder) { - const bmadResult = await installer.findBmadDir(confirmedDirectory); - bmadDir = bmadResult.bmadDir; - hasLegacyCfg = bmadResult.hasLegacyCfg; - } - - // Handle legacy .bmad or _cfg folder - these are very old (v4 or alpha) - // Show version warning instead of offering conversion - if (hasLegacyBmadFolder || hasLegacyCfg) { - await prompts.log.warn('LEGACY INSTALLATION DETECTED'); - await prompts.note( - 'Found a ".bmad"/"bmad" folder, or a legacy "_cfg" folder under the bmad folder -\n' + - 'this is from an old BMAD version that is out of date for automatic upgrade,\n' + - 'manual intervention required.\n\n' + - 'You have a legacy version installed (v4 or alpha).\n' + - 'Legacy installations may have compatibility issues.\n\n' + - 'For the best experience, we strongly recommend:\n' + - ' 1. Delete your current BMAD installation folder (.bmad or bmad)\n' + - ' 2. Run a fresh installation\n\n' + - 'If you do not want to start fresh, you can attempt to proceed beyond this\n' + - 'point IF you have ensured the bmad folder is named _bmad, and under it there\n' + - 'is a _config folder. If you have a folder under your bmad folder named _cfg,\n' + - 'you would need to rename it _config, and then restart the installer.\n\n' + - 'Benefits of a fresh install:\n' + - ' \u2022 Cleaner configuration without legacy artifacts\n' + - ' \u2022 All new features properly configured\n' + - ' \u2022 Fewer potential conflicts\n\n' + - 'If you have already produced output from an earlier alpha version, you can\n' + - 'still retain those artifacts. After installation, ensure you configured during\n' + - 'install the proper file locations for artifacts depending on the module you\n' + - 'are using, or move the files to the proper locations.', - 'Legacy Installation Detected', - ); - - const proceed = await prompts.select({ - message: 'How would you like to proceed?', - choices: [ - { - name: 'Cancel and do a fresh install (recommended)', - value: 'cancel', - }, - { - name: 'Proceed anyway (will attempt update, potentially may fail or have unstable behavior)', - value: 'proceed', - }, - ], - default: 'cancel', - }); - - if (proceed === 'cancel') { - await prompts.note('1. Delete the existing bmad folder in your project\n' + "2. Run 'bmad install' again", 'To do a fresh install'); - process.exit(0); - return; - } - - const s = await prompts.spinner(); - s.start('Updating folder structure...'); - try { - // Handle .bmad folder - if (hasLegacyBmadFolder) { - const newBmadPath = path.join(confirmedDirectory, '_bmad'); - await fs.move(legacyBmadPath, newBmadPath); - bmadDir = newBmadPath; - s.stop(`Renamed "${path.basename(legacyBmadPath)}" to "_bmad"`); - } - - // Handle _cfg folder (either from .bmad or standalone) - const cfgPath = path.join(bmadDir, '_cfg'); - if (await fs.pathExists(cfgPath)) { - s.start('Renaming configuration folder...'); - const newCfgPath = path.join(bmadDir, '_config'); - await fs.move(cfgPath, newCfgPath); - s.stop('Renamed "_cfg" to "_config"'); - } - } catch (error) { - s.stop('Failed to update folder structure'); - await prompts.log.error(`Error: ${error.message}`); - process.exit(1); - } - } - - // Check if there's an existing BMAD installation (after any folder renames) - const hasExistingInstall = await fs.pathExists(bmadDir); - - let customContentConfig = { hasCustomContent: false }; - if (!hasExistingInstall) { - customContentConfig._shouldAsk = true; - } - - // Track action type (only set if there's an existing installation) - let actionType; - - // Only show action menu if there's an existing installation - if (hasExistingInstall) { - // Get version information - const { existingInstall, bmadDir } = await this.getExistingInstallation(confirmedDirectory); - const packageJsonPath = path.join(__dirname, '../../../package.json'); - const currentVersion = require(packageJsonPath).version; - const installedVersion = existingInstall.version || 'unknown'; - - // Check if version is pre beta - const shouldProceed = await this.showLegacyVersionWarning(installedVersion, currentVersion, path.basename(bmadDir), options); - - // If user chose to cancel, exit the installer - if (!shouldProceed) { - process.exit(0); - return; - } - - // Build menu choices dynamically - const choices = []; - - // Always show Quick Update first (allows refreshing installation even on same version) - if (installedVersion !== 'unknown') { - choices.push({ - name: `Quick Update (v${installedVersion} → v${currentVersion})`, - value: 'quick-update', - }); - } - - // Common actions - choices.push({ name: 'Modify BMAD Installation', value: 'update' }); - - // Check if action is provided via command-line - if (options.action) { - const validActions = choices.map((c) => c.value); - if (!validActions.includes(options.action)) { - throw new Error(`Invalid action: ${options.action}. Valid actions: ${validActions.join(', ')}`); - } - actionType = options.action; - await prompts.log.info(`Using action from command-line: ${actionType}`); - } else if (options.yes) { - // Default to quick-update if available, otherwise first available choice - if (choices.length === 0) { - throw new Error('No valid actions available for this installation'); - } - const hasQuickUpdate = choices.some((c) => c.value === 'quick-update'); - actionType = hasQuickUpdate ? 'quick-update' : choices[0].value; - await prompts.log.info(`Non-interactive mode (--yes): defaulting to ${actionType}`); - } else { - actionType = await prompts.select({ - message: 'How would you like to proceed?', - choices: choices, - default: choices[0].value, - }); - } - - // Handle quick update separately - if (actionType === 'quick-update') { - // Pass --custom-content through so installer can re-cache if cache is missing - let customContentForQuickUpdate = { hasCustomContent: false }; - if (options.customContent) { - const paths = options.customContent - .split(',') - .map((p) => p.trim()) - .filter(Boolean); - if (paths.length > 0) { - const customPaths = []; - const selectedModuleIds = []; - const sources = []; - for (const customPath of paths) { - const expandedPath = this.expandUserPath(customPath); - const validation = this.validateCustomContentPathSync(expandedPath); - if (validation) continue; - let moduleMeta; - try { - const moduleYamlPath = path.join(expandedPath, 'module.yaml'); - moduleMeta = require('yaml').parse(await fs.readFile(moduleYamlPath, 'utf-8')); - } catch { - continue; - } - if (!moduleMeta?.code) continue; - customPaths.push(expandedPath); - selectedModuleIds.push(moduleMeta.code); - sources.push({ path: expandedPath, id: moduleMeta.code, name: moduleMeta.name || moduleMeta.code }); - } - if (customPaths.length > 0) { - customContentForQuickUpdate = { - hasCustomContent: true, - selected: true, - sources, - selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')), - selectedModuleIds, - }; - } - } - } - return { - actionType: 'quick-update', - directory: confirmedDirectory, - customContent: customContentForQuickUpdate, - skipPrompts: options.yes || false, - }; - } - - // If actionType === 'update', handle it with the new flow - // Return early with modify configuration - if (actionType === 'update') { - // Get existing installation info - const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory); - - await prompts.log.message(`Found existing modules: ${[...installedModuleIds].join(', ')}`); - - // Unified module selection - all modules in one grouped multiselect - let selectedModules; - if (options.modules) { - // Use modules from command-line - selectedModules = options.modules - .split(',') - .map((m) => m.trim()) - .filter(Boolean); - await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`); - } else if (options.yes) { - selectedModules = await this.getDefaultModules(installedModuleIds); - await prompts.log.info( - `Non-interactive mode (--yes): using default modules (installed + defaults): ${selectedModules.join(', ')}`, - ); - } else { - selectedModules = await this.selectAllModules(installedModuleIds); - } - - // After module selection, ask about custom modules - let customModuleResult = { selectedCustomModules: [], customContentConfig: { hasCustomContent: false } }; - - if (options.customContent) { - // Use custom content from command-line - const paths = options.customContent - .split(',') - .map((p) => p.trim()) - .filter(Boolean); - await prompts.log.info(`Using custom content from command-line: ${paths.join(', ')}`); - - // Build custom content config similar to promptCustomContentSource - const customPaths = []; - const selectedModuleIds = []; - const sources = []; - - for (const customPath of paths) { - const expandedPath = this.expandUserPath(customPath); - const validation = this.validateCustomContentPathSync(expandedPath); - if (validation) { - await prompts.log.warn(`Skipping invalid custom content path: ${customPath} - ${validation}`); - continue; - } - - // Read module metadata - let moduleMeta; - try { - const moduleYamlPath = path.join(expandedPath, 'module.yaml'); - const moduleYaml = await fs.readFile(moduleYamlPath, 'utf-8'); - const yaml = require('yaml'); - moduleMeta = yaml.parse(moduleYaml); - } catch (error) { - await prompts.log.warn(`Skipping custom content path: ${customPath} - failed to read module.yaml: ${error.message}`); - continue; - } - - if (!moduleMeta) { - await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`); - continue; - } - - if (!moduleMeta.code) { - await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`); - continue; - } - - customPaths.push(expandedPath); - selectedModuleIds.push(moduleMeta.code); - sources.push({ - path: expandedPath, - id: moduleMeta.code, - name: moduleMeta.name || moduleMeta.code, - }); - } - - if (customPaths.length > 0) { - customModuleResult = { - selectedCustomModules: selectedModuleIds, - customContentConfig: { - hasCustomContent: true, - selected: true, - sources, - selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')), - selectedModuleIds: selectedModuleIds, - }, - }; - } - } else if (options.yes) { - // Non-interactive mode: preserve existing custom modules (matches default: false) - const cacheDir = path.join(bmadDir, '_config', 'custom'); - if (await fs.pathExists(cacheDir)) { - const entries = await fs.readdir(cacheDir, { withFileTypes: true }); - for (const entry of entries) { - if (entry.isDirectory()) { - customModuleResult.selectedCustomModules.push(entry.name); - } - } - await prompts.log.info( - `Non-interactive mode (--yes): preserving ${customModuleResult.selectedCustomModules.length} existing custom module(s)`, - ); - } else { - await prompts.log.info('Non-interactive mode (--yes): no existing custom modules found'); - } - } else { - const changeCustomModules = await prompts.confirm({ - message: 'Modify custom modules, agents, or workflows?', - default: false, - }); - - if (changeCustomModules) { - customModuleResult = await this.handleCustomModulesInModifyFlow(confirmedDirectory, selectedModules); - } else { - // Preserve existing custom modules if user doesn't want to modify them - const { Installer } = require('../installers/lib/core/installer'); - const installer = new Installer(); - const { bmadDir } = await installer.findBmadDir(confirmedDirectory); - - const cacheDir = path.join(bmadDir, '_config', 'custom'); - if (await fs.pathExists(cacheDir)) { - const entries = await fs.readdir(cacheDir, { withFileTypes: true }); - for (const entry of entries) { - if (entry.isDirectory()) { - customModuleResult.selectedCustomModules.push(entry.name); - } - } - } - } - } - - // Merge any selected custom modules - if (customModuleResult.selectedCustomModules.length > 0) { - selectedModules.push(...customModuleResult.selectedCustomModules); - } - - // Filter out core - it's always installed via installCore flag - selectedModules = selectedModules.filter((m) => m !== 'core'); - - // Get tool selection - const toolSelection = await this.promptToolSelection(confirmedDirectory, options); - - const coreConfig = await this.collectCoreConfig(confirmedDirectory, options); - - return { - actionType: 'update', - directory: confirmedDirectory, - installCore: true, - modules: selectedModules, - ides: toolSelection.ides, - skipIde: toolSelection.skipIde, - coreConfig: coreConfig, - customContent: customModuleResult.customContentConfig, - skipPrompts: options.yes || false, - }; - } - } - - // This section is only for new installations (update returns early above) - const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory); - - // Unified module selection - all modules in one grouped multiselect - let selectedModules; - if (options.modules) { - // Use modules from command-line - selectedModules = options.modules - .split(',') - .map((m) => m.trim()) - .filter(Boolean); - await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`); - } else if (options.yes) { - // Use default modules when --yes flag is set - selectedModules = await this.getDefaultModules(installedModuleIds); - await prompts.log.info(`Using default modules (--yes flag): ${selectedModules.join(', ')}`); - } else { - selectedModules = await this.selectAllModules(installedModuleIds); - } - - // Ask about custom content (local modules/agents/workflows) - if (options.customContent) { - // Use custom content from command-line - const paths = options.customContent - .split(',') - .map((p) => p.trim()) - .filter(Boolean); - await prompts.log.info(`Using custom content from command-line: ${paths.join(', ')}`); - - // Build custom content config similar to promptCustomContentSource - const customPaths = []; - const selectedModuleIds = []; - const sources = []; - - for (const customPath of paths) { - const expandedPath = this.expandUserPath(customPath); - const validation = this.validateCustomContentPathSync(expandedPath); - if (validation) { - await prompts.log.warn(`Skipping invalid custom content path: ${customPath} - ${validation}`); - continue; - } - - // Read module metadata - let moduleMeta; - try { - const moduleYamlPath = path.join(expandedPath, 'module.yaml'); - const moduleYaml = await fs.readFile(moduleYamlPath, 'utf-8'); - const yaml = require('yaml'); - moduleMeta = yaml.parse(moduleYaml); - } catch (error) { - await prompts.log.warn(`Skipping custom content path: ${customPath} - failed to read module.yaml: ${error.message}`); - continue; - } - - if (!moduleMeta) { - await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`); - continue; - } - - if (!moduleMeta.code) { - await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`); - continue; - } - - customPaths.push(expandedPath); - selectedModuleIds.push(moduleMeta.code); - sources.push({ - path: expandedPath, - id: moduleMeta.code, - name: moduleMeta.name || moduleMeta.code, - }); - } - - if (customPaths.length > 0) { - customContentConfig = { - hasCustomContent: true, - selected: true, - sources, - selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')), - selectedModuleIds: selectedModuleIds, - }; - } - } else if (!options.yes) { - const wantsCustomContent = await prompts.confirm({ - message: 'Add custom modules, agents, or workflows from your computer?', - default: false, - }); - - if (wantsCustomContent) { - customContentConfig = await this.promptCustomContentSource(); - } - } - - // Add custom content modules if any were selected - if (customContentConfig && customContentConfig.selectedModuleIds) { - selectedModules.push(...customContentConfig.selectedModuleIds); - } - - selectedModules = selectedModules.filter((m) => m !== 'core'); - let toolSelection = await this.promptToolSelection(confirmedDirectory, options); - const coreConfig = await this.collectCoreConfig(confirmedDirectory, options); - - return { - actionType: 'install', - directory: confirmedDirectory, - installCore: true, - modules: selectedModules, - ides: toolSelection.ides, - skipIde: toolSelection.skipIde, - coreConfig: coreConfig, - customContent: customContentConfig, - skipPrompts: options.yes || false, - }; - } - - /** - * Prompt for tool/IDE selection (called after module configuration) - * Uses a split prompt approach: - * 1. Recommended tools - standard multiselect for preferred tools - * 2. Additional tools - autocompleteMultiselect with search capability - * @param {string} projectDir - Project directory to check for existing IDEs - * @param {Object} options - Command-line options - * @returns {Object} Tool configuration - */ - async promptToolSelection(projectDir, options = {}) { - // Check for existing configured IDEs - use findBmadDir to detect custom folder names - const { Detector } = require('../installers/lib/core/detector'); - const { Installer } = require('../installers/lib/core/installer'); - const detector = new Detector(); - const installer = new Installer(); - const bmadResult = await installer.findBmadDir(projectDir || process.cwd()); - const bmadDir = bmadResult.bmadDir; - const existingInstall = await detector.detect(bmadDir); - const configuredIdes = existingInstall.ides || []; - - // Get IDE manager to fetch available IDEs dynamically - const { IdeManager } = require('../installers/lib/ide/manager'); - const ideManager = new IdeManager(); - await ideManager.ensureInitialized(); // IMPORTANT: Must initialize before getting IDEs - - const preferredIdes = ideManager.getPreferredIdes(); - const otherIdes = ideManager.getOtherIdes(); - - // Determine which configured IDEs are in "preferred" vs "other" categories - const configuredPreferred = configuredIdes.filter((id) => preferredIdes.some((ide) => ide.value === id)); - const configuredOther = configuredIdes.filter((id) => otherIdes.some((ide) => ide.value === id)); - - // Warn about previously configured tools that are no longer available - const allKnownValues = new Set([...preferredIdes, ...otherIdes].map((ide) => ide.value)); - const unknownTools = configuredIdes.filter((id) => id && typeof id === 'string' && !allKnownValues.has(id)); - if (unknownTools.length > 0) { - await prompts.log.warn(`Previously configured tools are no longer available: ${unknownTools.join(', ')}`); - } - - // ───────────────────────────────────────────────────────────────────────────── - // UPGRADE PATH: If tools already configured, show all tools with configured at top - // ───────────────────────────────────────────────────────────────────────────── - if (configuredIdes.length > 0) { - const allTools = [...preferredIdes, ...otherIdes]; - - // Non-interactive: handle --tools and --yes flags before interactive prompt - if (options.tools) { - if (options.tools.toLowerCase() === 'none') { - await prompts.log.info('Skipping tool configuration (--tools none)'); - return { ides: [], skipIde: true }; - } - const selectedIdes = options.tools - .split(',') - .map((t) => t.trim()) - .filter(Boolean); - await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`); - await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); - return { ides: selectedIdes, skipIde: false }; - } - - if (options.yes) { - await prompts.log.info(`Non-interactive mode (--yes): keeping configured tools: ${configuredIdes.join(', ')}`); - await this.displaySelectedTools(configuredIdes, preferredIdes, allTools); - return { ides: configuredIdes, skipIde: false }; - } - - // Sort: configured tools first, then preferred, then others - const sortedTools = [ - ...allTools.filter((ide) => configuredIdes.includes(ide.value)), - ...allTools.filter((ide) => !configuredIdes.includes(ide.value)), - ]; - - const upgradeOptions = sortedTools.map((ide) => { - const isConfigured = configuredIdes.includes(ide.value); - const isPreferred = preferredIdes.some((p) => p.value === ide.value); - let label = ide.name; - if (isPreferred) label += ' ⭐'; - if (isConfigured) label += ' ✅'; - return { label, value: ide.value }; - }); - - // Sort initialValues to match display order - const sortedInitialValues = sortedTools.filter((ide) => configuredIdes.includes(ide.value)).map((ide) => ide.value); - - const upgradeSelected = await prompts.autocompleteMultiselect({ - message: 'Integrate with', - options: upgradeOptions, - initialValues: sortedInitialValues, - required: false, - maxItems: 8, - }); - - const selectedIdes = upgradeSelected || []; - - if (selectedIdes.length === 0) { - const confirmNoTools = await prompts.confirm({ - message: 'No tools selected. Continue without installing any tools?', - default: false, - }); - - if (!confirmNoTools) { - return this.promptToolSelection(projectDir, options); - } - - return { ides: [], skipIde: true }; - } - - // Display selected tools - await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); - - return { ides: selectedIdes, skipIde: false }; - } - - // ───────────────────────────────────────────────────────────────────────────── - // NEW INSTALL: Show all tools with search - // ───────────────────────────────────────────────────────────────────────────── - const allTools = [...preferredIdes, ...otherIdes]; - - const allToolOptions = allTools.map((ide) => { - const isPreferred = preferredIdes.some((p) => p.value === ide.value); - let label = ide.name; - if (isPreferred) label += ' ⭐'; - return { - label, - value: ide.value, - }; - }); - - let selectedIdes = []; - - // Check if tools are provided via command-line - if (options.tools) { - // Check for explicit "none" value to skip tool installation - if (options.tools.toLowerCase() === 'none') { - await prompts.log.info('Skipping tool configuration (--tools none)'); - return { ides: [], skipIde: true }; - } else { - selectedIdes = options.tools - .split(',') - .map((t) => t.trim()) - .filter(Boolean); - await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`); - await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); - return { ides: selectedIdes, skipIde: false }; - } - } else if (options.yes) { - // If --yes flag is set, skip tool prompt and use previously configured tools or empty - if (configuredIdes.length > 0) { - await prompts.log.info(`Using previously configured tools (--yes flag): ${configuredIdes.join(', ')}`); - await this.displaySelectedTools(configuredIdes, preferredIdes, allTools); - return { ides: configuredIdes, skipIde: false }; - } else { - await prompts.log.info('Skipping tool configuration (--yes flag, no previous tools)'); - return { ides: [], skipIde: true }; - } - } - - // Interactive mode - const interactiveSelectedIdes = await prompts.autocompleteMultiselect({ - message: 'Integrate with:', - options: allToolOptions, - initialValues: configuredIdes.length > 0 ? configuredIdes : undefined, - required: false, - maxItems: 8, - }); - - selectedIdes = interactiveSelectedIdes || []; - - // ───────────────────────────────────────────────────────────────────────────── - // STEP 3: Confirm if no tools selected - // ───────────────────────────────────────────────────────────────────────────── - if (selectedIdes.length === 0) { - const confirmNoTools = await prompts.confirm({ - message: 'No tools selected. Continue without installing any tools?', - default: false, - }); - - if (!confirmNoTools) { - // User wants to select tools - recurse - return this.promptToolSelection(projectDir, options); - } - - return { - ides: [], - skipIde: true, - }; - } - - // Display selected tools - await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); - - return { - ides: selectedIdes, - skipIde: selectedIdes.length === 0, - }; - } - - /** - * Prompt for update configuration - * @returns {Object} Update configuration - */ - async promptUpdate() { - const backupFirst = await prompts.confirm({ - message: 'Create backup before updating?', - default: true, - }); - - const preserveCustomizations = await prompts.confirm({ - message: 'Preserve local customizations?', - default: true, - }); - - return { backupFirst, preserveCustomizations }; - } - - /** - * Confirm action - * @param {string} message - Confirmation message - * @param {boolean} defaultValue - Default value - * @returns {boolean} User confirmation - */ - async confirm(message, defaultValue = false) { - return await prompts.confirm({ - message, - default: defaultValue, - }); - } - - /** - * Get confirmed directory from user - * @returns {string} Confirmed directory path - */ - async getConfirmedDirectory() { - let confirmedDirectory = null; - while (!confirmedDirectory) { - const directoryAnswer = await this.promptForDirectory(); - await this.displayDirectoryInfo(directoryAnswer.directory); - - if (await this.confirmDirectory(directoryAnswer.directory)) { - confirmedDirectory = directoryAnswer.directory; - } - } - return confirmedDirectory; - } - - /** - * Get existing installation info and installed modules - * @param {string} directory - Installation directory - * @returns {Object} Object with existingInstall, installedModuleIds, and bmadDir - */ - async getExistingInstallation(directory) { - const { Detector } = require('../installers/lib/core/detector'); - const { Installer } = require('../installers/lib/core/installer'); - const detector = new Detector(); - const installer = new Installer(); - const bmadDirResult = await installer.findBmadDir(directory); - const bmadDir = bmadDirResult.bmadDir; - const existingInstall = await detector.detect(bmadDir); - const installedModuleIds = new Set(existingInstall.modules.map((mod) => mod.id)); - - return { existingInstall, installedModuleIds, bmadDir }; - } - - /** - * Collect core configuration - * @param {string} directory - Installation directory - * @param {Object} options - Command-line options - * @returns {Object} Core configuration - */ - async collectCoreConfig(directory, options = {}) { - const { ConfigCollector } = require('../installers/lib/core/config-collector'); - const configCollector = new ConfigCollector(); - - // If options are provided, set them directly - if (options.userName || options.communicationLanguage || options.documentOutputLanguage || options.outputFolder) { - const coreConfig = {}; - if (options.userName) { - coreConfig.user_name = options.userName; - await prompts.log.info(`Using user name from command-line: ${options.userName}`); - } - if (options.communicationLanguage) { - coreConfig.communication_language = options.communicationLanguage; - await prompts.log.info(`Using communication language from command-line: ${options.communicationLanguage}`); - } - if (options.documentOutputLanguage) { - coreConfig.document_output_language = options.documentOutputLanguage; - await prompts.log.info(`Using document output language from command-line: ${options.documentOutputLanguage}`); - } - if (options.outputFolder) { - coreConfig.output_folder = options.outputFolder; - await prompts.log.info(`Using output folder from command-line: ${options.outputFolder}`); - } - - // Load existing config to merge with provided options - await configCollector.loadExistingConfig(directory); - - // Merge provided options with existing config (or defaults) - const existingConfig = configCollector.collectedConfig.core || {}; - configCollector.collectedConfig.core = { ...existingConfig, ...coreConfig }; - - // If not all options are provided, collect the missing ones interactively (unless --yes flag) - if ( - !options.yes && - (!options.userName || !options.communicationLanguage || !options.documentOutputLanguage || !options.outputFolder) - ) { - await configCollector.collectModuleConfig('core', directory, false, true); - } - } else if (options.yes) { - // Use all defaults when --yes flag is set - await configCollector.loadExistingConfig(directory); - const existingConfig = configCollector.collectedConfig.core || {}; - - // If no existing config, use defaults - if (Object.keys(existingConfig).length === 0) { - let safeUsername; - try { - safeUsername = os.userInfo().username; - } catch { - safeUsername = process.env.USER || process.env.USERNAME || 'User'; - } - const defaultUsername = safeUsername.charAt(0).toUpperCase() + safeUsername.slice(1); - configCollector.collectedConfig.core = { - user_name: defaultUsername, - communication_language: 'English', - document_output_language: 'English', - output_folder: '_bmad-output', - }; - await prompts.log.info('Using default configuration (--yes flag)'); - } - } else { - // Load existing configs first if they exist - await configCollector.loadExistingConfig(directory); - // Now collect with existing values as defaults (false = don't skip loading, true = skip completion message) - await configCollector.collectModuleConfig('core', directory, false, true); - } - - const coreConfig = configCollector.collectedConfig.core; - // Ensure we always have a core config object, even if empty - return coreConfig || {}; - } - - /** - * Get module choices for selection - * @param {Set} installedModuleIds - Currently installed module IDs - * @param {Object} customContentConfig - Custom content configuration - * @returns {Array} Module choices for prompt - */ - async getModuleChoices(installedModuleIds, customContentConfig = null) { - const color = await prompts.getColor(); - const moduleChoices = []; - const isNewInstallation = installedModuleIds.size === 0; - - const customContentItems = []; - - // Add custom content items - if (customContentConfig && customContentConfig.hasCustomContent && customContentConfig.customPath) { - // Existing installation - show from directory - const customHandler = new CustomHandler(); - const customFiles = await customHandler.findCustomContent(customContentConfig.customPath); - - for (const customFile of customFiles) { - const customInfo = await customHandler.getCustomInfo(customFile); - if (customInfo) { - customContentItems.push({ - name: `${color.cyan('\u2713')} ${customInfo.name} ${color.dim(`(${customInfo.relativePath})`)}`, - value: `__CUSTOM_CONTENT__${customFile}`, // Unique value for each custom content - checked: true, // Default to selected since user chose to provide custom content - path: customInfo.path, // Track path to avoid duplicates - hint: customInfo.description || undefined, - }); - } - } - } - - // Add official modules - const { ModuleManager } = require('../installers/lib/modules/manager'); - const moduleManager = new ModuleManager(); - const { modules: availableModules, customModules: customModulesFromCache } = await moduleManager.listAvailable(); - - // First, add all items to appropriate sections - const allCustomModules = []; - - // Add custom content items from directory - allCustomModules.push(...customContentItems); - - // Add custom modules from cache - for (const mod of customModulesFromCache) { - // Skip if this module is already in customContentItems (by path) - const isDuplicate = allCustomModules.some((item) => item.path && mod.path && path.resolve(item.path) === path.resolve(mod.path)); - - if (!isDuplicate) { - allCustomModules.push({ - name: `${color.cyan('\u2713')} ${mod.name} ${color.dim('(cached)')}`, - value: mod.id, - checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id), - hint: mod.description || undefined, - }); - } - } - - // Add separators and modules in correct order - if (allCustomModules.length > 0) { - // Add separator for custom content, all custom modules, and official content separator - moduleChoices.push( - new choiceUtils.Separator('── Custom Content ──'), - ...allCustomModules, - new choiceUtils.Separator('── Official Content ──'), - ); - } - - // Add official modules (only non-custom ones) - for (const mod of availableModules) { - if (!mod.isCustom) { - moduleChoices.push({ - name: mod.name, - value: mod.id, - checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id), - hint: mod.description || undefined, - }); - } - } - - return moduleChoices; - } - - /** - * Select all modules (official + community) using grouped multiselect. - * Core is shown as locked but filtered from the result since it's always installed separately. - * @param {Set} installedModuleIds - Currently installed module IDs - * @returns {Array} Selected module codes (excluding core) - */ - async selectAllModules(installedModuleIds = new Set()) { - const { ModuleManager } = require('../installers/lib/modules/manager'); - const moduleManager = new ModuleManager(); - const { modules: localModules } = await moduleManager.listAvailable(); - - // Get external modules - const externalManager = new ExternalModuleManager(); - const externalModules = await externalManager.listAvailable(); - - // Build flat options list with group hints for autocompleteMultiselect - const allOptions = []; - const initialValues = []; - const lockedValues = ['core']; - - // Core module is always installed — show it locked at the top - allOptions.push({ label: 'BMad Core Module', value: 'core', hint: 'Core configuration and shared resources' }); - initialValues.push('core'); - - // Helper to build module entry with proper sorting and selection - const buildModuleEntry = (mod, value, group) => { - const isInstalled = installedModuleIds.has(value); - return { - label: mod.name, - value, - hint: mod.description || group, - // Pre-select only if already installed (not on fresh install) - selected: isInstalled, - }; - }; - - // Local modules (BMM, BMB, etc.) - const localEntries = []; - for (const mod of localModules) { - if (!mod.isCustom && mod.id !== 'core') { - const entry = buildModuleEntry(mod, mod.id, 'Local'); - localEntries.push(entry); - if (entry.selected) { - initialValues.push(mod.id); - } - } - } - allOptions.push(...localEntries.map(({ label, value, hint }) => ({ label, value, hint }))); - - // Group 2: BMad Official Modules (type: bmad-org) - const officialModules = []; - for (const mod of externalModules) { - if (mod.type === 'bmad-org') { - const entry = buildModuleEntry(mod, mod.code, 'Official'); - officialModules.push(entry); - if (entry.selected) { - initialValues.push(mod.code); - } - } - } - allOptions.push(...officialModules.map(({ label, value, hint }) => ({ label, value, hint }))); - - // Group 3: Community Modules (type: community) - const communityModules = []; - for (const mod of externalModules) { - if (mod.type === 'community') { - const entry = buildModuleEntry(mod, mod.code, 'Community'); - communityModules.push(entry); - if (entry.selected) { - initialValues.push(mod.code); - } - } - } - allOptions.push(...communityModules.map(({ label, value, hint }) => ({ label, value, hint }))); - - const selected = await prompts.autocompleteMultiselect({ - message: 'Select modules to install:', - options: allOptions, - initialValues: initialValues.length > 0 ? initialValues : undefined, - lockedValues, - required: true, - maxItems: allOptions.length, - }); - - const result = selected ? selected.filter((m) => m !== 'core') : []; - - // Display selected modules as bulleted list - if (result.length > 0) { - const moduleLines = result.map((moduleId) => { - const opt = allOptions.find((o) => o.value === moduleId); - return ` \u2022 ${opt?.label || moduleId}`; - }); - await prompts.log.message('Selected modules:\n' + moduleLines.join('\n')); - } - - return result; - } - - /** - * Get default modules for non-interactive mode - * @param {Set} installedModuleIds - Already installed module IDs - * @returns {Array} Default module codes - */ - async getDefaultModules(installedModuleIds = new Set()) { - const { ModuleManager } = require('../installers/lib/modules/manager'); - const moduleManager = new ModuleManager(); - const { modules: localModules } = await moduleManager.listAvailable(); - - const defaultModules = []; - - // Add default-selected local modules (typically BMM) - for (const mod of localModules) { - if (mod.defaultSelected === true || installedModuleIds.has(mod.id)) { - defaultModules.push(mod.id); - } - } - - // If no defaults found, use 'bmm' as the fallback default - if (defaultModules.length === 0) { - defaultModules.push('bmm'); - } - - return defaultModules; - } - - /** - * Prompt for directory selection - * @returns {Object} Directory answer from prompt - */ - async promptForDirectory() { - // Use sync validation because @clack/prompts doesn't support async validate - const directory = await prompts.text({ - message: 'Installation directory:', - default: process.cwd(), - placeholder: process.cwd(), - validate: (input) => this.validateDirectorySync(input), - }); - - // Apply filter logic - let filteredDir = directory; - if (!filteredDir || filteredDir.trim() === '') { - filteredDir = process.cwd(); - } else { - filteredDir = this.expandUserPath(filteredDir); - } - - return { directory: filteredDir }; - } - - /** - * Display directory information - * @param {string} directory - The directory path - */ - async displayDirectoryInfo(directory) { - await prompts.log.info(`Resolved installation path: ${directory}`); - - const dirExists = await fs.pathExists(directory); - if (dirExists) { - // Show helpful context about the existing path - const stats = await fs.stat(directory); - if (stats.isDirectory()) { - const files = await fs.readdir(directory); - if (files.length > 0) { - // Check for any bmad installation (any folder with _config/manifest.yaml) - const { Installer } = require('../installers/lib/core/installer'); - const installer = new Installer(); - const bmadResult = await installer.findBmadDir(directory); - const hasBmadInstall = - (await fs.pathExists(bmadResult.bmadDir)) && (await fs.pathExists(path.join(bmadResult.bmadDir, '_config', 'manifest.yaml'))); - - const bmadNote = hasBmadInstall ? ` including existing BMAD installation (${path.basename(bmadResult.bmadDir)})` : ''; - await prompts.log.message(`Directory exists and contains ${files.length} item(s)${bmadNote}`); - } else { - await prompts.log.message('Directory exists and is empty'); - } - } - } - } - - /** - * Confirm directory selection - * @param {string} directory - The directory path - * @returns {boolean} Whether user confirmed - */ - async confirmDirectory(directory) { - const dirExists = await fs.pathExists(directory); - - if (dirExists) { - const proceed = await prompts.confirm({ - message: 'Install to this directory?', - default: true, - }); - - if (!proceed) { - await prompts.log.warn("Let's try again with a different path."); - } - - return proceed; - } else { - // Ask for confirmation to create the directory - const create = await prompts.confirm({ - message: `Create directory: ${directory}?`, - default: false, - }); - - if (!create) { - await prompts.log.warn("Let's try again with a different path."); - } - - return create; - } - } - - /** - * Validate directory path for installation (sync version for clack prompts) - * @param {string} input - User input path - * @returns {string|undefined} Error message or undefined if valid - */ - validateDirectorySync(input) { - // Allow empty input to use the default - if (!input || input.trim() === '') { - return; // Empty means use default, undefined = valid for clack - } - - let expandedPath; - try { - expandedPath = this.expandUserPath(input.trim()); - } catch (error) { - return error.message; - } - - // Check if the path exists - const pathExists = fs.pathExistsSync(expandedPath); - - if (!pathExists) { - // Find the first existing parent directory - const existingParent = this.findExistingParentSync(expandedPath); - - if (!existingParent) { - return 'Cannot create directory: no existing parent directory found'; - } - - // Check if the existing parent is writable - try { - fs.accessSync(existingParent, fs.constants.W_OK); - // Path doesn't exist but can be created - will prompt for confirmation later - return; - } catch { - // Provide a detailed error message explaining both issues - return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`; - } - } - - // If it exists, validate it's a directory and writable - const stat = fs.statSync(expandedPath); - if (!stat.isDirectory()) { - return `Path exists but is not a directory: ${expandedPath}`; - } - - // Check write permissions - try { - fs.accessSync(expandedPath, fs.constants.W_OK); - } catch { - return `Directory is not writable: ${expandedPath}`; - } - - return; - } - - /** - * Validate directory path for installation (async version) - * @param {string} input - User input path - * @returns {string|true} Error message or true if valid - */ - async validateDirectory(input) { - // Allow empty input to use the default - if (!input || input.trim() === '') { - return true; // Empty means use default - } - - let expandedPath; - try { - expandedPath = this.expandUserPath(input.trim()); - } catch (error) { - return error.message; - } - - // Check if the path exists - const pathExists = await fs.pathExists(expandedPath); - - if (!pathExists) { - // Find the first existing parent directory - const existingParent = await this.findExistingParent(expandedPath); - - if (!existingParent) { - return 'Cannot create directory: no existing parent directory found'; - } - - // Check if the existing parent is writable - try { - await fs.access(existingParent, fs.constants.W_OK); - // Path doesn't exist but can be created - will prompt for confirmation later - return true; - } catch { - // Provide a detailed error message explaining both issues - return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`; - } - } - - // If it exists, validate it's a directory and writable - const stat = await fs.stat(expandedPath); - if (!stat.isDirectory()) { - return `Path exists but is not a directory: ${expandedPath}`; - } - - // Check write permissions - try { - await fs.access(expandedPath, fs.constants.W_OK); - } catch { - return `Directory is not writable: ${expandedPath}`; - } - - return true; - } - - /** - * Find the first existing parent directory (sync version) - * @param {string} targetPath - The path to check - * @returns {string|null} The first existing parent directory, or null if none found - */ - findExistingParentSync(targetPath) { - let currentPath = path.resolve(targetPath); - - // Walk up the directory tree until we find an existing directory - while (currentPath !== path.dirname(currentPath)) { - // Stop at root - const parent = path.dirname(currentPath); - if (fs.pathExistsSync(parent)) { - return parent; - } - currentPath = parent; - } - - return null; // No existing parent found (shouldn't happen in practice) - } - - /** - * Find the first existing parent directory (async version) - * @param {string} targetPath - The path to check - * @returns {string|null} The first existing parent directory, or null if none found - */ - async findExistingParent(targetPath) { - let currentPath = path.resolve(targetPath); - - // Walk up the directory tree until we find an existing directory - while (currentPath !== path.dirname(currentPath)) { - // Stop at root - const parent = path.dirname(currentPath); - if (await fs.pathExists(parent)) { - return parent; - } - currentPath = parent; - } - - return null; // No existing parent found (shouldn't happen in practice) - } - - /** - * Expands the user-provided path: handles ~ and resolves to absolute. - * @param {string} inputPath - User input path. - * @returns {string} Absolute expanded path. - */ - expandUserPath(inputPath) { - if (typeof inputPath !== 'string') { - throw new TypeError('Path must be a string.'); - } - - let expanded = inputPath.trim(); - - // Handle tilde expansion - if (expanded.startsWith('~')) { - if (expanded === '~') { - expanded = os.homedir(); - } else if (expanded.startsWith('~' + path.sep)) { - const pathAfterHome = expanded.slice(2); // Remove ~/ or ~\ - expanded = path.join(os.homedir(), pathAfterHome); - } else { - const restOfPath = expanded.slice(1); - const separatorIndex = restOfPath.indexOf(path.sep); - const username = separatorIndex === -1 ? restOfPath : restOfPath.slice(0, separatorIndex); - if (username) { - throw new Error(`Path expansion for ~${username} is not supported. Please use an absolute path or ~${path.sep}`); - } - } - } - - // Resolve to the absolute path relative to the current working directory - return path.resolve(expanded); - } - - /** - * Load existing configurations to use as defaults - * @param {string} directory - Installation directory - * @returns {Object} Existing configurations - */ - async loadExistingConfigurations(directory) { - const configs = { - hasCustomContent: false, - coreConfig: {}, - ideConfig: { ides: [], skipIde: false }, - }; - - try { - // Load core config - configs.coreConfig = await this.collectCoreConfig(directory); - - // Load IDE configuration - const configuredIdes = await this.getConfiguredIdes(directory); - if (configuredIdes.length > 0) { - configs.ideConfig.ides = configuredIdes; - configs.ideConfig.skipIde = false; - } - - return configs; - } catch { - // If loading fails, return empty configs - await prompts.log.warn('Could not load existing configurations'); - return configs; - } - } - - /** - * Get configured IDEs from existing installation - * @param {string} directory - Installation directory - * @returns {Array} List of configured IDEs - */ - async getConfiguredIdes(directory) { - const { Detector } = require('../installers/lib/core/detector'); - const { Installer } = require('../installers/lib/core/installer'); - const detector = new Detector(); - const installer = new Installer(); - const bmadResult = await installer.findBmadDir(directory); - const existingInstall = await detector.detect(bmadResult.bmadDir); - return existingInstall.ides || []; - } - - /** - * Validate custom content path synchronously - * @param {string} input - User input path - * @returns {string|undefined} Error message or undefined if valid - */ - validateCustomContentPathSync(input) { - // Allow empty input to cancel - if (!input || input.trim() === '') { - return; // Allow empty to exit - } - - try { - // Expand the path - const expandedPath = this.expandUserPath(input.trim()); - - // Check if path exists - if (!fs.pathExistsSync(expandedPath)) { - return 'Path does not exist'; - } - - // Check if it's a directory - const stat = fs.statSync(expandedPath); - if (!stat.isDirectory()) { - return 'Path must be a directory'; - } - - // Check for module.yaml in the root - const moduleYamlPath = path.join(expandedPath, 'module.yaml'); - if (!fs.pathExistsSync(moduleYamlPath)) { - return 'Directory must contain a module.yaml file in the root'; - } - - // Try to parse the module.yaml to get the module ID - try { - const yaml = require('yaml'); - const content = fs.readFileSync(moduleYamlPath, 'utf8'); - const moduleData = yaml.parse(content); - if (!moduleData.code) { - return 'module.yaml must contain a "code" field for the module ID'; - } - } catch (error) { - return 'Invalid module.yaml file: ' + error.message; - } - - return; // Valid - } catch (error) { - return 'Error validating path: ' + error.message; - } - } - - /** - * Prompt user for custom content source location - * @returns {Object} Custom content configuration - */ - async promptCustomContentSource() { - const customContentConfig = { hasCustomContent: true, sources: [] }; - - // Keep asking for more sources until user is done - while (true) { - // First ask if user wants to add another module or continue - if (customContentConfig.sources.length > 0) { - const action = await prompts.select({ - message: 'Would you like to:', - choices: [ - { name: 'Add another custom module', value: 'add' }, - { name: 'Continue with installation', value: 'continue' }, - ], - default: 'continue', - }); - - if (action === 'continue') { - break; - } - } - - let sourcePath; - let isValid = false; - - while (!isValid) { - // Use sync validation because @clack/prompts doesn't support async validate - const inputPath = await prompts.text({ - message: 'Path to custom module folder (press Enter to skip):', - validate: (input) => this.validateCustomContentPathSync(input), - }); - - // If user pressed Enter without typing anything, exit the loop - if (!inputPath || inputPath.trim() === '') { - // If we have no modules yet, return false for no custom content - if (customContentConfig.sources.length === 0) { - return { hasCustomContent: false }; - } - return customContentConfig; - } - - sourcePath = this.expandUserPath(inputPath); - isValid = true; - } - - // Read module.yaml to get module info - const yaml = require('yaml'); - const moduleYamlPath = path.join(sourcePath, 'module.yaml'); - const moduleContent = await fs.readFile(moduleYamlPath, 'utf8'); - const moduleData = yaml.parse(moduleContent); - - // Add to sources - customContentConfig.sources.push({ - path: sourcePath, - id: moduleData.code, - name: moduleData.name || moduleData.code, - }); - - await prompts.log.success(`Confirmed local custom module: ${moduleData.name || moduleData.code}`); - } - - // Ask if user wants to add these to the installation - const shouldInstall = await prompts.confirm({ - message: `Install these ${customContentConfig.sources.length} custom modules?`, - default: true, - }); - - if (shouldInstall) { - customContentConfig.selected = true; - // Store paths to module.yaml files, not directories - customContentConfig.selectedFiles = customContentConfig.sources.map((s) => path.join(s.path, 'module.yaml')); - // Also include module IDs for installation - customContentConfig.selectedModuleIds = customContentConfig.sources.map((s) => s.id); - } - - return customContentConfig; - } - - /** - * Handle custom modules in the modify flow - * @param {string} directory - Installation directory - * @param {Array} selectedModules - Currently selected modules - * @returns {Object} Result with selected custom modules and custom content config - */ - async handleCustomModulesInModifyFlow(directory, selectedModules) { - // Get existing installation to find custom modules - const { existingInstall } = await this.getExistingInstallation(directory); - - // Check if there are any custom modules in cache - const { Installer } = require('../installers/lib/core/installer'); - const installer = new Installer(); - const { bmadDir } = await installer.findBmadDir(directory); - - const cacheDir = path.join(bmadDir, '_config', 'custom'); - const cachedCustomModules = []; - - if (await fs.pathExists(cacheDir)) { - const entries = await fs.readdir(cacheDir, { withFileTypes: true }); - for (const entry of entries) { - if (entry.isDirectory()) { - const moduleYamlPath = path.join(cacheDir, entry.name, 'module.yaml'); - if (await fs.pathExists(moduleYamlPath)) { - const yaml = require('yaml'); - const content = await fs.readFile(moduleYamlPath, 'utf8'); - const moduleData = yaml.parse(content); - - cachedCustomModules.push({ - id: entry.name, - name: moduleData.name || entry.name, - description: moduleData.description || 'Custom module from cache', - checked: selectedModules.includes(entry.name), - fromCache: true, - }); - } - } - } - } - - const result = { - selectedCustomModules: [], - customContentConfig: { hasCustomContent: false }, - }; - - // Ask user about custom modules - await prompts.log.info('Custom Modules'); - if (cachedCustomModules.length > 0) { - await prompts.log.message('Found custom modules in your installation:'); - } else { - await prompts.log.message('No custom modules currently installed.'); - } - - // Build choices dynamically based on whether we have existing modules - const choices = []; - if (cachedCustomModules.length > 0) { - choices.push( - { name: 'Keep all existing custom modules', value: 'keep' }, - { name: 'Select which custom modules to keep', value: 'select' }, - { name: 'Add new custom modules', value: 'add' }, - { name: 'Remove all custom modules', value: 'remove' }, - ); - } else { - choices.push({ name: 'Add new custom modules', value: 'add' }, { name: 'Cancel (no custom modules)', value: 'cancel' }); - } - - const customAction = await prompts.select({ - message: cachedCustomModules.length > 0 ? 'Manage custom modules?' : 'Add custom modules?', - choices: choices, - default: cachedCustomModules.length > 0 ? 'keep' : 'add', - }); - - switch (customAction) { - case 'keep': { - // Keep all existing custom modules - result.selectedCustomModules = cachedCustomModules.map((m) => m.id); - await prompts.log.message(`Keeping ${result.selectedCustomModules.length} custom module(s)`); - break; - } - - case 'select': { - // Let user choose which to keep - const selectChoices = cachedCustomModules.map((m) => ({ - name: `${m.name} (${m.id})`, - value: m.id, - checked: m.checked, - })); - - // Add "None / I changed my mind" option at the end - const choicesWithSkip = [ - ...selectChoices, - { - name: '⚠ None / I changed my mind - keep no custom modules', - value: '__NONE__', - checked: false, - }, - ]; - - const keepModules = await prompts.multiselect({ - message: 'Select custom modules to keep (use arrow keys, space to toggle):', - choices: choicesWithSkip, - required: true, - }); - - // If user selected both "__NONE__" and other modules, honor the "None" choice - if (keepModules && keepModules.includes('__NONE__') && keepModules.length > 1) { - await prompts.log.warn('"None / I changed my mind" was selected, so no custom modules will be kept.'); - result.selectedCustomModules = []; - } else { - // Filter out the special '__NONE__' value - result.selectedCustomModules = keepModules ? keepModules.filter((m) => m !== '__NONE__') : []; - } - break; - } - - case 'add': { - // By default, keep existing modules when adding new ones - // User chose "Add new" not "Replace", so we assume they want to keep existing - result.selectedCustomModules = cachedCustomModules.map((m) => m.id); - - // Then prompt for new ones (reuse existing method) - const newCustomContent = await this.promptCustomContentSource(); - if (newCustomContent.hasCustomContent && newCustomContent.selected) { - result.selectedCustomModules.push(...newCustomContent.selectedModuleIds); - result.customContentConfig = newCustomContent; - } - break; - } - - case 'remove': { - // Remove all custom modules - await prompts.log.warn('All custom modules will be removed from the installation'); - break; - } - - case 'cancel': { - // User cancelled - no custom modules - await prompts.log.message('No custom modules will be added'); - break; - } - } - - return result; - } - - /** - * Check if installed version is a legacy version that needs fresh install - * @param {string} installedVersion - The installed version - * @returns {boolean} True if legacy (v4 or any alpha) - */ - isLegacyVersion(installedVersion) { - if (!installedVersion || installedVersion === 'unknown') { - return true; // Treat unknown as legacy for safety - } - // Check if version string contains -alpha or -Alpha (any v6 alpha) - return /-alpha\./i.test(installedVersion); - } - - /** - * Show warning for legacy version (v4 or alpha) and ask if user wants to proceed - * @param {string} installedVersion - The installed version - * @param {string} currentVersion - The current version - * @param {string} bmadFolderName - Name of the BMAD folder - * @returns {Promise} True if user wants to proceed, false if they cancel - */ - async showLegacyVersionWarning(installedVersion, currentVersion, bmadFolderName, options = {}) { - if (!this.isLegacyVersion(installedVersion)) { - return true; // Not legacy, proceed - } - - let warningContent; - if (installedVersion === 'unknown') { - warningContent = 'Unable to detect your installed BMAD version.\n' + 'This appears to be a legacy or unsupported installation.'; - } else { - warningContent = - `You are updating from ${installedVersion} to ${currentVersion}.\n` + 'You have a legacy version installed (v4 or alpha).'; - } - - warningContent += - '\n\nFor the best experience, we recommend:\n' + - ' 1. Delete your current BMAD installation folder\n' + - ` (the "${bmadFolderName}/" folder in your project)\n` + - ' 2. Run a fresh installation\n\n' + - 'Benefits of a fresh install:\n' + - ' \u2022 Cleaner configuration without legacy artifacts\n' + - ' \u2022 All new features properly configured\n' + - ' \u2022 Fewer potential conflicts'; - - await prompts.log.warn('VERSION WARNING'); - await prompts.note(warningContent, 'Version Warning'); - - if (options.yes) { - await prompts.log.warn('Non-interactive mode (--yes): auto-proceeding with legacy update'); - return true; - } - - const proceed = await prompts.select({ - message: 'How would you like to proceed?', - choices: [ - { - name: 'Proceed with update anyway (may have issues)', - value: 'proceed', - }, - { - name: 'Cancel (recommended - do a fresh install instead)', - value: 'cancel', - }, - ], - default: 'cancel', - }); - - if (proceed === 'cancel') { - await prompts.note( - `1. Delete the "${bmadFolderName}/" folder in your project\n` + "2. Run 'bmad install' again", - 'To do a fresh install', - ); - } - - return proceed === 'proceed'; - } - - /** - * Display module versions with update availability - * @param {Array} modules - Array of module info objects with version info - * @param {Array} availableUpdates - Array of available updates - */ - async displayModuleVersions(modules, availableUpdates = []) { - // Group modules by source - const builtIn = modules.filter((m) => m.source === 'built-in'); - const external = modules.filter((m) => m.source === 'external'); - const custom = modules.filter((m) => m.source === 'custom'); - const unknown = modules.filter((m) => m.source === 'unknown'); - - const lines = []; - const formatGroup = (group, title) => { - if (group.length === 0) return; - lines.push(title); - for (const mod of group) { - const updateInfo = availableUpdates.find((u) => u.name === mod.name); - const versionDisplay = mod.version || 'unknown'; - if (updateInfo) { - lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2192 ${updateInfo.latestVersion} \u2191`); - } else { - lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2713`); - } - } - }; - - formatGroup(builtIn, 'Built-in Modules'); - formatGroup(external, 'External Modules (Official)'); - formatGroup(custom, 'Custom Modules'); - formatGroup(unknown, 'Other Modules'); - - await prompts.note(lines.join('\n'), 'Module Versions'); - } - - /** - * Prompt user to select which modules to update - * @param {Array} availableUpdates - Array of available updates - * @returns {Array} Selected module names to update - */ - async promptUpdateSelection(availableUpdates) { - if (availableUpdates.length === 0) { - return []; - } - - await prompts.log.info('Available Updates'); - - const choices = availableUpdates.map((update) => ({ - name: `${update.name} (v${update.installedVersion} \u2192 v${update.latestVersion})`, - value: update.name, - checked: true, // Default to selecting all updates - })); - - // Add "Update All" and "Cancel" options - const action = await prompts.select({ - message: 'How would you like to proceed?', - choices: [ - { name: 'Update all available modules', value: 'all' }, - { name: 'Select specific modules to update', value: 'select' }, - { name: 'Skip updates for now', value: 'skip' }, - ], - default: 'all', - }); - - if (action === 'all') { - return availableUpdates.map((u) => u.name); - } - - if (action === 'skip') { - return []; - } - - // Allow specific selection - const selected = await prompts.multiselect({ - message: 'Select modules to update (use arrow keys, space to toggle):', - choices: choices, - required: true, - }); - - return selected || []; - } - - /** - * Display status of all installed modules - * @param {Object} statusData - Status data with modules, installation info, and available updates - */ - async displayStatus(statusData) { - const { installation, modules, availableUpdates, bmadDir } = statusData; - - // Installation info - const infoLines = [ - `Version: ${installation.version || 'unknown'}`, - `Location: ${bmadDir}`, - `Installed: ${new Date(installation.installDate).toLocaleDateString()}`, - `Last Updated: ${installation.lastUpdated ? new Date(installation.lastUpdated).toLocaleDateString() : 'unknown'}`, - ]; - - await prompts.note(infoLines.join('\n'), 'BMAD Status'); - - // Module versions - await this.displayModuleVersions(modules, availableUpdates); - - // Update summary - if (availableUpdates.length > 0) { - await prompts.log.warn(`${availableUpdates.length} update(s) available`); - await prompts.log.message('Run \'bmad install\' and select "Quick Update" to update'); - } else { - await prompts.log.success('All modules are up to date'); - } - } - - /** - * Display list of selected tools after IDE selection - * @param {Array} selectedIdes - Array of selected IDE values - * @param {Array} preferredIdes - Array of preferred IDE objects - * @param {Array} allTools - Array of all tool objects - */ - async displaySelectedTools(selectedIdes, preferredIdes, allTools) { - if (selectedIdes.length === 0) return; - - const preferredValues = new Set(preferredIdes.map((ide) => ide.value)); - const toolLines = selectedIdes.map((ideValue) => { - const tool = allTools.find((t) => t.value === ideValue); - const name = tool?.name || ideValue; - const marker = preferredValues.has(ideValue) ? ' \u2B50' : ''; - return ` \u2022 ${name}${marker}`; - }); - await prompts.log.message('Selected tools:\n' + toolLines.join('\n')); - } -} - -module.exports = { UI }; diff --git a/tools/docs/_prompt-external-modules-page.md b/tools/docs/_prompt-external-modules-page.md index f5e124373..414f977a8 100644 --- a/tools/docs/_prompt-external-modules-page.md +++ b/tools/docs/_prompt-external-modules-page.md @@ -6,7 +6,7 @@ Create a reference documentation page at `docs/reference/modules.md` that lists ## Source of Truth -Read `tools/cli/external-official-modules.yaml` — this is the authoritative registry of official external modules. Use the module names, codes, npm package names, and repository URLs from this file. +Read `tools/installer/external-official-modules.yaml` — this is the authoritative registry of official external modules. Use the module names, codes, npm package names, and repository URLs from this file. ## Research Step diff --git a/tools/docs/native-skills-migration-checklist.md b/tools/docs/native-skills-migration-checklist.md index 2f0f31344..80c6a9296 100644 --- a/tools/docs/native-skills-migration-checklist.md +++ b/tools/docs/native-skills-migration-checklist.md @@ -205,17 +205,14 @@ Support assumption: full Agent Skills support. BMAD currently uses a custom inst - [x] Implement/extend automated tests — 11 assertions in test suite 17 including marker cleanup - [x] Commit -## KiloCoder — SUSPENDED - -**Status: Kilo Code does not support the Agent Skills standard.** The original migration assumed skills support because Kilo forked from Roo Code, but manual IDE verification confirmed Kilo has not merged that feature. BMAD support is paused until Kilo implements skills. +## KiloCoder **Install:** VS Code extension `kilocode.kilo-code` — search "Kilo Code" in Extensions or `code --install-extension kilocode.kilo-code` -- [x] ~~Confirm KiloCoder native skills path~~ — **FALSE**: assumed from Roo Code fork, not verified. Manual testing showed no skills support in the IDE -- [x] Config and installer code retained in platform-codes.yaml with `suspended` flag — hidden from IDE picker, setup blocked with explanation -- [x] Installer fails early (before writing `_bmad/`) if Kilo is the only selected IDE, protecting existing installations -- [x] Legacy cleanup still runs for `.kilocode/workflows` and `.kilocodemodes` when users switch to a different IDE -- [x] Automated tests — 7 assertions in suite 22 (suspended config, hidden from picker, setup blocked, no files written, legacy cleanup) +- [x] Confirm KiloCoder native skills path — `.kilocode/skills` +- [x] Legacy cleanup for `.kilocode/workflows` and `.kilocodemodes` +- [x] Automated tests — suite 22 (config, IDE picker, install, skill output, legacy cleanup, reinstall) +- [x] Commit ## Gemini CLI diff --git a/tools/cli/README.md b/tools/installer/README.md similarity index 100% rename from tools/cli/README.md rename to tools/installer/README.md diff --git a/tools/cli/bmad-cli.js b/tools/installer/bmad-cli.js similarity index 98% rename from tools/cli/bmad-cli.js rename to tools/installer/bmad-cli.js index 31db41fbf..042714e45 100755 --- a/tools/cli/bmad-cli.js +++ b/tools/installer/bmad-cli.js @@ -1,9 +1,11 @@ +#!/usr/bin/env node + const { program } = require('commander'); const path = require('node:path'); const fs = require('node:fs'); const { execSync } = require('node:child_process'); const semver = require('semver'); -const prompts = require('./lib/prompts'); +const prompts = require('./prompts'); // The installer flow uses many sequential @clack/prompts, each adding keypress // listeners to stdin. Raise the limit to avoid spurious EventEmitter warnings. diff --git a/tools/installer/cli-utils.js b/tools/installer/cli-utils.js new file mode 100644 index 000000000..b2b7b0979 --- /dev/null +++ b/tools/installer/cli-utils.js @@ -0,0 +1,53 @@ +const prompts = require('./prompts'); + +const CLIUtils = { + /** + * Display BMAD logo and version using @clack intro + box + */ + async displayLogo() { + const color = await prompts.getColor(); + const termWidth = process.stdout.columns || 80; + + // Full "BMad Method" logo for wide terminals, "BMad" only for narrow + const logoWide = [ + ' ██████╗ ███╗ ███╗ █████╗ ██████╗ ███╗ ███╗███████╗████████╗██╗ ██╗ ██████╗ ██████╗ ™', + '██╔══██╗████╗ ████║██╔══██╗██╔══██╗ ████╗ ████║██╔════╝╚══██╔══╝██║ ██║██╔═══██╗██╔══██╗', + '██████╔╝██╔████╔██║███████║██║ ██║ ██╔████╔██║█████╗ ██║ ███████║██║ ██║██║ ██║', + '██╔══██╗██║╚██╔╝██║██╔══██║██║ ██║ ██║╚██╔╝██║██╔══╝ ██║ ██╔══██║██║ ██║██║ ██║', + '██████╔╝██║ ╚═╝ ██║██║ ██║██████╔╝ ██║ ╚═╝ ██║███████╗ ██║ ██║ ██║╚██████╔╝██████╔╝', + '╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ', + ]; + + const logoNarrow = [ + ' ██████╗ ███╗ ███╗ █████╗ ██████╗ ™', + ' ██╔══██╗████╗ ████║██╔══██╗██╔══██╗', + ' ██████╔╝██╔████╔██║███████║██║ ██║', + ' ██╔══██╗██║╚██╔╝██║██╔══██║██║ ██║', + ' ██████╔╝██║ ╚═╝ ██║██║ ██║██████╔╝', + ' ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝', + ]; + + const logoLines = termWidth >= 95 ? logoWide : logoNarrow; + const logo = logoLines.map((line) => color.blue(line)).join('\n'); + const tagline = color.white(' Build More, Architect Dreams\n © BMad Code'); + + await prompts.box(`${logo}\n${tagline}`, '', { + contentAlign: 'center', + rounded: true, + formatBorder: color.blue, + }); + }, + + /** + * Display module configuration header + * @param {string} moduleName - Module name (fallback if no custom header) + * @param {string} header - Custom header from module.yaml + * @param {string} subheader - Custom subheader from module.yaml + */ + async displayModuleConfigHeader(moduleName, header = null, subheader = null) { + const title = header || `Configuring ${moduleName.toUpperCase()} Module`; + await prompts.note(subheader || '', title); + }, +}; + +module.exports = { CLIUtils }; diff --git a/tools/cli/commands/install.js b/tools/installer/commands/install.js similarity index 91% rename from tools/cli/commands/install.js rename to tools/installer/commands/install.js index 3577116d7..c6ec46ceb 100644 --- a/tools/cli/commands/install.js +++ b/tools/installer/commands/install.js @@ -1,7 +1,7 @@ const path = require('node:path'); -const prompts = require('../lib/prompts'); -const { Installer } = require('../installers/lib/core/installer'); -const { UI } = require('../lib/ui'); +const prompts = require('../prompts'); +const { Installer } = require('../core/installer'); +const { UI } = require('../ui'); const installer = new Installer(); const ui = new UI(); @@ -17,12 +17,12 @@ module.exports = { '--tools ', 'Comma-separated list of tool/IDE IDs to configure (e.g., "claude-code,cursor"). Use "none" to skip tool configuration.', ], - ['--custom-content ', 'Comma-separated list of paths to custom modules/agents/workflows'], ['--action ', 'Action type for existing installations: install, update, or quick-update'], ['--user-name ', 'Name for agents to use (default: system username)'], ['--communication-language ', 'Language for agent communication (default: English)'], ['--document-output-language ', 'Language for document output (default: English)'], ['--output-folder ', 'Output folder path relative to project root (default: _bmad-output)'], + ['--custom-source ', 'Comma-separated Git URLs or local paths to install custom modules from'], ['-y, --yes', 'Accept all defaults and skip prompts where possible'], ], action: async (options) => { diff --git a/tools/cli/commands/status.js b/tools/installer/commands/status.js similarity index 89% rename from tools/cli/commands/status.js rename to tools/installer/commands/status.js index ec931fe46..49c0afd73 100644 --- a/tools/cli/commands/status.js +++ b/tools/installer/commands/status.js @@ -1,8 +1,8 @@ const path = require('node:path'); -const prompts = require('../lib/prompts'); -const { Installer } = require('../installers/lib/core/installer'); -const { Manifest } = require('../installers/lib/core/manifest'); -const { UI } = require('../lib/ui'); +const prompts = require('../prompts'); +const { Installer } = require('../core/installer'); +const { Manifest } = require('../core/manifest'); +const { UI } = require('../ui'); const installer = new Installer(); const manifest = new Manifest(); diff --git a/tools/cli/commands/uninstall.js b/tools/installer/commands/uninstall.js similarity index 94% rename from tools/cli/commands/uninstall.js rename to tools/installer/commands/uninstall.js index 99734791e..d0e168a15 100644 --- a/tools/cli/commands/uninstall.js +++ b/tools/installer/commands/uninstall.js @@ -1,7 +1,7 @@ const path = require('node:path'); const fs = require('fs-extra'); -const prompts = require('../lib/prompts'); -const { Installer } = require('../installers/lib/core/installer'); +const prompts = require('../prompts'); +const { Installer } = require('../core/installer'); const installer = new Installer(); @@ -62,9 +62,9 @@ module.exports = { } const existingInstall = await installer.getStatus(projectDir); - const version = existingInstall.version || 'unknown'; - const modules = (existingInstall.modules || []).map((m) => m.id || m.name).join(', '); - const ides = (existingInstall.ides || []).join(', '); + const version = existingInstall.installed ? existingInstall.version : 'unknown'; + const modules = existingInstall.moduleIds.join(', '); + const ides = existingInstall.ides.join(', '); const outputFolder = await installer.getOutputFolder(projectDir); diff --git a/tools/installer/core/config.js b/tools/installer/core/config.js new file mode 100644 index 000000000..c844e2d00 --- /dev/null +++ b/tools/installer/core/config.js @@ -0,0 +1,52 @@ +/** + * Clean install configuration built from user input. + * User input comes from either UI answers or headless CLI flags. + */ +class Config { + constructor({ directory, modules, ides, skipPrompts, verbose, actionType, coreConfig, moduleConfigs, quickUpdate }) { + this.directory = directory; + this.modules = Object.freeze([...modules]); + this.ides = Object.freeze([...ides]); + this.skipPrompts = skipPrompts; + this.verbose = verbose; + this.actionType = actionType; + this.coreConfig = coreConfig; + this.moduleConfigs = moduleConfigs; + this._quickUpdate = quickUpdate; + Object.freeze(this); + } + + /** + * Build a clean install config from raw user input. + * @param {Object} userInput - UI answers or CLI flags + * @returns {Config} + */ + static build(userInput) { + const modules = [...(userInput.modules || [])]; + if (userInput.installCore && !modules.includes('core')) { + modules.unshift('core'); + } + + return new Config({ + directory: userInput.directory, + modules, + ides: userInput.skipIde ? [] : [...(userInput.ides || [])], + skipPrompts: userInput.skipPrompts || false, + verbose: userInput.verbose || false, + actionType: userInput.actionType, + coreConfig: userInput.coreConfig || {}, + moduleConfigs: userInput.moduleConfigs || null, + quickUpdate: userInput._quickUpdate || false, + }); + } + + hasCoreConfig() { + return this.coreConfig && Object.keys(this.coreConfig).length > 0; + } + + isQuickUpdate() { + return this._quickUpdate; + } +} + +module.exports = { Config }; diff --git a/tools/installer/core/existing-install.js b/tools/installer/core/existing-install.js new file mode 100644 index 000000000..643f1d946 --- /dev/null +++ b/tools/installer/core/existing-install.js @@ -0,0 +1,121 @@ +const path = require('node:path'); +const fs = require('fs-extra'); +const yaml = require('yaml'); +const { Manifest } = require('./manifest'); + +/** + * Immutable snapshot of an existing BMAD installation. + * Pure query object — no filesystem operations after construction. + */ +class ExistingInstall { + #version; + + constructor({ installed, version, hasCore, modules, ides }) { + this.installed = installed; + this.#version = version; + this.hasCore = hasCore; + this.modules = Object.freeze(modules.map((m) => Object.freeze({ ...m }))); + this.moduleIds = Object.freeze(this.modules.map((m) => m.id)); + this.ides = Object.freeze([...ides]); + Object.freeze(this); + } + + get version() { + if (!this.installed) { + throw new Error('version is not available when nothing is installed'); + } + return this.#version; + } + + static empty() { + return new ExistingInstall({ + installed: false, + version: null, + hasCore: false, + modules: [], + ides: [], + }); + } + + /** + * Scan a bmad directory and return an immutable snapshot of what's installed. + * @param {string} bmadDir - Path to bmad directory + * @returns {Promise} + */ + static async detect(bmadDir) { + if (!(await fs.pathExists(bmadDir))) { + return ExistingInstall.empty(); + } + + let version = null; + let hasCore = false; + const modules = []; + let ides = []; + + const manifest = new Manifest(); + const manifestData = await manifest.read(bmadDir); + if (manifestData) { + version = manifestData.version; + if (manifestData.ides) { + ides = manifestData.ides.filter((ide) => ide && typeof ide === 'string'); + } + } + + const corePath = path.join(bmadDir, 'core'); + if (await fs.pathExists(corePath)) { + hasCore = true; + + if (!version) { + const coreConfigPath = path.join(corePath, 'config.yaml'); + if (await fs.pathExists(coreConfigPath)) { + try { + const configContent = await fs.readFile(coreConfigPath, 'utf8'); + const config = yaml.parse(configContent); + if (config.version) { + version = config.version; + } + } catch { + // Ignore config read errors + } + } + } + } + + if (manifestData && manifestData.modules && manifestData.modules.length > 0) { + for (const moduleId of manifestData.modules) { + const modulePath = path.join(bmadDir, moduleId); + const moduleConfigPath = path.join(modulePath, 'config.yaml'); + + const moduleInfo = { + id: moduleId, + path: modulePath, + version: 'unknown', + }; + + if (await fs.pathExists(moduleConfigPath)) { + try { + const configContent = await fs.readFile(moduleConfigPath, 'utf8'); + const config = yaml.parse(configContent); + moduleInfo.version = config.version || 'unknown'; + moduleInfo.name = config.name || moduleId; + moduleInfo.description = config.description; + } catch { + // Ignore config read errors + } + } + + modules.push(moduleInfo); + } + } + + const installed = hasCore || modules.length > 0 || !!manifestData; + + if (!installed) { + return ExistingInstall.empty(); + } + + return new ExistingInstall({ installed, version, hasCore, modules, ides }); + } +} + +module.exports = { ExistingInstall }; diff --git a/tools/installer/core/install-paths.js b/tools/installer/core/install-paths.js new file mode 100644 index 000000000..f1c50ee43 --- /dev/null +++ b/tools/installer/core/install-paths.js @@ -0,0 +1,126 @@ +const path = require('node:path'); +const fs = require('fs-extra'); +const { getProjectRoot } = require('../project-root'); +const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils'); + +class InstallPaths { + static async create(config) { + const srcDir = getProjectRoot(); + await assertReadableDir(srcDir, 'BMAD source root'); + + const pkgPath = path.join(srcDir, 'package.json'); + await assertReadableFile(pkgPath, 'package.json'); + const version = require(pkgPath).version; + + const projectRoot = path.resolve(config.directory); + await ensureWritableDir(projectRoot, 'project root'); + + const bmadDir = path.join(projectRoot, BMAD_FOLDER_NAME); + const isUpdate = await fs.pathExists(bmadDir); + + const configDir = path.join(bmadDir, '_config'); + const agentsDir = path.join(configDir, 'agents'); + const coreDir = path.join(bmadDir, 'core'); + + for (const [dir, label] of [ + [bmadDir, 'bmad directory'], + [configDir, 'config directory'], + [agentsDir, 'agents config directory'], + [coreDir, 'core module directory'], + ]) { + await ensureWritableDir(dir, label); + } + + return new InstallPaths({ + srcDir, + version, + projectRoot, + bmadDir, + configDir, + agentsDir, + coreDir, + isUpdate, + }); + } + + constructor(props) { + Object.assign(this, props); + Object.freeze(this); + } + + manifestFile() { + return path.join(this.configDir, 'manifest.yaml'); + } + agentManifest() { + return path.join(this.configDir, 'agent-manifest.csv'); + } + filesManifest() { + return path.join(this.configDir, 'files-manifest.csv'); + } + helpCatalog() { + return path.join(this.configDir, 'bmad-help.csv'); + } + moduleDir(name) { + return path.join(this.bmadDir, name); + } + moduleConfig(name) { + return path.join(this.bmadDir, name, 'config.yaml'); + } +} + +async function assertReadableDir(dirPath, label) { + const stat = await fs.stat(dirPath).catch(() => null); + if (!stat) { + throw new Error(`${label} does not exist: ${dirPath}`); + } + if (!stat.isDirectory()) { + throw new Error(`${label} is not a directory: ${dirPath}`); + } + try { + await fs.access(dirPath, fs.constants.R_OK); + } catch { + throw new Error(`${label} is not readable: ${dirPath}`); + } +} + +async function assertReadableFile(filePath, label) { + const stat = await fs.stat(filePath).catch(() => null); + if (!stat) { + throw new Error(`${label} does not exist: ${filePath}`); + } + if (!stat.isFile()) { + throw new Error(`${label} is not a file: ${filePath}`); + } + try { + await fs.access(filePath, fs.constants.R_OK); + } catch { + throw new Error(`${label} is not readable: ${filePath}`); + } +} + +async function ensureWritableDir(dirPath, label) { + const stat = await fs.stat(dirPath).catch(() => null); + if (stat && !stat.isDirectory()) { + throw new Error(`${label} exists but is not a directory: ${dirPath}`); + } + + try { + await fs.ensureDir(dirPath); + } catch (error) { + if (error.code === 'EACCES') { + throw new Error(`${label}: permission denied creating directory: ${dirPath}`); + } + if (error.code === 'ENOSPC') { + throw new Error(`${label}: no space left on device: ${dirPath}`); + } + throw new Error(`${label}: cannot create directory: ${dirPath} (${error.message})`); + } + + try { + await fs.access(dirPath, fs.constants.R_OK | fs.constants.W_OK); + } catch { + throw new Error(`${label} is not writable: ${dirPath}`); + } +} + +module.exports = { InstallPaths }; diff --git a/tools/installer/core/installer.js b/tools/installer/core/installer.js new file mode 100644 index 000000000..95e16adfe --- /dev/null +++ b/tools/installer/core/installer.js @@ -0,0 +1,1507 @@ +const path = require('node:path'); +const fs = require('fs-extra'); +const { Manifest } = require('./manifest'); +const { OfficialModules } = require('../modules/official-modules'); +const { IdeManager } = require('../ide/manager'); +const { FileOps } = require('../file-ops'); +const { Config } = require('./config'); +const { getProjectRoot, getSourcePath } = require('../project-root'); +const { ManifestGenerator } = require('./manifest-generator'); +const prompts = require('../prompts'); +const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils'); +const { InstallPaths } = require('./install-paths'); +const { ExternalModuleManager } = require('../modules/external-manager'); + +const { ExistingInstall } = require('./existing-install'); + +class Installer { + constructor() { + this.externalModuleManager = new ExternalModuleManager(); + this.manifest = new Manifest(); + this.ideManager = new IdeManager(); + this.fileOps = new FileOps(); + this.installedFiles = new Set(); // Track all installed files + this.bmadFolderName = BMAD_FOLDER_NAME; + } + + /** + * Read the module version from .claude-plugin/marketplace.json + * Walks up from sourcePath looking for .claude-plugin/marketplace.json + * @param {string} sourcePath - Module source directory + * @returns {string} Version string or empty string + */ + async _getMarketplaceVersion(sourcePath) { + let dir = sourcePath; + for (let i = 0; i < 5; i++) { + const marketplacePath = path.join(dir, '.claude-plugin', 'marketplace.json'); + if (await fs.pathExists(marketplacePath)) { + try { + const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8')); + return this._extractMarketplaceVersion(data); + } catch { + return ''; + } + } + const parent = path.dirname(dir); + if (parent === dir) break; + dir = parent; + } + return ''; + } + + /** + * Extract the highest version from marketplace.json plugins array + */ + _extractMarketplaceVersion(data) { + const plugins = data?.plugins; + if (!Array.isArray(plugins) || plugins.length === 0) return ''; + let best = ''; + for (const p of plugins) { + if (p.version && (!best || p.version > best)) best = p.version; + } + return best; + } + + /** + * Main installation method + * @param {Object} config - Installation configuration + * @param {string} config.directory - Target directory + * @param {string[]} config.modules - Modules to install (including 'core') + * @param {string[]} config.ides - IDEs to configure + */ + async install(originalConfig) { + let updateState = null; + + try { + const config = Config.build(originalConfig); + const paths = await InstallPaths.create(config); + const officialModules = await OfficialModules.build(config, paths); + const existingInstall = await ExistingInstall.detect(paths.bmadDir); + + if (existingInstall.installed) { + await this._removeDeselectedModules(existingInstall, config, paths); + updateState = await this._prepareUpdateState(paths, config, existingInstall, officialModules); + await this._removeDeselectedIdes(existingInstall, config, paths); + } + + await this._validateIdeSelection(config); + + // Capture pre-install module versions for from→to display + const preInstallVersions = new Map(); + if (existingInstall.installed) { + const existingModules = await this.manifest.getAllModuleVersions(paths.bmadDir); + for (const mod of existingModules) { + if (mod.name && mod.version) { + preInstallVersions.set(mod.name, mod.version); + } + } + } + + // Results collector for consolidated summary + const results = []; + const addResult = (step, status, detail = '', meta = {}) => results.push({ step, status, detail, ...meta }); + + // Capture previously installed skill IDs before they get overwritten + const previousSkillIds = new Set(); + const prevCsvPath = path.join(paths.bmadDir, '_config', 'skill-manifest.csv'); + if (await fs.pathExists(prevCsvPath)) { + try { + const csvParse = require('csv-parse/sync'); + const content = await fs.readFile(prevCsvPath, 'utf8'); + const records = csvParse.parse(content, { columns: true, skip_empty_lines: true }); + for (const r of records) { + if (r.canonicalId) previousSkillIds.add(r.canonicalId); + } + } catch (error) { + await prompts.log.warn(`Failed to parse skill-manifest.csv: ${error.message}`); + } + } + + const allModules = config.modules || []; + + await this._installAndConfigure(config, originalConfig, paths, allModules, allModules, addResult, officialModules); + + await this._setupIdes(config, allModules, paths, addResult, previousSkillIds); + + // Skills are now in IDE directories — remove redundant copies from _bmad/. + // Also cleans up skill dirs left by older installer versions. + await this._cleanupSkillDirs(paths.bmadDir); + + const restoreResult = await this._restoreUserFiles(paths, updateState); + + // Render consolidated summary + await this.renderInstallSummary(results, { + bmadDir: paths.bmadDir, + modules: config.modules, + ides: config.ides, + customFiles: restoreResult.customFiles.length > 0 ? restoreResult.customFiles : undefined, + modifiedFiles: restoreResult.modifiedFiles.length > 0 ? restoreResult.modifiedFiles : undefined, + preInstallVersions, + }); + + return { + success: true, + path: paths.bmadDir, + modules: config.modules, + ides: config.ides, + projectDir: paths.projectRoot, + }; + } catch (error) { + await prompts.log.error('Installation failed'); + + // Clean up any temp backup directories that were created before the failure + try { + if (updateState?.tempBackupDir && (await fs.pathExists(updateState.tempBackupDir))) { + await fs.remove(updateState.tempBackupDir); + } + if (updateState?.tempModifiedBackupDir && (await fs.pathExists(updateState.tempModifiedBackupDir))) { + await fs.remove(updateState.tempModifiedBackupDir); + } + } catch { + // Best-effort cleanup — don't mask the original error + } + + throw error; + } + } + + /** + * Remove modules that were previously installed but are no longer selected. + * No confirmation — the user's module selection is the decision. + */ + async _removeDeselectedModules(existingInstall, config, paths) { + const previouslyInstalled = new Set(existingInstall.moduleIds); + const newlySelected = new Set(config.modules || []); + const toRemove = [...previouslyInstalled].filter((m) => !newlySelected.has(m) && m !== 'core'); + + for (const moduleId of toRemove) { + const modulePath = paths.moduleDir(moduleId); + try { + if (await fs.pathExists(modulePath)) { + await fs.remove(modulePath); + } + } catch (error) { + await prompts.log.warn(`Warning: Failed to remove ${moduleId}: ${error.message}`); + } + } + } + + /** + * Fail fast if all selected IDEs are suspended. + */ + async _validateIdeSelection(config) { + if (!config.ides || config.ides.length === 0) return; + + await this.ideManager.ensureInitialized(); + const suspendedIdes = config.ides.filter((ide) => { + const handler = this.ideManager.handlers.get(ide); + return handler?.platformConfig?.suspended; + }); + + if (suspendedIdes.length > 0 && suspendedIdes.length === config.ides.length) { + for (const ide of suspendedIdes) { + const handler = this.ideManager.handlers.get(ide); + await prompts.log.error(`${handler.displayName || ide}: ${handler.platformConfig.suspended}`); + } + throw new Error( + `All selected tool(s) are suspended: ${suspendedIdes.join(', ')}. Installation aborted to prevent upgrading _bmad/ without a working IDE configuration.`, + ); + } + } + + /** + * Remove IDEs that were previously installed but are no longer selected. + * No confirmation — the user's IDE selection is the decision. + */ + async _removeDeselectedIdes(existingInstall, config, paths) { + const previouslyInstalled = new Set(existingInstall.ides); + const newlySelected = new Set(config.ides || []); + const toRemove = [...previouslyInstalled].filter((ide) => !newlySelected.has(ide)); + + if (toRemove.length === 0) return; + + await this.ideManager.ensureInitialized(); + for (const ide of toRemove) { + try { + const handler = this.ideManager.handlers.get(ide); + if (handler) { + await handler.cleanup(paths.projectRoot); + } + } catch (error) { + await prompts.log.warn(`Warning: Failed to remove ${ide}: ${error.message}`); + } + } + } + + /** + * Install modules, create directories, generate configs and manifests. + */ + async _installAndConfigure(config, originalConfig, paths, officialModuleIds, allModules, addResult, officialModules) { + const isQuickUpdate = config.isQuickUpdate(); + const moduleConfigs = officialModules.moduleConfigs; + + const dirResults = { createdDirs: [], movedDirs: [], createdWdsFolders: [] }; + + const installTasks = []; + + if (allModules.length > 0) { + installTasks.push({ + title: isQuickUpdate ? `Updating ${allModules.length} module(s)` : `Installing ${allModules.length} module(s)`, + task: async (message) => { + const installedModuleNames = new Set(); + + await this._installOfficialModules(config, paths, officialModuleIds, addResult, isQuickUpdate, officialModules, { + message, + installedModuleNames, + }); + + return `${allModules.length} module(s) ${isQuickUpdate ? 'updated' : 'installed'}`; + }, + }); + } + + installTasks.push({ + title: 'Creating module directories', + task: async (message) => { + const verboseMode = process.env.BMAD_VERBOSE_INSTALL === 'true' || config.verbose; + const moduleLogger = { + log: async (msg) => (verboseMode ? await prompts.log.message(msg) : undefined), + error: async (msg) => await prompts.log.error(msg), + warn: async (msg) => await prompts.log.warn(msg), + }; + + if (config.modules && config.modules.length > 0) { + for (const moduleName of config.modules) { + message(`Setting up ${moduleName}...`); + const result = await officialModules.createModuleDirectories(moduleName, paths.bmadDir, { + installedIDEs: config.ides || [], + moduleConfig: moduleConfigs[moduleName] || {}, + existingModuleConfig: officialModules.existingConfig?.[moduleName] || {}, + coreConfig: moduleConfigs.core || {}, + logger: moduleLogger, + silent: true, + }); + if (result) { + dirResults.createdDirs.push(...result.createdDirs); + dirResults.movedDirs.push(...(result.movedDirs || [])); + dirResults.createdWdsFolders.push(...result.createdWdsFolders); + } + } + } + + addResult('Module directories', 'ok'); + return 'Module directories created'; + }, + }); + + const configTask = { + title: 'Generating configurations', + task: async (message) => { + await this.generateModuleConfigs(paths.bmadDir, moduleConfigs); + addResult('Configurations', 'ok', 'generated'); + + this.installedFiles.add(paths.manifestFile()); + this.installedFiles.add(paths.agentManifest()); + + message('Generating manifests...'); + const manifestGen = new ManifestGenerator(); + + const allModulesForManifest = config.isQuickUpdate() + ? originalConfig._existingModules || allModules || [] + : originalConfig._preserveModules + ? [...allModules, ...originalConfig._preserveModules] + : allModules || []; + + let modulesForCsvPreserve; + if (config.isQuickUpdate()) { + modulesForCsvPreserve = originalConfig._existingModules || allModules || []; + } else { + modulesForCsvPreserve = originalConfig._preserveModules ? [...allModules, ...originalConfig._preserveModules] : allModules; + } + + await manifestGen.generateManifests(paths.bmadDir, allModulesForManifest, [...this.installedFiles], { + ides: config.ides || [], + preservedModules: modulesForCsvPreserve, + }); + + message('Generating help catalog...'); + await this.mergeModuleHelpCatalogs(paths.bmadDir); + addResult('Help catalog', 'ok'); + + return 'Configurations generated'; + }, + }; + installTasks.push(configTask); + + // Run install + dirs first, then render dir output, then run config generation + const mainTasks = installTasks.filter((t) => t !== configTask); + await prompts.tasks(mainTasks); + + const color = await prompts.getColor(); + if (dirResults.movedDirs.length > 0) { + const lines = dirResults.movedDirs.map((d) => ` ${d}`).join('\n'); + await prompts.log.message(color.cyan(`Moved directories:\n${lines}`)); + } + if (dirResults.createdDirs.length > 0) { + const lines = dirResults.createdDirs.map((d) => ` ${d}`).join('\n'); + await prompts.log.message(color.yellow(`Created directories:\n${lines}`)); + } + if (dirResults.createdWdsFolders.length > 0) { + const lines = dirResults.createdWdsFolders.map((f) => color.dim(` \u2713 ${f}/`)).join('\n'); + await prompts.log.message(color.cyan(`Created WDS folder structure:\n${lines}`)); + } + + await prompts.tasks([configTask]); + } + + /** + * Set up IDE integrations for each selected IDE. + */ + async _setupIdes(config, allModules, paths, addResult, previousSkillIds = new Set()) { + if (config.skipIde || !config.ides || config.ides.length === 0) return; + + await this.ideManager.ensureInitialized(); + const validIdes = config.ides.filter((ide) => ide && typeof ide === 'string'); + + if (validIdes.length === 0) { + addResult('IDE configuration', 'warn', 'no valid IDEs selected'); + return; + } + + for (const ide of validIdes) { + const setupResult = await this.ideManager.setup(ide, paths.projectRoot, paths.bmadDir, { + selectedModules: allModules || [], + verbose: config.verbose, + previousSkillIds, + }); + + if (setupResult.success) { + addResult(ide, 'ok', setupResult.detail || ''); + } else { + addResult(ide, 'error', setupResult.error || 'failed'); + } + } + } + + /** + * Remove skill directories from _bmad/ after IDE installation. + * Skills are self-contained in IDE directories, so _bmad/ only needs + * module-level files (config.yaml, _config/, etc.). + * Also cleans up skill dirs left by older installer versions. + * @param {string} bmadDir - BMAD installation directory + */ + async _cleanupSkillDirs(bmadDir) { + const csv = require('csv-parse/sync'); + const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv'); + if (!(await fs.pathExists(csvPath))) return; + + const csvContent = await fs.readFile(csvPath, 'utf8'); + const records = csv.parse(csvContent, { columns: true, skip_empty_lines: true }); + const bmadFolderName = path.basename(bmadDir); + const bmadPrefix = bmadFolderName + '/'; + + for (const record of records) { + if (!record.path) continue; + const relativePath = record.path.startsWith(bmadPrefix) ? record.path.slice(bmadPrefix.length) : record.path; + const sourceDir = path.dirname(path.join(bmadDir, relativePath)); + if (await fs.pathExists(sourceDir)) { + await fs.remove(sourceDir); + } + } + } + + /** + * Restore custom and modified files that were backed up before the update. + * No-op for fresh installs (updateState is null). + * @param {Object} paths - InstallPaths instance + * @param {Object|null} updateState - From _prepareUpdateState, or null for fresh installs + * @returns {Object} { customFiles, modifiedFiles } — lists of restored files + */ + async _restoreUserFiles(paths, updateState) { + const noFiles = { customFiles: [], modifiedFiles: [] }; + + if (!updateState || (updateState.customFiles.length === 0 && updateState.modifiedFiles.length === 0)) { + return noFiles; + } + + let restoredCustomFiles = []; + let restoredModifiedFiles = []; + + await prompts.tasks([ + { + title: 'Finalizing installation', + task: async (message) => { + if (updateState.customFiles.length > 0) { + message(`Restoring ${updateState.customFiles.length} custom files...`); + + for (const originalPath of updateState.customFiles) { + const relativePath = path.relative(paths.bmadDir, originalPath); + const backupPath = path.join(updateState.tempBackupDir, relativePath); + + if (await fs.pathExists(backupPath)) { + await fs.ensureDir(path.dirname(originalPath)); + await fs.copy(backupPath, originalPath, { overwrite: true }); + } + } + + if (updateState.tempBackupDir && (await fs.pathExists(updateState.tempBackupDir))) { + await fs.remove(updateState.tempBackupDir); + } + + restoredCustomFiles = updateState.customFiles; + } + + if (updateState.modifiedFiles.length > 0) { + restoredModifiedFiles = updateState.modifiedFiles; + + if (updateState.tempModifiedBackupDir && (await fs.pathExists(updateState.tempModifiedBackupDir))) { + message(`Restoring ${restoredModifiedFiles.length} modified files as .bak...`); + + for (const modifiedFile of restoredModifiedFiles) { + const relativePath = path.relative(paths.bmadDir, modifiedFile.path); + const tempBackupPath = path.join(updateState.tempModifiedBackupDir, relativePath); + const bakPath = modifiedFile.path + '.bak'; + + if (await fs.pathExists(tempBackupPath)) { + await fs.ensureDir(path.dirname(bakPath)); + await fs.copy(tempBackupPath, bakPath, { overwrite: true }); + } + } + + await fs.remove(updateState.tempModifiedBackupDir); + } + } + + return 'Installation finalized'; + }, + }, + ]); + + return { customFiles: restoredCustomFiles, modifiedFiles: restoredModifiedFiles }; + } + + /** + * Common update preparation: detect files, preserve core config, back up. + * @param {Object} paths - InstallPaths instance + * @param {Object} config - Clean config (may have coreConfig updated) + * @param {Object} existingInstall - Detection result + * @param {Object} officialModules - OfficialModules instance + * @returns {Object} Update state: { customFiles, modifiedFiles, tempBackupDir, tempModifiedBackupDir } + */ + async _prepareUpdateState(paths, config, existingInstall, officialModules) { + // Detect custom and modified files BEFORE updating (compare current files vs files-manifest.csv) + const existingFilesManifest = await this.readFilesManifest(paths.bmadDir); + const { customFiles, modifiedFiles } = await this.detectCustomFiles(paths.bmadDir, existingFilesManifest); + + // Preserve existing core configuration during updates + // (no-op for quick-update which already has core config from collectModuleConfigQuick) + const coreConfigPath = paths.moduleConfig('core'); + if ((await fs.pathExists(coreConfigPath)) && (!config.coreConfig || Object.keys(config.coreConfig).length === 0)) { + try { + const yaml = require('yaml'); + const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8'); + const existingCoreConfig = yaml.parse(coreConfigContent); + + config.coreConfig = existingCoreConfig; + officialModules.moduleConfigs.core = existingCoreConfig; + } catch (error) { + await prompts.log.warn(`Warning: Could not read existing core config: ${error.message}`); + } + } + + const backupDirs = await this._backupUserFiles(paths, customFiles, modifiedFiles); + + return { + customFiles, + modifiedFiles, + tempBackupDir: backupDirs.tempBackupDir, + tempModifiedBackupDir: backupDirs.tempModifiedBackupDir, + }; + } + + /** + * Back up custom and modified files to temp directories before overwriting. + * Returns the temp directory paths (or undefined if no files to back up). + * @param {Object} paths - InstallPaths instance + * @param {string[]} customFiles - Absolute paths of custom (user-added) files + * @param {Object[]} modifiedFiles - Array of { path, relativePath } for modified files + * @returns {Object} { tempBackupDir, tempModifiedBackupDir } — undefined if no files + */ + async _backupUserFiles(paths, customFiles, modifiedFiles) { + let tempBackupDir; + let tempModifiedBackupDir; + + if (customFiles.length > 0) { + tempBackupDir = path.join(paths.projectRoot, '_bmad-custom-backup-temp'); + await fs.ensureDir(tempBackupDir); + + for (const customFile of customFiles) { + const relativePath = path.relative(paths.bmadDir, customFile); + const backupPath = path.join(tempBackupDir, relativePath); + await fs.ensureDir(path.dirname(backupPath)); + await fs.copy(customFile, backupPath); + } + } + + if (modifiedFiles.length > 0) { + tempModifiedBackupDir = path.join(paths.projectRoot, '_bmad-modified-backup-temp'); + await fs.ensureDir(tempModifiedBackupDir); + + for (const modifiedFile of modifiedFiles) { + const relativePath = path.relative(paths.bmadDir, modifiedFile.path); + const tempBackupPath = path.join(tempModifiedBackupDir, relativePath); + await fs.ensureDir(path.dirname(tempBackupPath)); + await fs.copy(modifiedFile.path, tempBackupPath, { overwrite: true }); + } + } + + return { tempBackupDir, tempModifiedBackupDir }; + } + + /** + * Install official (non-custom) modules. + * @param {Object} config - Installation configuration + * @param {Object} paths - InstallPaths instance + * @param {string[]} officialModuleIds - Official module IDs to install + * @param {Function} addResult - Callback to record installation results + * @param {boolean} isQuickUpdate - Whether this is a quick update + * @param {Object} ctx - Shared context: { message, installedModuleNames } + */ + async _installOfficialModules(config, paths, officialModuleIds, addResult, isQuickUpdate, officialModules, ctx) { + const { message, installedModuleNames } = ctx; + const { CustomModuleManager } = require('../modules/custom-module-manager'); + + for (const moduleName of officialModuleIds) { + if (installedModuleNames.has(moduleName)) continue; + installedModuleNames.add(moduleName); + + message(`${isQuickUpdate ? 'Updating' : 'Installing'} ${moduleName}...`); + + const moduleConfig = officialModules.moduleConfigs[moduleName] || {}; + const installResult = await officialModules.install( + moduleName, + paths.bmadDir, + (filePath) => { + this.installedFiles.add(filePath); + }, + { + skipModuleInstaller: true, + moduleConfig: moduleConfig, + installer: this, + silent: true, + }, + ); + + // Get display name from source module.yaml; version from resolution cache or marketplace.json + const sourcePath = await officialModules.findModuleSource(moduleName, { silent: true }); + const moduleInfo = sourcePath ? await officialModules.getModuleInfo(sourcePath, moduleName, '') : null; + const displayName = moduleInfo?.name || moduleName; + + // Prefer version from resolution cache (accurate for custom/local modules), + // fall back to marketplace.json walk-up for official modules + const cachedResolution = CustomModuleManager._resolutionCache.get(moduleName); + const version = cachedResolution?.version || (sourcePath ? await this._getMarketplaceVersion(sourcePath) : ''); + addResult(displayName, 'ok', '', { moduleCode: moduleName, newVersion: version }); + } + } + + /** + * Read files-manifest.csv + * @param {string} bmadDir - BMAD installation directory + * @returns {Array} Array of file entries from files-manifest.csv + */ + async readFilesManifest(bmadDir) { + const filesManifestPath = path.join(bmadDir, '_config', 'files-manifest.csv'); + if (!(await fs.pathExists(filesManifestPath))) { + return []; + } + + try { + const content = await fs.readFile(filesManifestPath, 'utf8'); + const lines = content.split('\n'); + const files = []; + + for (let i = 1; i < lines.length; i++) { + // Skip header + const line = lines[i].trim(); + if (!line) continue; + + // Parse CSV line properly handling quoted values + const parts = []; + let current = ''; + let inQuotes = false; + + for (const char of line) { + if (char === '"') { + inQuotes = !inQuotes; + } else if (char === ',' && !inQuotes) { + parts.push(current); + current = ''; + } else { + current += char; + } + } + parts.push(current); // Add last part + + if (parts.length >= 4) { + files.push({ + type: parts[0], + name: parts[1], + module: parts[2], + path: parts[3], + hash: parts[4] || null, // Hash may not exist in old manifests + }); + } + } + + return files; + } catch (error) { + await prompts.log.warn('Could not read files-manifest.csv: ' + error.message); + return []; + } + } + + /** + * Detect custom and modified files + * @param {string} bmadDir - BMAD installation directory + * @param {Array} existingFilesManifest - Previous files from files-manifest.csv + * @returns {Object} Object with customFiles and modifiedFiles arrays + */ + async detectCustomFiles(bmadDir, existingFilesManifest) { + const customFiles = []; + const modifiedFiles = []; + + // Memory is always in _bmad/_memory + const bmadMemoryPath = '_memory'; + + // Check if the manifest has hashes - if not, we can't detect modifications + let manifestHasHashes = false; + if (existingFilesManifest && existingFilesManifest.length > 0) { + manifestHasHashes = existingFilesManifest.some((f) => f.hash); + } + + // Build map of previously installed files from files-manifest.csv with their hashes + const installedFilesMap = new Map(); + for (const fileEntry of existingFilesManifest) { + if (fileEntry.path) { + const absolutePath = path.join(bmadDir, fileEntry.path); + installedFilesMap.set(path.normalize(absolutePath), { + hash: fileEntry.hash, + relativePath: fileEntry.path, + }); + } + } + + // Recursively scan bmadDir for all files + const scanDirectory = async (dir) => { + try { + const entries = await fs.readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + // Skip certain directories + if (entry.name === 'node_modules' || entry.name === '.git') { + continue; + } + await scanDirectory(fullPath); + } else if (entry.isFile()) { + const normalizedPath = path.normalize(fullPath); + const fileInfo = installedFilesMap.get(normalizedPath); + + // Skip certain system files that are auto-generated + const relativePath = path.relative(bmadDir, fullPath); + const fileName = path.basename(fullPath); + + // Skip _config directory EXCEPT for modified agent customizations + if (relativePath.startsWith('_config/') || relativePath.startsWith('_config\\')) { + // Special handling for .customize.yaml files - only preserve if modified + if (relativePath.includes('/agents/') && fileName.endsWith('.customize.yaml')) { + // Check if the customization file has been modified from manifest + const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml'); + if (await fs.pathExists(manifestPath)) { + const crypto = require('node:crypto'); + const currentContent = await fs.readFile(fullPath, 'utf8'); + const currentHash = crypto.createHash('sha256').update(currentContent).digest('hex'); + + const yaml = require('yaml'); + const manifestContent = await fs.readFile(manifestPath, 'utf8'); + const manifestData = yaml.parse(manifestContent); + const originalHash = manifestData.agentCustomizations?.[relativePath]; + + // Only add to customFiles if hash differs (user modified) + if (originalHash && currentHash !== originalHash) { + customFiles.push(fullPath); + } + } + } + continue; + } + + if (relativePath.startsWith(bmadMemoryPath + '/') && path.dirname(relativePath).includes('-sidecar')) { + continue; + } + + // Skip config.yaml files - these are regenerated on each install/update + if (fileName === 'config.yaml') { + continue; + } + + if (!fileInfo) { + // File not in manifest = custom file + // EXCEPT: Agent .md files in module folders are generated files, not custom + // Only treat .md files under _config/agents/ as custom + if (!(fileName.endsWith('.md') && relativePath.includes('/agents/') && !relativePath.startsWith('_config/'))) { + customFiles.push(fullPath); + } + } else if (manifestHasHashes && fileInfo.hash) { + // File in manifest with hash - check if it was modified + const currentHash = await this.manifest.calculateFileHash(fullPath); + if (currentHash && currentHash !== fileInfo.hash) { + // Hash changed = file was modified + modifiedFiles.push({ + path: fullPath, + relativePath: fileInfo.relativePath, + }); + } + } + } + } + } catch { + // Ignore errors scanning directories + } + }; + + await scanDirectory(bmadDir); + return { customFiles, modifiedFiles }; + } + + /** + * Generate clean config.yaml files for each installed module + * @param {string} bmadDir - BMAD installation directory + * @param {Object} moduleConfigs - Collected configuration values + */ + async generateModuleConfigs(bmadDir, moduleConfigs) { + const yaml = require('yaml'); + + // Extract core config values to share with other modules + const coreConfig = moduleConfigs.core || {}; + + // Get all installed module directories + const entries = await fs.readdir(bmadDir, { withFileTypes: true }); + const installedModules = entries + .filter((entry) => entry.isDirectory() && entry.name !== '_config' && entry.name !== 'docs') + .map((entry) => entry.name); + + // Generate config.yaml for each installed module + for (const moduleName of installedModules) { + const modulePath = path.join(bmadDir, moduleName); + + // Get module-specific config or use empty object if none + const config = moduleConfigs[moduleName] || {}; + + if (await fs.pathExists(modulePath)) { + const configPath = path.join(modulePath, 'config.yaml'); + + // Create header + const packageJson = require(path.join(getProjectRoot(), 'package.json')); + const header = `# ${moduleName.toUpperCase()} Module Configuration +# Generated by BMAD installer +# Version: ${packageJson.version} +# Date: ${new Date().toISOString()} + +`; + + // For non-core modules, add core config values directly + let finalConfig = { ...config }; + let coreSection = ''; + + if (moduleName !== 'core' && coreConfig && Object.keys(coreConfig).length > 0) { + // Add core values directly to the module config + // These will be available for reference in the module + finalConfig = { + ...config, + ...coreConfig, // Spread core config values directly into the module config + }; + + // Create a comment section to identify core values + coreSection = '\n# Core Configuration Values\n'; + } + + // Clean the config to remove any non-serializable values (like functions) + const cleanConfig = structuredClone(finalConfig); + + // Convert config to YAML + let yamlContent = yaml.stringify(cleanConfig, { + indent: 2, + lineWidth: 0, + minContentWidth: 0, + }); + + // If we have core values, reorganize the YAML to group them with their comment + if (coreSection && moduleName !== 'core') { + // Split the YAML into lines + const lines = yamlContent.split('\n'); + const moduleConfigLines = []; + const coreConfigLines = []; + + // Separate module-specific and core config lines + for (const line of lines) { + const key = line.split(':')[0].trim(); + if (Object.prototype.hasOwnProperty.call(coreConfig, key)) { + coreConfigLines.push(line); + } else { + moduleConfigLines.push(line); + } + } + + // Rebuild YAML with module config first, then core config with comment + yamlContent = moduleConfigLines.join('\n'); + if (coreConfigLines.length > 0) { + yamlContent += coreSection + coreConfigLines.join('\n'); + } + } + + // Write the clean config file with POSIX-compliant final newline + const content = header + yamlContent; + await fs.writeFile(configPath, content.endsWith('\n') ? content : content + '\n', 'utf8'); + + // Track the config file in installedFiles + this.installedFiles.add(configPath); + } + } + } + + /** + * Merge all module-help.csv files into a single bmad-help.csv + * Scans all installed modules for module-help.csv and merges them + * Enriches agent info from agent-manifest.csv + * Output is written to _bmad/_config/bmad-help.csv + * @param {string} bmadDir - BMAD installation directory + */ + async mergeModuleHelpCatalogs(bmadDir) { + const allRows = []; + const headerRow = + 'module,phase,name,code,sequence,workflow-file,command,required,agent-name,agent-command,agent-display-name,agent-title,options,description,output-location,outputs'; + + // Load agent manifest for agent info lookup + const agentManifestPath = path.join(bmadDir, '_config', 'agent-manifest.csv'); + const agentInfo = new Map(); // agent-name -> {command, displayName, title+icon} + + if (await fs.pathExists(agentManifestPath)) { + const manifestContent = await fs.readFile(agentManifestPath, 'utf8'); + const lines = manifestContent.split('\n').filter((line) => line.trim()); + + for (const line of lines) { + if (line.startsWith('name,')) continue; // Skip header + + const cols = line.split(','); + if (cols.length >= 4) { + const agentName = cols[0].replaceAll('"', '').trim(); + const displayName = cols[1].replaceAll('"', '').trim(); + const title = cols[2].replaceAll('"', '').trim(); + const icon = cols[3].replaceAll('"', '').trim(); + const module = cols[10] ? cols[10].replaceAll('"', '').trim() : ''; + + // Build agent command: bmad:module:agent:name + const agentCommand = module ? `bmad:${module}:agent:${agentName}` : `bmad:agent:${agentName}`; + + agentInfo.set(agentName, { + command: agentCommand, + displayName: displayName || agentName, + title: icon && title ? `${icon} ${title}` : title || agentName, + }); + } + } + } + + // Get all installed module directories + const entries = await fs.readdir(bmadDir, { withFileTypes: true }); + const installedModules = entries + .filter((entry) => entry.isDirectory() && entry.name !== '_config' && entry.name !== 'docs' && entry.name !== '_memory') + .map((entry) => entry.name); + + // Add core module to scan (it's installed at root level as _config, but we check src/core-skills) + const coreModulePath = getSourcePath('core-skills'); + const modulePaths = new Map(); + + // Map all module source paths + if (await fs.pathExists(coreModulePath)) { + modulePaths.set('core', coreModulePath); + } + + // Map installed module paths + for (const moduleName of installedModules) { + const modulePath = path.join(bmadDir, moduleName); + modulePaths.set(moduleName, modulePath); + } + + // Scan each module for module-help.csv + for (const [moduleName, modulePath] of modulePaths) { + const helpFilePath = path.join(modulePath, 'module-help.csv'); + + if (await fs.pathExists(helpFilePath)) { + try { + const content = await fs.readFile(helpFilePath, 'utf8'); + const lines = content.split('\n').filter((line) => line.trim() && !line.startsWith('#')); + + for (const line of lines) { + // Skip header row + if (line.startsWith('module,')) { + continue; + } + + // Parse the line - handle quoted fields with commas + const columns = this.parseCSVLine(line); + if (columns.length >= 12) { + // Map old schema to new schema + // Old: module,phase,name,code,sequence,workflow-file,command,required,agent,options,description,output-location,outputs + // New: module,phase,name,code,sequence,workflow-file,command,required,agent-name,agent-command,agent-display-name,agent-title,options,description,output-location,outputs + + const [ + module, + phase, + name, + code, + sequence, + workflowFile, + command, + required, + agentName, + options, + description, + outputLocation, + outputs, + ] = columns; + + // Pass through _meta rows as-is (module metadata, not a skill) + if (phase === '_meta') { + const finalModule = (!module || module.trim() === '') && moduleName !== 'core' ? moduleName : module || ''; + const metaRow = [finalModule, '_meta', '', '', '', '', '', 'false', '', '', '', '', '', '', outputLocation || '', '']; + allRows.push(metaRow.map((c) => this.escapeCSVField(c)).join(',')); + continue; + } + + // If module column is empty, set it to this module's name (except for core which stays empty for universal tools) + const finalModule = (!module || module.trim() === '') && moduleName !== 'core' ? moduleName : module || ''; + + // Lookup agent info + const cleanAgentName = agentName ? agentName.trim() : ''; + const agentData = agentInfo.get(cleanAgentName) || { command: '', displayName: '', title: '' }; + + // Build new row with agent info + const newRow = [ + finalModule, + phase || '', + name || '', + code || '', + sequence || '', + workflowFile || '', + command || '', + required || 'false', + cleanAgentName, + agentData.command, + agentData.displayName, + agentData.title, + options || '', + description || '', + outputLocation || '', + outputs || '', + ]; + + allRows.push(newRow.map((c) => this.escapeCSVField(c)).join(',')); + } + } + + if (process.env.BMAD_VERBOSE_INSTALL === 'true') { + await prompts.log.message(` Merged module-help from: ${moduleName}`); + } + } catch (error) { + await prompts.log.warn(` Warning: Failed to read module-help.csv from ${moduleName}: ${error.message}`); + } + } + } + + // Sort by module, then phase, then sequence + allRows.sort((a, b) => { + const colsA = this.parseCSVLine(a); + const colsB = this.parseCSVLine(b); + + // Module comparison (empty module/universal tools come first) + const moduleA = (colsA[0] || '').toLowerCase(); + const moduleB = (colsB[0] || '').toLowerCase(); + if (moduleA !== moduleB) { + return moduleA.localeCompare(moduleB); + } + + // Phase comparison + const phaseA = colsA[1] || ''; + const phaseB = colsB[1] || ''; + if (phaseA !== phaseB) { + return phaseA.localeCompare(phaseB); + } + + // Sequence comparison + const seqA = parseInt(colsA[4] || '0', 10); + const seqB = parseInt(colsB[4] || '0', 10); + return seqA - seqB; + }); + + // Write merged catalog + const outputDir = path.join(bmadDir, '_config'); + await fs.ensureDir(outputDir); + const outputPath = path.join(outputDir, 'bmad-help.csv'); + + const mergedContent = [headerRow, ...allRows].join('\n'); + await fs.writeFile(outputPath, mergedContent, 'utf8'); + + // Track the installed file + this.installedFiles.add(outputPath); + + if (process.env.BMAD_VERBOSE_INSTALL === 'true') { + await prompts.log.message(` Generated bmad-help.csv: ${allRows.length} workflows`); + } + } + + /** + * Render a consolidated install summary using prompts.note() + * @param {Array} results - Array of {step, status: 'ok'|'error'|'warn', detail} + * @param {Object} context - {bmadDir, modules, ides, customFiles, modifiedFiles} + */ + async renderInstallSummary(results, context = {}) { + const color = await prompts.getColor(); + const selectedIdes = new Set((context.ides || []).map((ide) => String(ide).toLowerCase())); + + // Build step lines with status indicators + const preVersions = context.preInstallVersions || new Map(); + const lines = []; + for (const r of results) { + const stepLabel = r.step; + + let icon; + if (r.status === 'ok') { + icon = color.green('\u2713'); + } else if (r.status === 'warn') { + icon = color.yellow('!'); + } else { + icon = color.red('\u2717'); + } + + // Build version detail for module results + let detail = ''; + if (r.moduleCode && r.newVersion) { + const oldVersion = preVersions.get(r.moduleCode); + if (oldVersion && oldVersion === r.newVersion) { + detail = ` (v${r.newVersion}, no change)`; + } else if (oldVersion) { + detail = ` (v${oldVersion} → v${r.newVersion})`; + } else { + detail = ` (v${r.newVersion}, installed)`; + } + } else if (r.detail) { + detail = ` (${r.detail})`; + } + lines.push(` ${icon} ${stepLabel}${detail}`); + } + + if ((context.ides || []).length === 0) { + lines.push(` ${color.green('\u2713')} No IDE selected (installed in _bmad only)`); + } + + // Context and warnings + lines.push(''); + if (context.bmadDir) { + lines.push(` Installed to: ${context.bmadDir}`); + } + if (context.customFiles && context.customFiles.length > 0) { + lines.push(` ${color.cyan(`Custom files preserved: ${context.customFiles.length}`)}`); + } + if (context.modifiedFiles && context.modifiedFiles.length > 0) { + lines.push(` ${color.yellow(`Modified files backed up (.bak): ${context.modifiedFiles.length}`)}`); + } + + // Next steps + lines.push( + '', + ' Get started:', + ` 1. Launch your AI agent from your project folder`, + ` 2. Not sure what to do? Invoke the ${color.cyan('bmad-help')} skill and ask it what to do!`, + '', + ` Blog, Docs and Guides: ${color.blue('https://bmadcode.com/')}`, + ` Community: ${color.blue('https://discord.gg/gk8jAdXWmj')}`, + ); + + await prompts.box(lines.join('\n'), 'BMAD is ready to use!', { + rounded: true, + formatBorder: color.green, + }); + } + + /** + * Quick update method - preserves all settings and only prompts for new config fields + * @param {Object} config - Configuration with directory + * @returns {Object} Update result + */ + async quickUpdate(config) { + const projectDir = path.resolve(config.directory); + const { bmadDir } = await this.findBmadDir(projectDir); + + // Check if bmad directory exists + if (!(await fs.pathExists(bmadDir))) { + throw new Error(`BMAD not installed at ${bmadDir}. Use regular install for first-time setup.`); + } + + // Detect existing installation + const existingInstall = await ExistingInstall.detect(bmadDir); + const installedModules = existingInstall.moduleIds; + const configuredIdes = existingInstall.ides; + const projectRoot = path.dirname(bmadDir); + + // Get available modules (what we have source for) + const availableModulesData = await new OfficialModules().listAvailable(); + const availableModules = [...availableModulesData.modules]; + + // Add external official modules to available modules + const externalModules = await this.externalModuleManager.listAvailable(); + for (const externalModule of externalModules) { + if (installedModules.includes(externalModule.code) && !availableModules.some((m) => m.id === externalModule.code)) { + availableModules.push({ + id: externalModule.code, + name: externalModule.name, + isExternal: true, + fromExternal: true, + }); + } + } + + // Add installed community modules to available modules + const { CommunityModuleManager } = require('../modules/community-manager'); + const communityMgr = new CommunityModuleManager(); + const communityModules = await communityMgr.listAll(); + for (const communityModule of communityModules) { + if (installedModules.includes(communityModule.code) && !availableModules.some((m) => m.id === communityModule.code)) { + availableModules.push({ + id: communityModule.code, + name: communityModule.displayName, + isExternal: true, + fromCommunity: true, + }); + } + } + + // Add installed custom modules to available modules + const { CustomModuleManager } = require('../modules/custom-module-manager'); + const customMgr = new CustomModuleManager(); + for (const moduleId of installedModules) { + if (!availableModules.some((m) => m.id === moduleId)) { + const customSource = await customMgr.findModuleSourceByCode(moduleId, { bmadDir }); + if (customSource) { + availableModules.push({ + id: moduleId, + name: moduleId, + isExternal: true, + fromCustom: true, + }); + } + } + } + + const availableModuleIds = new Set(availableModules.map((m) => m.id)); + + // Only update modules that are BOTH installed AND available (we have source for) + const modulesToUpdate = installedModules.filter((id) => availableModuleIds.has(id)); + const skippedModules = installedModules.filter((id) => !availableModuleIds.has(id)); + + if (skippedModules.length > 0) { + await prompts.log.warn(`Skipping ${skippedModules.length} module(s) - no source available: ${skippedModules.join(', ')}`); + } + + // Load existing configs and collect new fields (if any) + await prompts.log.info('Checking for new configuration options...'); + const quickModules = new OfficialModules(); + await quickModules.loadExistingConfig(projectDir); + + let promptedForNewFields = false; + + const corePrompted = await quickModules.collectModuleConfigQuick('core', projectDir, true); + if (corePrompted) { + promptedForNewFields = true; + } + + for (const moduleName of modulesToUpdate) { + if (moduleName === 'core') continue; // Already collected above + const modulePrompted = await quickModules.collectModuleConfigQuick(moduleName, projectDir, true); + if (modulePrompted) { + promptedForNewFields = true; + } + } + + if (!promptedForNewFields) { + await prompts.log.success('All configuration is up to date, no new options to configure'); + } + + quickModules.collectedConfig._meta = { + version: require(path.join(getProjectRoot(), 'package.json')).version, + installDate: new Date().toISOString(), + lastModified: new Date().toISOString(), + }; + + // Build config and delegate to install() + const installConfig = { + directory: projectDir, + modules: modulesToUpdate, + ides: configuredIdes, + coreConfig: quickModules.collectedConfig.core, + moduleConfigs: quickModules.collectedConfig, + actionType: 'install', + _quickUpdate: true, + _preserveModules: skippedModules, + _existingModules: installedModules, + }; + + await this.install(installConfig); + + return { + success: true, + moduleCount: modulesToUpdate.length, + hadNewFields: promptedForNewFields, + modules: modulesToUpdate, + skippedModules: skippedModules, + ides: configuredIdes, + }; + } + + /** + * Uninstall BMAD with selective removal options + * @param {string} directory - Project directory + * @param {Object} options - Uninstall options + * @param {boolean} [options.removeModules=true] - Remove _bmad/ directory + * @param {boolean} [options.removeIdeConfigs=true] - Remove IDE configurations + * @param {boolean} [options.removeOutputFolder=false] - Remove user artifacts output folder + * @returns {Object} Result with success status and removed components + */ + async uninstall(directory, options = {}) { + const projectDir = path.resolve(directory); + const { bmadDir } = await this.findBmadDir(projectDir); + + if (!(await fs.pathExists(bmadDir))) { + return { success: false, reason: 'not-installed' }; + } + + // 1. DETECT: Read state BEFORE deleting anything + const existingInstall = await ExistingInstall.detect(bmadDir); + const outputFolder = await this._readOutputFolder(bmadDir); + + const removed = { modules: false, ideConfigs: false, outputFolder: false }; + + // 2. IDE CLEANUP (before _bmad/ deletion so configs are accessible) + if (options.removeIdeConfigs !== false) { + await this.uninstallIdeConfigs(projectDir, existingInstall, { silent: options.silent }); + removed.ideConfigs = true; + } + + // 3. OUTPUT FOLDER (only if explicitly requested) + if (options.removeOutputFolder === true && outputFolder) { + removed.outputFolder = await this.uninstallOutputFolder(projectDir, outputFolder); + } + + // 4. BMAD DIRECTORY (last, after everything that needs it) + if (options.removeModules !== false) { + removed.modules = await this.uninstallModules(projectDir); + } + + return { success: true, removed, version: existingInstall.installed ? existingInstall.version : null }; + } + + /** + * Uninstall IDE configurations only + * @param {string} projectDir - Project directory + * @param {Object} existingInstall - Detection result from detector.detect() + * @param {Object} [options] - Options (e.g. { silent: true }) + * @returns {Promise} Results from IDE cleanup + */ + async uninstallIdeConfigs(projectDir, existingInstall, options = {}) { + await this.ideManager.ensureInitialized(); + const cleanupOptions = { isUninstall: true, silent: options.silent }; + const ideList = existingInstall.ides; + if (ideList.length > 0) { + return this.ideManager.cleanupByList(projectDir, ideList, cleanupOptions); + } + return this.ideManager.cleanup(projectDir, cleanupOptions); + } + + /** + * Remove user artifacts output folder + * @param {string} projectDir - Project directory + * @param {string} outputFolder - Output folder name (relative) + * @returns {Promise} Whether the folder was removed + */ + async uninstallOutputFolder(projectDir, outputFolder) { + if (!outputFolder) return false; + const resolvedProject = path.resolve(projectDir); + const outputPath = path.resolve(resolvedProject, outputFolder); + if (!outputPath.startsWith(resolvedProject + path.sep)) { + return false; + } + if (await fs.pathExists(outputPath)) { + await fs.remove(outputPath); + return true; + } + return false; + } + + /** + * Remove the _bmad/ directory + * @param {string} projectDir - Project directory + * @returns {Promise} Whether the directory was removed + */ + async uninstallModules(projectDir) { + const { bmadDir } = await this.findBmadDir(projectDir); + if (await fs.pathExists(bmadDir)) { + await fs.remove(bmadDir); + return true; + } + return false; + } + + /** + * Get installation status + */ + async getStatus(directory) { + const projectDir = path.resolve(directory); + const { bmadDir } = await this.findBmadDir(projectDir); + return await ExistingInstall.detect(bmadDir); + } + + /** + * Get available modules + */ + async getAvailableModules() { + return await new OfficialModules().listAvailable(); + } + + /** + * Get the configured output folder name for a project + * Resolves bmadDir internally from projectDir + * @param {string} projectDir - Project directory + * @returns {string} Output folder name (relative, default: '_bmad-output') + */ + async getOutputFolder(projectDir) { + const { bmadDir } = await this.findBmadDir(projectDir); + return this._readOutputFolder(bmadDir); + } + + /** + * Find the bmad installation directory in a project + * Always uses the standard _bmad folder name + * @param {string} projectDir - Project directory + * @returns {Promise} { bmadDir: string } + */ + async findBmadDir(projectDir) { + const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME); + return { bmadDir }; + } + + /** + * Read the output_folder setting from module config files + * Checks bmm/config.yaml first, then other module configs + * @param {string} bmadDir - BMAD installation directory + * @returns {string} Output folder path or default + */ + async _readOutputFolder(bmadDir) { + const yaml = require('yaml'); + + // Check bmm/config.yaml first (most common) + const bmmConfigPath = path.join(bmadDir, 'bmm', 'config.yaml'); + if (await fs.pathExists(bmmConfigPath)) { + try { + const content = await fs.readFile(bmmConfigPath, 'utf8'); + const config = yaml.parse(content); + if (config && config.output_folder) { + // Strip {project-root}/ prefix if present + return config.output_folder.replace(/^\{project-root\}[/\\]/, ''); + } + } catch { + // Fall through to other modules + } + } + + // Scan other module config.yaml files + try { + const entries = await fs.readdir(bmadDir, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory() || entry.name === 'bmm' || entry.name.startsWith('_')) continue; + const configPath = path.join(bmadDir, entry.name, 'config.yaml'); + if (await fs.pathExists(configPath)) { + try { + const content = await fs.readFile(configPath, 'utf8'); + const config = yaml.parse(content); + if (config && config.output_folder) { + return config.output_folder.replace(/^\{project-root\}[/\\]/, ''); + } + } catch { + // Continue scanning + } + } + } + } catch { + // Directory scan failed + } + + // Default fallback + return '_bmad-output'; + } + + /** + * Parse a CSV line, handling quoted fields + * @param {string} line - CSV line to parse + * @returns {Array} Array of field values + */ + parseCSVLine(line) { + const result = []; + let current = ''; + let inQuotes = false; + + for (let i = 0; i < line.length; i++) { + const char = line[i]; + const nextChar = line[i + 1]; + + if (char === '"') { + if (inQuotes && nextChar === '"') { + // Escaped quote + current += '"'; + i++; // Skip next quote + } else { + // Toggle quote mode + inQuotes = !inQuotes; + } + } else if (char === ',' && !inQuotes) { + result.push(current); + current = ''; + } else { + current += char; + } + } + result.push(current); + return result; + } + + /** + * Escape a CSV field if it contains special characters + * @param {string} field - Field value to escape + * @returns {string} Escaped field + */ + escapeCSVField(field) { + if (field === null || field === undefined) { + return ''; + } + const str = String(field); + // If field contains comma, quote, or newline, wrap in quotes and escape inner quotes + if (str.includes(',') || str.includes('"') || str.includes('\n')) { + return `"${str.replaceAll('"', '""')}"`; + } + return str; + } +} + +module.exports = { Installer }; diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/installer/core/manifest-generator.js similarity index 96% rename from tools/cli/installers/lib/core/manifest-generator.js rename to tools/installer/core/manifest-generator.js index 14fd8887e..13e33af56 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/installer/core/manifest-generator.js @@ -3,17 +3,16 @@ const fs = require('fs-extra'); const yaml = require('yaml'); const crypto = require('node:crypto'); const csv = require('csv-parse/sync'); -const { getSourcePath, getModulePath } = require('../../../lib/project-root'); -const prompts = require('../../../lib/prompts'); +const { getSourcePath, getModulePath } = require('../project-root'); +const prompts = require('../prompts'); const { loadSkillManifest: loadSkillManifestShared, getCanonicalId: getCanonicalIdShared, getArtifactType: getArtifactTypeShared, - getInstallToBmad: getInstallToBmadShared, } = require('../ide/shared/skill-manifest'); // Load package.json for version info -const packageJson = require('../../../../../package.json'); +const packageJson = require('../../../package.json'); /** * Generates manifest files for installed skills and agents @@ -42,11 +41,6 @@ class ManifestGenerator { return getArtifactTypeShared(manifest, filename); } - /** Delegate to shared skill-manifest module */ - getInstallToBmad(manifest, filename) { - return getInstallToBmadShared(manifest, filename); - } - /** * Clean text for CSV output by normalizing whitespace. * Note: Quote escaping is handled by escapeCsv() at write time. @@ -127,7 +121,7 @@ class ManifestGenerator { * Recursively walk a module directory tree, collecting native SKILL.md entrypoints. * A directory is discovered as a skill when it contains a SKILL.md file with * valid name/description frontmatter (name must match directory name). - * Manifest YAML is loaded only when present — for install_to_bmad and agent metadata. + * Manifest YAML is loaded only when present — for agent metadata. * Populates this.skills[] and this.skillClaimedDirs (Set of absolute paths). */ async collectSkills() { @@ -156,7 +150,7 @@ class ManifestGenerator { const skillMeta = await this.parseSkillMd(skillMdPath, dir, dirName, debug); if (skillMeta) { - // Load manifest when present (for install_to_bmad and agent metadata) + // Load manifest when present (for agent metadata) const manifest = await this.loadSkillManifest(dir); const artifactType = this.getArtifactType(manifest, skillFile); @@ -182,7 +176,6 @@ class ManifestGenerator { module: moduleName, path: installPath, canonicalId, - install_to_bmad: this.getInstallToBmad(manifest, skillFile), }); // Add to files list @@ -377,11 +370,11 @@ class ManifestGenerator { */ async writeMainManifest(cfgDir) { const manifestPath = path.join(cfgDir, 'manifest.yaml'); + const installedModuleSet = new Set(this.modules); // Read existing manifest to preserve install date let existingInstallDate = null; const existingModulesMap = new Map(); - if (await fs.pathExists(manifestPath)) { try { const existingContent = await fs.readFile(manifestPath, 'utf8'); @@ -419,7 +412,7 @@ class ManifestGenerator { // Get existing install date if available const existing = existingModulesMap.get(moduleName); - updatedModules.push({ + const moduleEntry = { name: moduleName, version: versionInfo.version, installDate: existing?.installDate || new Date().toISOString(), @@ -427,7 +420,9 @@ class ManifestGenerator { source: versionInfo.source, npmPackage: versionInfo.npmPackage, repoUrl: versionInfo.repoUrl, - }); + }; + if (versionInfo.localPath) moduleEntry.localPath = versionInfo.localPath; + updatedModules.push(moduleEntry); } const manifest = { @@ -463,7 +458,7 @@ class ManifestGenerator { const csvPath = path.join(cfgDir, 'skill-manifest.csv'); const escapeCsv = (value) => `"${String(value ?? '').replaceAll('"', '""')}"`; - let csvContent = 'canonicalId,name,description,module,path,install_to_bmad\n'; + let csvContent = 'canonicalId,name,description,module,path\n'; for (const skill of this.skills) { const row = [ @@ -472,7 +467,6 @@ class ManifestGenerator { escapeCsv(skill.description), escapeCsv(skill.module), escapeCsv(skill.path), - escapeCsv(skill.install_to_bmad), ].join(','); csvContent += row + '\n'; } diff --git a/tools/installer/core/manifest.js b/tools/installer/core/manifest.js new file mode 100644 index 000000000..aaa86649a --- /dev/null +++ b/tools/installer/core/manifest.js @@ -0,0 +1,455 @@ +const path = require('node:path'); +const fs = require('fs-extra'); +const crypto = require('node:crypto'); +const { getProjectRoot } = require('../project-root'); +const prompts = require('../prompts'); + +class Manifest { + /** + * Create a new manifest + * @param {string} bmadDir - Path to bmad directory + * @param {Object} data - Manifest data + * @param {Array} installedFiles - List of installed files (no longer used, files tracked in files-manifest.csv) + */ + async create(bmadDir, data, installedFiles = []) { + const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml'); + const yaml = require('yaml'); + + // Ensure _config directory exists + await fs.ensureDir(path.dirname(manifestPath)); + + // Get the BMad version from package.json + const bmadVersion = data.version || require(path.join(process.cwd(), 'package.json')).version; + + // Convert module list to new detailed format + const moduleDetails = []; + if (data.modules && Array.isArray(data.modules)) { + for (const moduleName of data.modules) { + // Core and BMM modules use the BMad version + const moduleVersion = moduleName === 'core' || moduleName === 'bmm' ? bmadVersion : null; + const now = data.installDate || new Date().toISOString(); + + moduleDetails.push({ + name: moduleName, + version: moduleVersion, + installDate: now, + lastUpdated: now, + source: moduleName === 'core' || moduleName === 'bmm' ? 'built-in' : 'unknown', + }); + } + } + + // Structure the manifest data + const manifestData = { + installation: { + version: bmadVersion, + installDate: data.installDate || new Date().toISOString(), + lastUpdated: data.lastUpdated || new Date().toISOString(), + }, + modules: moduleDetails, + ides: data.ides || [], + }; + + // Write YAML manifest + // Clean the manifest data to remove any non-serializable values + const cleanManifestData = structuredClone(manifestData); + + const yamlContent = yaml.stringify(cleanManifestData, { + indent: 2, + lineWidth: 0, + sortKeys: false, + }); + + // Ensure POSIX-compliant final newline + const content = yamlContent.endsWith('\n') ? yamlContent : yamlContent + '\n'; + await fs.writeFile(manifestPath, content, 'utf8'); + return { success: true, path: manifestPath, filesTracked: 0 }; + } + + /** + * Read existing manifest + * @param {string} bmadDir - Path to bmad directory + * @returns {Object|null} Manifest data or null if not found + */ + async read(bmadDir) { + const yamlPath = path.join(bmadDir, '_config', 'manifest.yaml'); + const yaml = require('yaml'); + + if (await fs.pathExists(yamlPath)) { + try { + const content = await fs.readFile(yamlPath, 'utf8'); + const manifestData = yaml.parse(content); + + // Handle new detailed module format + const modules = manifestData.modules || []; + + // For backward compatibility: if modules is an array of strings (old format), + // the calling code may need the array of names + const moduleNames = modules.map((m) => (typeof m === 'string' ? m : m.name)); + + // Check if we have the new detailed format + const hasDetailedModules = modules.length > 0 && typeof modules[0] === 'object'; + + // Flatten the structure for compatibility with existing code + return { + version: manifestData.installation?.version, + installDate: manifestData.installation?.installDate, + lastUpdated: manifestData.installation?.lastUpdated, + modules: moduleNames, // Simple array of module names for backward compatibility + modulesDetailed: hasDetailedModules ? modules : null, // New detailed format + ides: manifestData.ides || [], + }; + } catch (error) { + await prompts.log.error(`Failed to read YAML manifest: ${error.message}`); + } + } + + return null; + } + + /** + * Read raw manifest data without flattening + * @param {string} bmadDir - Path to bmad directory + * @returns {Object|null} Raw manifest data or null if not found + */ + async _readRaw(bmadDir) { + const yamlPath = path.join(bmadDir, '_config', 'manifest.yaml'); + const yaml = require('yaml'); + + if (await fs.pathExists(yamlPath)) { + try { + const content = await fs.readFile(yamlPath, 'utf8'); + return yaml.parse(content); + } catch (error) { + await prompts.log.error(`Failed to read YAML manifest: ${error.message}`); + } + } + + return null; + } + + /** + * Flatten manifest for backward compatibility + * @param {Object} manifest - Raw manifest data + * @returns {Object} Flattened manifest + */ + _flattenManifest(manifest) { + const modules = manifest.modules || []; + const moduleNames = modules.map((m) => (typeof m === 'string' ? m : m.name)); + const hasDetailedModules = modules.length > 0 && typeof modules[0] === 'object'; + + return { + version: manifest.installation?.version, + installDate: manifest.installation?.installDate, + lastUpdated: manifest.installation?.lastUpdated, + modules: moduleNames, + modulesDetailed: hasDetailedModules ? modules : null, + ides: manifest.ides || [], + }; + } + + /** + * Add a module to the manifest with optional version info + * If module already exists, update its version info + * @param {string} bmadDir - Path to bmad directory + * @param {string} moduleName - Module name to add + * @param {Object} options - Optional version info + */ + async addModule(bmadDir, moduleName, options = {}) { + let manifest = await this._readRaw(bmadDir); + if (!manifest) { + // Bootstrap a minimal manifest if it doesn't exist yet + // (e.g., skill-only modules with no agents to compile) + manifest = { modules: [] }; + } + + if (!manifest.modules) { + manifest.modules = []; + } + + const existingIndex = manifest.modules.findIndex((m) => m.name === moduleName); + + if (existingIndex === -1) { + // Module doesn't exist, add it + const entry = { + name: moduleName, + version: options.version || null, + installDate: new Date().toISOString(), + lastUpdated: new Date().toISOString(), + source: options.source || 'unknown', + npmPackage: options.npmPackage || null, + repoUrl: options.repoUrl || null, + }; + if (options.localPath) entry.localPath = options.localPath; + manifest.modules.push(entry); + } else { + // Module exists, update its version info + const existing = manifest.modules[existingIndex]; + manifest.modules[existingIndex] = { + ...existing, + version: options.version === undefined ? existing.version : options.version, + source: options.source || existing.source, + npmPackage: options.npmPackage === undefined ? existing.npmPackage : options.npmPackage, + repoUrl: options.repoUrl === undefined ? existing.repoUrl : options.repoUrl, + localPath: options.localPath === undefined ? existing.localPath : options.localPath, + lastUpdated: new Date().toISOString(), + }; + } + + await this._writeRaw(bmadDir, manifest); + } + + /** + * Get all modules with their version info + * @param {string} bmadDir - Path to bmad directory + * @returns {Array} Array of module info objects + */ + async getAllModuleVersions(bmadDir) { + const manifest = await this._readRaw(bmadDir); + if (!manifest || !manifest.modules) { + return []; + } + + return manifest.modules; + } + + /** + * Write raw manifest data to file + * @param {string} bmadDir - Path to bmad directory + * @param {Object} manifestData - Raw manifest data to write + */ + async _writeRaw(bmadDir, manifestData) { + const yaml = require('yaml'); + const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml'); + + await fs.ensureDir(path.dirname(manifestPath)); + + const cleanManifestData = structuredClone(manifestData); + + const yamlContent = yaml.stringify(cleanManifestData, { + indent: 2, + lineWidth: 0, + sortKeys: false, + }); + + const content = yamlContent.endsWith('\n') ? yamlContent : yamlContent + '\n'; + await fs.writeFile(manifestPath, content, 'utf8'); + } + + /** + * Calculate SHA256 hash of a file + * @param {string} filePath - Path to file + * @returns {string} SHA256 hash + */ + async calculateFileHash(filePath) { + try { + const content = await fs.readFile(filePath); + return crypto.createHash('sha256').update(content).digest('hex'); + } catch { + return null; + } + } + + /** + * Get module version info from source + * @param {string} moduleName - Module name/code + * @param {string} bmadDir - Path to bmad directory + * @param {string} moduleSourcePath - Optional source path for custom modules + * @returns {Object} Version info object with version, source, npmPackage, repoUrl + */ + async getModuleVersionInfo(moduleName, bmadDir, moduleSourcePath = null) { + const yaml = require('yaml'); + + // Resolve source type first, then read version with the correct path context + if (['core', 'bmm'].includes(moduleName)) { + const version = await this._readMarketplaceVersion(moduleName, moduleSourcePath); + return { + version, + source: 'built-in', + npmPackage: null, + repoUrl: null, + }; + } + + // Check if this is an external official module + const { ExternalModuleManager } = require('../modules/external-manager'); + const extMgr = new ExternalModuleManager(); + const moduleInfo = await extMgr.getModuleByCode(moduleName); + + if (moduleInfo) { + // External module: use moduleSourcePath if provided, otherwise fall back to cache + const version = await this._readMarketplaceVersion(moduleName, moduleSourcePath); + return { + version, + source: 'external', + npmPackage: moduleInfo.npmPackage || null, + repoUrl: moduleInfo.url || null, + }; + } + + // Check if this is a community module + const { CommunityModuleManager } = require('../modules/community-manager'); + const communityMgr = new CommunityModuleManager(); + const communityInfo = await communityMgr.getModuleByCode(moduleName); + if (communityInfo) { + const communityVersion = await this._readMarketplaceVersion(moduleName, moduleSourcePath); + return { + version: communityVersion || communityInfo.version, + source: 'community', + npmPackage: communityInfo.npmPackage || null, + repoUrl: communityInfo.url || null, + }; + } + + // Check if this is a custom module (from user-provided URL or local path) + const { CustomModuleManager } = require('../modules/custom-module-manager'); + const customMgr = new CustomModuleManager(); + const resolved = customMgr.getResolution(moduleName); + const customSource = await customMgr.findModuleSourceByCode(moduleName, { bmadDir }); + if (customSource || resolved) { + const customVersion = resolved?.version || (await this._readMarketplaceVersion(moduleName, moduleSourcePath)); + return { + version: customVersion, + source: 'custom', + npmPackage: null, + repoUrl: resolved?.repoUrl || null, + localPath: resolved?.localPath || null, + }; + } + + // Unknown module + const version = await this._readMarketplaceVersion(moduleName, moduleSourcePath); + return { + version, + source: 'unknown', + npmPackage: null, + repoUrl: null, + }; + } + + /** + * Read version from .claude-plugin/marketplace.json for a module + * @param {string} moduleName - Module code + * @returns {string|null} Version or null + */ + async _readMarketplaceVersion(moduleName, moduleSourcePath = null) { + const os = require('node:os'); + let marketplacePath; + + if (['core', 'bmm'].includes(moduleName)) { + marketplacePath = path.join(getProjectRoot(), '.claude-plugin', 'marketplace.json'); + } else if (moduleSourcePath) { + // Walk up from source path to find marketplace.json + let dir = moduleSourcePath; + for (let i = 0; i < 5; i++) { + const candidate = path.join(dir, '.claude-plugin', 'marketplace.json'); + if (await fs.pathExists(candidate)) { + marketplacePath = candidate; + break; + } + const parent = path.dirname(dir); + if (parent === dir) break; + dir = parent; + } + } + + // Fallback to external module cache + if (!marketplacePath) { + const cacheDir = path.join(os.homedir(), '.bmad', 'cache', 'external-modules', moduleName); + marketplacePath = path.join(cacheDir, '.claude-plugin', 'marketplace.json'); + } + + try { + if (await fs.pathExists(marketplacePath)) { + const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8')); + const plugins = data?.plugins; + if (!Array.isArray(plugins) || plugins.length === 0) return null; + let best = null; + for (const p of plugins) { + if (p.version && (!best || p.version > best)) best = p.version; + } + return best; + } + } catch { + // ignore + } + return null; + } + + /** + * Fetch latest version from npm for a package + * @param {string} packageName - npm package name + * @returns {string|null} Latest version or null + */ + async fetchNpmVersion(packageName) { + try { + const https = require('node:https'); + const { execSync } = require('node:child_process'); + + // Try using npm view first (more reliable) + try { + const result = execSync(`npm view ${packageName} version`, { + encoding: 'utf8', + stdio: 'pipe', + timeout: 10_000, + }); + return result.trim(); + } catch { + // Fallback to npm registry API + return new Promise((resolve, reject) => { + https + .get(`https://registry.npmjs.org/${packageName}`, (res) => { + let data = ''; + res.on('data', (chunk) => (data += chunk)); + res.on('end', () => { + try { + const pkg = JSON.parse(data); + resolve(pkg['dist-tags']?.latest || pkg.version || null); + } catch { + resolve(null); + } + }); + }) + .on('error', () => resolve(null)); + }); + } + } catch { + return null; + } + } + + /** + * Check for available updates for installed modules + * @param {string} bmadDir - Path to bmad directory + * @returns {Array} Array of update info objects + */ + async checkForUpdates(bmadDir) { + const modules = await this.getAllModuleVersions(bmadDir); + const updates = []; + + for (const module of modules) { + if (!module.npmPackage) { + continue; // Skip modules without npm package (built-in) + } + + const latestVersion = await this.fetchNpmVersion(module.npmPackage); + if (!latestVersion) { + continue; + } + + if (module.version !== latestVersion) { + updates.push({ + name: module.name, + installedVersion: module.version, + latestVersion: latestVersion, + npmPackage: module.npmPackage, + updateAvailable: true, + }); + } + } + + return updates; + } +} + +module.exports = { Manifest }; diff --git a/tools/cli/lib/file-ops.js b/tools/installer/file-ops.js similarity index 100% rename from tools/cli/lib/file-ops.js rename to tools/installer/file-ops.js diff --git a/tools/installer/ide/_config-driven.js b/tools/installer/ide/_config-driven.js new file mode 100644 index 000000000..9c7df4bc5 --- /dev/null +++ b/tools/installer/ide/_config-driven.js @@ -0,0 +1,647 @@ +const os = require('node:os'); +const path = require('node:path'); +const fs = require('fs-extra'); +const yaml = require('yaml'); +const prompts = require('../prompts'); +const csv = require('csv-parse/sync'); +const { BMAD_FOLDER_NAME } = require('./shared/path-utils'); + +/** + * Config-driven IDE setup handler + * + * This class provides a standardized way to install BMAD artifacts to IDEs + * based on configuration in platform-codes.yaml. It eliminates the need for + * individual installer files for each IDE. + * + * Features: + * - Config-driven from platform-codes.yaml + * - Verbatim skill installation from skill-manifest.csv + * - Legacy directory cleanup and IDE-specific marker removal + */ +class ConfigDrivenIdeSetup { + constructor(platformCode, platformConfig) { + this.name = platformCode; + this.displayName = platformConfig.name || platformCode; + this.preferred = platformConfig.preferred || false; + this.platformConfig = platformConfig; + this.installerConfig = platformConfig.installer || null; + this.bmadFolderName = BMAD_FOLDER_NAME; + + // Set configDir from target_dir so detect() works + this.configDir = this.installerConfig?.target_dir || null; + } + + setBmadFolderName(bmadFolderName) { + this.bmadFolderName = bmadFolderName; + } + + /** + * Detect whether this IDE already has configuration in the project. + * Checks for bmad-prefixed entries in target_dir. + * @param {string} projectDir - Project directory + * @returns {Promise} + */ + async detect(projectDir) { + if (!this.configDir) return false; + + const dir = path.join(projectDir || process.cwd(), this.configDir); + if (await fs.pathExists(dir)) { + try { + const entries = await fs.readdir(dir); + return entries.some((e) => typeof e === 'string' && e.startsWith('bmad')); + } catch { + return false; + } + } + return false; + } + + /** + * Main setup method - called by IdeManager + * @param {string} projectDir - Project directory + * @param {string} bmadDir - BMAD installation directory + * @param {Object} options - Setup options + * @returns {Promise} Setup result + */ + async setup(projectDir, bmadDir, options = {}) { + // Check for BMAD files in ancestor directories that would cause duplicates + if (this.installerConfig?.ancestor_conflict_check) { + const conflict = await this.findAncestorConflict(projectDir); + if (conflict) { + await prompts.log.error( + `Found existing BMAD skills in ancestor installation: ${conflict}\n` + + ` ${this.name} inherits skills from parent directories, so this would cause duplicates.\n` + + ` Please remove the BMAD files from that directory first:\n` + + ` rm -rf "${conflict}"/bmad*`, + ); + return { + success: false, + reason: 'ancestor-conflict', + error: `Ancestor conflict: ${conflict}`, + conflictDir: conflict, + }; + } + } + + if (!options.silent) await prompts.log.info(`Setting up ${this.name}...`); + + // Clean up any old BMAD installation first + await this.cleanup(projectDir, options, bmadDir); + + if (!this.installerConfig) { + return { success: false, reason: 'no-config' }; + } + + if (this.installerConfig.target_dir) { + return this.installToTarget(projectDir, bmadDir, this.installerConfig, options); + } + + return { success: false, reason: 'invalid-config' }; + } + + /** + * Install to a single target directory + * @param {string} projectDir - Project directory + * @param {string} bmadDir - BMAD installation directory + * @param {Object} config - Installation configuration + * @param {Object} options - Setup options + * @returns {Promise} Installation result + */ + async installToTarget(projectDir, bmadDir, config, options) { + const { target_dir } = config; + const targetPath = path.join(projectDir, target_dir); + await fs.ensureDir(targetPath); + + this.skillWriteTracker = new Set(); + const results = { skills: 0 }; + + results.skills = await this.installVerbatimSkills(projectDir, bmadDir, targetPath, config); + results.skillDirectories = this.skillWriteTracker.size; + + await this.printSummary(results, target_dir, options); + this.skillWriteTracker = null; + return { success: true, results }; + } + + /** + * Install verbatim native SKILL.md directories from skill-manifest.csv. + * Copies the entire source directory as-is into the IDE skill directory. + * The source SKILL.md is used directly — no frontmatter transformation or file generation. + * @param {string} projectDir - Project directory + * @param {string} bmadDir - BMAD installation directory + * @param {string} targetPath - Target skills directory + * @param {Object} config - Installation configuration + * @returns {Promise} Count of skills installed + */ + async installVerbatimSkills(projectDir, bmadDir, targetPath, config) { + const bmadFolderName = path.basename(bmadDir); + const bmadPrefix = bmadFolderName + '/'; + const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv'); + + if (!(await fs.pathExists(csvPath))) return 0; + + const csvContent = await fs.readFile(csvPath, 'utf8'); + const records = csv.parse(csvContent, { + columns: true, + skip_empty_lines: true, + }); + + let count = 0; + + for (const record of records) { + const canonicalId = record.canonicalId; + if (!canonicalId) continue; + + // Derive source directory from path column + // path is like "_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/SKILL.md" + // Strip bmadFolderName prefix and join with bmadDir, then get dirname + const relativePath = record.path.startsWith(bmadPrefix) ? record.path.slice(bmadPrefix.length) : record.path; + const sourceFile = path.join(bmadDir, relativePath); + const sourceDir = path.dirname(sourceFile); + + if (!(await fs.pathExists(sourceDir))) continue; + + // Clean target before copy to prevent stale files + const skillDir = path.join(targetPath, canonicalId); + await fs.remove(skillDir); + await fs.ensureDir(skillDir); + this.skillWriteTracker?.add(canonicalId); + + // Copy all skill files, filtering OS/editor artifacts recursively + const skipPatterns = new Set(['.DS_Store', 'Thumbs.db', 'desktop.ini']); + const skipSuffixes = ['~', '.swp', '.swo', '.bak']; + const filter = (src) => { + const name = path.basename(src); + if (src === sourceDir) return true; + if (skipPatterns.has(name)) return false; + if (name.startsWith('.') && name !== '.gitkeep') return false; + if (skipSuffixes.some((s) => name.endsWith(s))) return false; + return true; + }; + await fs.copy(sourceDir, skillDir, { filter }); + + count++; + } + + return count; + } + + /** + * Print installation summary + * @param {Object} results - Installation results + * @param {string} targetDir - Target directory (relative) + */ + async printSummary(results, targetDir, options = {}) { + if (options.silent) return; + const count = results.skillDirectories || results.skills || 0; + if (count > 0) { + await prompts.log.success(`${this.name} configured: ${count} skills → ${targetDir}`); + } + } + + /** + * Cleanup IDE configuration + * @param {string} projectDir - Project directory + */ + async cleanup(projectDir, options = {}, bmadDir = null) { + const resolvedBmadDir = bmadDir || (await this._findBmadDir(projectDir)); + + // Build removal set: previously installed skills + removals.txt entries + let removalSet; + if (options.previousSkillIds && options.previousSkillIds.size > 0) { + // Install/update flow: use pre-captured skill IDs (before manifest was overwritten) + removalSet = new Set(options.previousSkillIds); + if (resolvedBmadDir) { + const removals = await this.loadRemovalLists(resolvedBmadDir); + for (const entry of removals) removalSet.add(entry); + } + } else if (resolvedBmadDir) { + // Uninstall flow: read from current skill-manifest.csv + removals.txt + removalSet = await this._buildUninstallSet(resolvedBmadDir); + } else { + removalSet = new Set(); + } + + // Migrate legacy target directories (e.g. .opencode/agent → .opencode/agents) + // Legacy dirs are abandoned entirely, so use prefix matching (null removalSet) + if (this.installerConfig?.legacy_targets) { + const legacyDirsExist = await Promise.all( + this.installerConfig.legacy_targets.map((d) => + this.isGlobalPath(d) ? fs.pathExists(d.replace(/^~/, os.homedir())) : fs.pathExists(path.join(projectDir, d)), + ), + ); + if (legacyDirsExist.some(Boolean)) { + if (!options.silent) await prompts.log.message(' Migrating legacy directories...'); + for (const legacyDir of this.installerConfig.legacy_targets) { + if (this.isGlobalPath(legacyDir)) { + await this.warnGlobalLegacy(legacyDir, options); + } else { + await this.cleanupTarget(projectDir, legacyDir, options, null); + await this.removeEmptyParents(projectDir, legacyDir); + } + } + } + } + + // Strip BMAD markers from copilot-instructions.md if present + if (this.name === 'github-copilot') { + await this.cleanupCopilotInstructions(projectDir, options); + } + + // Strip BMAD modes from .kilocodemodes if present + if (this.name === 'kilo') { + await this.cleanupKiloModes(projectDir, options); + } + + // Strip BMAD entries from .rovodev/prompts.yml if present + if (this.name === 'rovo-dev') { + await this.cleanupRovoDevPrompts(projectDir, options); + } + + // Clean current target directory + if (this.installerConfig?.target_dir) { + await this.cleanupTarget(projectDir, this.installerConfig.target_dir, options, removalSet); + } + } + + /** + * Check if a path is global (starts with ~ or is absolute) + * @param {string} p - Path to check + * @returns {boolean} + */ + isGlobalPath(p) { + return p.startsWith('~') || path.isAbsolute(p); + } + + /** + * Warn about stale BMAD files in a global legacy directory (never auto-deletes) + * @param {string} legacyDir - Legacy directory path (may start with ~) + * @param {Object} options - Options (silent, etc.) + */ + async warnGlobalLegacy(legacyDir, options = {}) { + try { + const expanded = legacyDir.startsWith('~/') + ? path.join(os.homedir(), legacyDir.slice(2)) + : legacyDir === '~' + ? os.homedir() + : legacyDir; + + if (!(await fs.pathExists(expanded))) return; + + const entries = await fs.readdir(expanded); + const bmadFiles = entries.filter((e) => typeof e === 'string' && e.startsWith('bmad')); + + if (bmadFiles.length > 0 && !options.silent) { + await prompts.log.warn(`Found ${bmadFiles.length} stale BMAD file(s) in ${expanded}. Remove manually: rm ${expanded}/bmad-*`); + } + } catch { + // Errors reading global paths are silently ignored + } + } + + /** + * Find the _bmad directory in a project + * @param {string} projectDir - Project directory + * @returns {string|null} Path to bmad dir or null + */ + async _findBmadDir(projectDir) { + const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME); + return (await fs.pathExists(bmadDir)) ? bmadDir : null; + } + + /** + * Build the full set of entries to remove for uninstall. + * Reads skill-manifest.csv to know exactly what was installed, plus removal lists. + * @param {string} bmadDir - BMAD installation directory + * @returns {Set} Set of entries to remove + */ + async _buildUninstallSet(bmadDir) { + const removals = await this.loadRemovalLists(bmadDir); + + // Also add all currently installed skills from skill-manifest.csv + const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv'); + try { + if (await fs.pathExists(csvPath)) { + const content = await fs.readFile(csvPath, 'utf8'); + const records = csv.parse(content, { columns: true, skip_empty_lines: true }); + for (const record of records) { + if (record.canonicalId) { + removals.add(record.canonicalId); + } + } + } + } catch { + // If we can't read the manifest, we still have the removal lists + } + + return removals; + } + + /** + * Load removal lists from all module sources in the bmad directory. + * Each module can have an optional removals.txt listing entries to remove. + * @param {string} bmadDir - BMAD installation directory + * @returns {Set} Set of entries to remove + */ + async loadRemovalLists(bmadDir) { + const removals = new Set(); + const { getProjectRoot } = require('../project-root'); + + // Read project-level removals.txt (covers core and bmm) + const projectRemovalsPath = path.join(getProjectRoot(), 'removals.txt'); + await this._readRemovalFile(projectRemovalsPath, removals); + + // Read per-module removals.txt from installed module directories + try { + const entries = await fs.readdir(bmadDir); + for (const entry of entries) { + if (entry.startsWith('_')) continue; + const removalPath = path.join(bmadDir, entry, 'removals.txt'); + await this._readRemovalFile(removalPath, removals); + } + } catch { + // bmadDir may not exist yet on fresh install + } + + return removals; + } + + /** + * Read a removals.txt file and add entries to the set + * @param {string} filePath - Path to removals.txt + * @param {Set} removals - Set to add entries to + */ + async _readRemovalFile(filePath, removals) { + try { + if (await fs.pathExists(filePath)) { + const content = await fs.readFile(filePath, 'utf8'); + for (const line of content.split('\n')) { + const trimmed = line.trim(); + if (trimmed && !trimmed.startsWith('#')) { + removals.add(trimmed); + } + } + } + } catch { + // Optional file — ignore errors + } + } + + /** + * Cleanup a specific target directory. + * When removalSet is provided, only removes entries in that set. + * When removalSet is null (legacy dirs), removes all bmad-prefixed entries. + * @param {string} projectDir - Project directory + * @param {string} targetDir - Target directory to clean + * @param {Object} options - Cleanup options + * @param {Set|null} removalSet - Entries to remove, or null for legacy prefix matching + */ + async cleanupTarget(projectDir, targetDir, options = {}, removalSet = new Set()) { + const targetPath = path.join(projectDir, targetDir); + + if (!(await fs.pathExists(targetPath))) { + return; + } + + if (removalSet && removalSet.size === 0) { + return; + } + + let entries; + try { + entries = await fs.readdir(targetPath); + } catch { + return; + } + + if (!entries || !Array.isArray(entries)) { + return; + } + + let removedCount = 0; + + for (const entry of entries) { + if (!entry || typeof entry !== 'string') continue; + + // Always preserve bmad-os-* utility skills regardless of cleanup mode + if (entry.startsWith('bmad-os-')) continue; + + // Surgical removal from set, or legacy prefix matching when set is null + const shouldRemove = removalSet ? removalSet.has(entry) : entry.startsWith('bmad'); + + if (shouldRemove) { + try { + await fs.remove(path.join(targetPath, entry)); + removedCount++; + } catch { + // Skip entries that can't be removed + } + } + } + + // Only log cleanup when it's not a routine reinstall (legacy dir cleanup or actual removals) + // Suppress for current target_dir since it's always cleaned before a fresh write + + // Remove empty directory after cleanup + if (removedCount > 0) { + try { + const remaining = await fs.readdir(targetPath); + if (remaining.length === 0) { + await fs.remove(targetPath); + } + } catch { + // Directory may already be gone or in use + } + } + } + + /** + * Strip BMAD-owned content from .github/copilot-instructions.md. + * The old custom installer injected content between and markers. + * Deletes the file if nothing remains. Restores .bak backup if one exists. + */ + async cleanupCopilotInstructions(projectDir, options = {}) { + const filePath = path.join(projectDir, '.github', 'copilot-instructions.md'); + + if (!(await fs.pathExists(filePath))) return; + + try { + const content = await fs.readFile(filePath, 'utf8'); + const startIdx = content.indexOf(''); + const endIdx = content.indexOf(''); + + if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) return; + + const cleaned = content.slice(0, startIdx) + content.slice(endIdx + ''.length); + + if (cleaned.trim().length === 0) { + await fs.remove(filePath); + const backupPath = `${filePath}.bak`; + if (await fs.pathExists(backupPath)) { + await fs.rename(backupPath, filePath); + if (!options.silent) await prompts.log.message(' Restored copilot-instructions.md from backup'); + } + } else { + await fs.writeFile(filePath, cleaned, 'utf8'); + const backupPath = `${filePath}.bak`; + if (await fs.pathExists(backupPath)) await fs.remove(backupPath); + } + + if (!options.silent) await prompts.log.message(' Cleaned BMAD markers from copilot-instructions.md'); + } catch { + if (!options.silent) await prompts.log.warn(' Warning: Could not clean BMAD markers from copilot-instructions.md'); + } + } + + /** + * Strip BMAD-owned modes from .kilocodemodes. + * The old custom kilo.js installer added modes with slug starting with 'bmad-'. + * Parses YAML, filters out BMAD modes, rewrites. Leaves file as-is on parse failure. + */ + async cleanupKiloModes(projectDir, options = {}) { + const kiloModesPath = path.join(projectDir, '.kilocodemodes'); + + if (!(await fs.pathExists(kiloModesPath))) return; + + const content = await fs.readFile(kiloModesPath, 'utf8'); + + let config; + try { + config = yaml.parse(content) || {}; + } catch { + if (!options.silent) await prompts.log.warn(' Warning: Could not parse .kilocodemodes for cleanup'); + return; + } + + if (!Array.isArray(config.customModes)) return; + + const originalCount = config.customModes.length; + config.customModes = config.customModes.filter((mode) => mode && (!mode.slug || !mode.slug.startsWith('bmad-'))); + const removedCount = originalCount - config.customModes.length; + + if (removedCount > 0) { + try { + await fs.writeFile(kiloModesPath, yaml.stringify(config, { lineWidth: 0 })); + if (!options.silent) await prompts.log.message(` Removed ${removedCount} BMAD modes from .kilocodemodes`); + } catch { + if (!options.silent) await prompts.log.warn(' Warning: Could not write .kilocodemodes during cleanup'); + } + } + } + + /** + * Strip BMAD-owned entries from .rovodev/prompts.yml. + * The old custom rovodev.js installer registered workflows in prompts.yml. + * Parses YAML, filters out entries with name starting with 'bmad-', rewrites. + * Removes the file if no entries remain. + */ + async cleanupRovoDevPrompts(projectDir, options = {}) { + const promptsPath = path.join(projectDir, '.rovodev', 'prompts.yml'); + + if (!(await fs.pathExists(promptsPath))) return; + + const content = await fs.readFile(promptsPath, 'utf8'); + + let config; + try { + config = yaml.parse(content) || {}; + } catch { + if (!options.silent) await prompts.log.warn(' Warning: Could not parse prompts.yml for cleanup'); + return; + } + + if (!Array.isArray(config.prompts)) return; + + const originalCount = config.prompts.length; + config.prompts = config.prompts.filter((entry) => entry && (!entry.name || !entry.name.startsWith('bmad-'))); + const removedCount = originalCount - config.prompts.length; + + if (removedCount > 0) { + try { + if (config.prompts.length === 0) { + await fs.remove(promptsPath); + } else { + await fs.writeFile(promptsPath, yaml.stringify(config, { lineWidth: 0 })); + } + if (!options.silent) await prompts.log.message(` Removed ${removedCount} BMAD entries from prompts.yml`); + } catch { + if (!options.silent) await prompts.log.warn(' Warning: Could not write prompts.yml during cleanup'); + } + } + } + + /** + * Check ancestor directories for existing BMAD files in the same target_dir. + * IDEs like Claude Code inherit commands from parent directories, so an existing + * installation in an ancestor would cause duplicate commands. + * @param {string} projectDir - Project directory being installed to + * @returns {Promise} Path to conflicting directory, or null if clean + */ + async findAncestorConflict(projectDir) { + const targetDir = this.installerConfig?.target_dir; + if (!targetDir) return null; + + const resolvedProject = await fs.realpath(path.resolve(projectDir)); + let current = path.dirname(resolvedProject); + const root = path.parse(current).root; + + while (current !== root && current.length > root.length) { + const candidatePath = path.join(current, targetDir); + try { + if (await fs.pathExists(candidatePath)) { + const entries = await fs.readdir(candidatePath); + const hasBmad = entries.some( + (e) => typeof e === 'string' && e.toLowerCase().startsWith('bmad') && !e.toLowerCase().startsWith('bmad-os-'), + ); + if (hasBmad) { + return candidatePath; + } + } + } catch { + // Can't read directory — skip + } + current = path.dirname(current); + } + + return null; + } + + /** + * Walk up ancestor directories from relativeDir toward projectDir, removing each if empty + * Stops at projectDir boundary — never removes projectDir itself + * @param {string} projectDir - Project root (boundary) + * @param {string} relativeDir - Relative directory to start from + */ + async removeEmptyParents(projectDir, relativeDir) { + const resolvedProject = path.resolve(projectDir); + let current = relativeDir; + let last = null; + while (current && current !== '.' && current !== last) { + last = current; + const fullPath = path.resolve(projectDir, current); + // Boundary guard: never traverse outside projectDir + if (!fullPath.startsWith(resolvedProject + path.sep) && fullPath !== resolvedProject) break; + try { + if (!(await fs.pathExists(fullPath))) { + // Dir already gone — advance current; last is reset at top of next iteration + current = path.dirname(current); + continue; + } + const remaining = await fs.readdir(fullPath); + if (remaining.length > 0) break; + await fs.rmdir(fullPath); + } catch (error) { + // ENOTEMPTY: TOCTOU race (file added between readdir and rmdir) — skip level, continue upward + // ENOENT: dir removed by another process between pathExists and rmdir — skip level, continue upward + if (error.code === 'ENOTEMPTY' || error.code === 'ENOENT') { + current = path.dirname(current); + continue; + } + break; // fatal error (e.g. EACCES) — stop upward walk + } + current = path.dirname(current); + } + } +} + +module.exports = { ConfigDrivenIdeSetup }; diff --git a/tools/cli/installers/lib/ide/manager.js b/tools/installer/ide/manager.js similarity index 82% rename from tools/cli/installers/lib/ide/manager.js rename to tools/installer/ide/manager.js index 0d7f91209..ac49a8773 100644 --- a/tools/cli/installers/lib/ide/manager.js +++ b/tools/installer/ide/manager.js @@ -1,5 +1,5 @@ const { BMAD_FOLDER_NAME } = require('./shared/path-utils'); -const prompts = require('../../../lib/prompts'); +const prompts = require('../prompts'); /** * IDE Manager - handles IDE-specific setup @@ -226,23 +226,6 @@ class IdeManager { return results; } - /** - * Get list of supported IDEs - * @returns {Array} List of supported IDE names - */ - getSupportedIdes() { - return [...this.handlers.keys()]; - } - - /** - * Check if an IDE is supported - * @param {string} ideName - Name of the IDE - * @returns {boolean} True if IDE is supported - */ - isSupported(ideName) { - return this.handlers.has(ideName.toLowerCase()); - } - /** * Detect installed IDEs * @param {string} projectDir - Project directory @@ -259,41 +242,6 @@ class IdeManager { return detected; } - - /** - * Install custom agent launchers for specified IDEs - * @param {Array} ides - List of IDE names to install for - * @param {string} projectDir - Project directory - * @param {string} agentName - Agent name (e.g., "fred-commit-poet") - * @param {string} agentPath - Path to compiled agent (relative to project root) - * @param {Object} metadata - Agent metadata - * @returns {Object} Results for each IDE - */ - async installCustomAgentLaunchers(ides, projectDir, agentName, agentPath, metadata) { - const results = {}; - - for (const ideName of ides) { - const handler = this.handlers.get(ideName.toLowerCase()); - - if (!handler) { - await prompts.log.warn(`IDE '${ideName}' is not yet supported for custom agent installation`); - continue; - } - - try { - if (typeof handler.installCustomAgentLauncher === 'function') { - const result = await handler.installCustomAgentLauncher(projectDir, agentName, agentPath, metadata); - if (result) { - results[ideName] = result; - } - } - } catch (error) { - await prompts.log.warn(`Failed to install ${ideName} launcher: ${error.message}`); - } - } - - return results; - } } module.exports = { IdeManager }; diff --git a/tools/installer/ide/platform-codes.js b/tools/installer/ide/platform-codes.js new file mode 100644 index 000000000..32d82e9cc --- /dev/null +++ b/tools/installer/ide/platform-codes.js @@ -0,0 +1,37 @@ +const fs = require('fs-extra'); +const path = require('node:path'); +const yaml = require('yaml'); + +const PLATFORM_CODES_PATH = path.join(__dirname, 'platform-codes.yaml'); + +let _cachedPlatformCodes = null; + +/** + * Load the platform codes configuration from YAML + * @returns {Object} Platform codes configuration + */ +async function loadPlatformCodes() { + if (_cachedPlatformCodes) { + return _cachedPlatformCodes; + } + + if (!(await fs.pathExists(PLATFORM_CODES_PATH))) { + throw new Error(`Platform codes configuration not found at: ${PLATFORM_CODES_PATH}`); + } + + const content = await fs.readFile(PLATFORM_CODES_PATH, 'utf8'); + _cachedPlatformCodes = yaml.parse(content); + return _cachedPlatformCodes; +} + +/** + * Clear the cached platform codes (useful for testing) + */ +function clearCache() { + _cachedPlatformCodes = null; +} + +module.exports = { + loadPlatformCodes, + clearCache, +}; diff --git a/tools/installer/ide/platform-codes.yaml b/tools/installer/ide/platform-codes.yaml new file mode 100644 index 000000000..4b08046f1 --- /dev/null +++ b/tools/installer/ide/platform-codes.yaml @@ -0,0 +1,192 @@ +# BMAD Platform Codes Configuration +# +# Each platform entry has: +# name: Display name shown to users +# preferred: Whether shown as a recommended option on install +# suspended: (optional) Message explaining why install is blocked +# installer: +# target_dir: Directory where skill directories are installed +# legacy_targets: (optional) Old target dirs to clean up on reinstall +# ancestor_conflict_check: (optional) Refuse install when ancestor dir has BMAD files + +platforms: + antigravity: + name: "Google Antigravity" + preferred: false + installer: + legacy_targets: + - .agent/workflows + target_dir: .agent/skills + + auggie: + name: "Auggie" + preferred: false + installer: + legacy_targets: + - .augment/commands + target_dir: .augment/skills + + claude-code: + name: "Claude Code" + preferred: true + installer: + legacy_targets: + - .claude/commands + target_dir: .claude/skills + + cline: + name: "Cline" + preferred: false + installer: + legacy_targets: + - .clinerules/workflows + target_dir: .cline/skills + + codex: + name: "Codex" + preferred: false + installer: + legacy_targets: + - .codex/prompts + - ~/.codex/prompts + target_dir: .agents/skills + + codebuddy: + name: "CodeBuddy" + preferred: false + installer: + legacy_targets: + - .codebuddy/commands + target_dir: .codebuddy/skills + + crush: + name: "Crush" + preferred: false + installer: + legacy_targets: + - .crush/commands + target_dir: .crush/skills + + cursor: + name: "Cursor" + preferred: true + installer: + legacy_targets: + - .cursor/commands + target_dir: .cursor/skills + + gemini: + name: "Gemini CLI" + preferred: false + installer: + legacy_targets: + - .gemini/commands + target_dir: .gemini/skills + + github-copilot: + name: "GitHub Copilot" + preferred: false + installer: + legacy_targets: + - .github/agents + - .github/prompts + target_dir: .github/skills + + iflow: + name: "iFlow" + preferred: false + installer: + legacy_targets: + - .iflow/commands + target_dir: .iflow/skills + + junie: + name: "Junie" + preferred: false + installer: + target_dir: .agents/skills + + kilo: + name: "KiloCoder" + preferred: false + installer: + legacy_targets: + - .kilocode/workflows + target_dir: .kilocode/skills + + kiro: + name: "Kiro" + preferred: false + installer: + legacy_targets: + - .kiro/steering + target_dir: .kiro/skills + + ona: + name: "Ona" + preferred: false + installer: + target_dir: .ona/skills + + opencode: + name: "OpenCode" + preferred: false + installer: + legacy_targets: + - .opencode/agents + - .opencode/commands + - .opencode/agent + - .opencode/command + target_dir: .opencode/skills + + pi: + name: "Pi" + preferred: false + installer: + target_dir: .pi/skills + + qoder: + name: "Qoder" + preferred: false + installer: + target_dir: .qoder/skills + + qwen: + name: "QwenCoder" + preferred: false + installer: + legacy_targets: + - .qwen/commands + target_dir: .qwen/skills + + roo: + name: "Roo Code" + preferred: false + installer: + legacy_targets: + - .roo/commands + target_dir: .roo/skills + + rovo-dev: + name: "Rovo Dev" + preferred: false + installer: + legacy_targets: + - .rovodev/workflows + target_dir: .rovodev/skills + + trae: + name: "Trae" + preferred: false + installer: + legacy_targets: + - .trae/rules + target_dir: .trae/skills + + windsurf: + name: "Windsurf" + preferred: false + installer: + legacy_targets: + - .windsurf/workflows + target_dir: .windsurf/skills diff --git a/tools/cli/installers/lib/ide/shared/path-utils.js b/tools/installer/ide/shared/path-utils.js similarity index 67% rename from tools/cli/installers/lib/ide/shared/path-utils.js rename to tools/installer/ide/shared/path-utils.js index 35fc263f4..6d7c2c9fa 100644 --- a/tools/cli/installers/lib/ide/shared/path-utils.js +++ b/tools/installer/ide/shared/path-utils.js @@ -15,8 +15,6 @@ * - standalone/agents/fred.md → bmad-agent-standalone-fred.md */ -// Type segments - agents are included in naming, others are filtered out -const TYPE_SEGMENTS = ['workflows', 'tasks', 'tools']; const AGENT_SEGMENT = 'agents'; // BMAD installation folder name - centralized constant for all installers @@ -194,125 +192,6 @@ function parseDashName(filename) { }; } -// ============================================================================ -// LEGACY FUNCTIONS (underscore format) - kept for backward compatibility -// ============================================================================ - -/** - * Convert hierarchical path to flat underscore-separated name (LEGACY) - * @deprecated Use toDashName instead - */ -function toUnderscoreName(module, type, name) { - const isAgent = type === AGENT_SEGMENT; - if (module === 'core') { - return isAgent ? `bmad_agent_${name}.md` : `bmad_${name}.md`; - } - if (module === 'standalone') { - return isAgent ? `bmad_agent_standalone_${name}.md` : `bmad_standalone_${name}.md`; - } - return isAgent ? `bmad_${module}_agent_${name}.md` : `bmad_${module}_${name}.md`; -} - -/** - * Convert relative path to flat underscore-separated name (LEGACY) - * @deprecated Use toDashPath instead - */ -function toUnderscorePath(relativePath) { - // Strip common file extensions (same as toDashPath for consistency) - const withoutExt = relativePath.replace(/\.(md|yaml|yml|json|xml|toml)$/i, ''); - const parts = withoutExt.split(/[/\\]/); - - const module = parts[0]; - const type = parts[1]; - const name = parts.slice(2).join('_'); - - return toUnderscoreName(module, type, name); -} - -/** - * Create custom agent underscore name (LEGACY) - * @deprecated Use customAgentDashName instead - */ -function customAgentUnderscoreName(agentName) { - return `bmad_custom_${agentName}.md`; -} - -/** - * Check if a filename uses underscore format (LEGACY) - * @deprecated Use isDashFormat instead - */ -function isUnderscoreFormat(filename) { - return filename.startsWith('bmad_') && filename.includes('_'); -} - -/** - * Extract parts from an underscore-formatted filename (LEGACY) - * @deprecated Use parseDashName instead - */ -function parseUnderscoreName(filename) { - const withoutExt = filename.replace('.md', ''); - const parts = withoutExt.split('_'); - - if (parts.length < 2 || parts[0] !== 'bmad') { - return null; - } - - const agentIndex = parts.indexOf('agent'); - - if (agentIndex !== -1) { - if (agentIndex === 1) { - // bmad_agent_... - check for standalone - if (parts.length >= 4 && parts[2] === 'standalone') { - return { - prefix: parts[0], - module: 'standalone', - type: 'agents', - name: parts.slice(3).join('_'), - }; - } - return { - prefix: parts[0], - module: 'core', - type: 'agents', - name: parts.slice(agentIndex + 1).join('_'), - }; - } else { - return { - prefix: parts[0], - module: parts[1], - type: 'agents', - name: parts.slice(agentIndex + 1).join('_'), - }; - } - } - - if (parts.length === 2) { - return { - prefix: parts[0], - module: 'core', - type: 'workflows', - name: parts[1], - }; - } - - // Check for standalone non-agent: bmad_standalone_name - if (parts[1] === 'standalone') { - return { - prefix: parts[0], - module: 'standalone', - type: 'workflows', - name: parts.slice(2).join('_'), - }; - } - - return { - prefix: parts[0], - module: parts[1], - type: 'workflows', - name: parts.slice(2).join('_'), - }; -} - /** * Resolve the skill name for an artifact. * Prefers canonicalId from a bmad-skill-manifest.yaml sidecar when available, @@ -328,37 +207,13 @@ function resolveSkillName(artifact) { return toDashPath(artifact.relativePath); } -// Backward compatibility aliases (colon format was same as underscore) -const toColonName = toUnderscoreName; -const toColonPath = toUnderscorePath; -const customAgentColonName = customAgentUnderscoreName; -const isColonFormat = isUnderscoreFormat; -const parseColonName = parseUnderscoreName; - module.exports = { - // New standard (dash-based) toDashName, toDashPath, resolveSkillName, customAgentDashName, isDashFormat, parseDashName, - - // Legacy (underscore-based) - kept for backward compatibility - toUnderscoreName, - toUnderscorePath, - customAgentUnderscoreName, - isUnderscoreFormat, - parseUnderscoreName, - - // Backward compatibility aliases - toColonName, - toColonPath, - customAgentColonName, - isColonFormat, - parseColonName, - - TYPE_SEGMENTS, AGENT_SEGMENT, BMAD_FOLDER_NAME, }; diff --git a/tools/cli/installers/lib/ide/shared/skill-manifest.js b/tools/installer/ide/shared/skill-manifest.js similarity index 77% rename from tools/cli/installers/lib/ide/shared/skill-manifest.js rename to tools/installer/ide/shared/skill-manifest.js index c5ae4aed8..746d5d16f 100644 --- a/tools/cli/installers/lib/ide/shared/skill-manifest.js +++ b/tools/installer/ide/shared/skill-manifest.js @@ -54,19 +54,4 @@ function getArtifactType(manifest, filename) { return null; } -/** - * Get the install_to_bmad flag for a specific file from a loaded skill manifest. - * @param {Object|null} manifest - Loaded manifest (from loadSkillManifest) - * @param {string} filename - Source filename to look up - * @returns {boolean} install_to_bmad value (defaults to true) - */ -function getInstallToBmad(manifest, filename) { - if (!manifest) return true; - // Single-entry manifest applies to all files in the directory - if (manifest.__single) return manifest.__single.install_to_bmad !== false; - // Multi-entry: look up by filename directly - if (manifest[filename]) return manifest[filename].install_to_bmad !== false; - return true; -} - -module.exports = { loadSkillManifest, getCanonicalId, getArtifactType, getInstallToBmad }; +module.exports = { loadSkillManifest, getCanonicalId, getArtifactType }; diff --git a/tools/installer/install-messages.yaml b/tools/installer/install-messages.yaml new file mode 100644 index 000000000..4aff87a95 --- /dev/null +++ b/tools/installer/install-messages.yaml @@ -0,0 +1,32 @@ +# BMAD Installer Messages +# These messages are displayed during installation +# Edit this file to change what users see during the install process + +# Display at the START of installation (after logo, before prompts) +startMessage: | + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + Agile AI-Driven Development. Powered by BMad Core and a growing module ecosystem. + Install official and community modules during setup to customize your experience. + + 🌟 100% free. 100% open source. Always. + No paywalls. No gated content. Knowledge shared, not sold. + + 🌐 CONNECT: + Website: https://bmadcode.com/ + Discord: https://discord.gg/gk8jAdXWmj + YouTube: https://www.youtube.com/@BMadCode + X: https://x.com/BMadCode + Facebook: https://facebook.com/@BMadCode + + ⭐ SUPPORT THE PROJECT: + Star us: https://github.com/bmad-code-org/BMAD-METHOD/ + Donate: https://buymeacoffee.com/bmad + Corporate sponsorship and speaking inquiries: contact@bmadcode.com + + Docs, blog, and latest updates: https://bmadcode.com/ + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# No end message - install summary and next steps are rendered by the installer +endMessage: "" diff --git a/tools/cli/installers/lib/message-loader.js b/tools/installer/message-loader.js similarity index 93% rename from tools/cli/installers/lib/message-loader.js rename to tools/installer/message-loader.js index 7198f0328..03ba7eca1 100644 --- a/tools/cli/installers/lib/message-loader.js +++ b/tools/installer/message-loader.js @@ -1,7 +1,7 @@ const fs = require('fs-extra'); const path = require('node:path'); const yaml = require('yaml'); -const prompts = require('../../lib/prompts'); +const prompts = require('./prompts'); /** * Load and display installer messages from messages.yaml @@ -18,7 +18,7 @@ class MessageLoader { return this.messages; } - const messagesPath = path.join(__dirname, '..', 'install-messages.yaml'); + const messagesPath = path.join(__dirname, 'install-messages.yaml'); try { const content = fs.readFileSync(messagesPath, 'utf8'); diff --git a/tools/installer/modules/community-manager.js b/tools/installer/modules/community-manager.js new file mode 100644 index 000000000..0f88cffff --- /dev/null +++ b/tools/installer/modules/community-manager.js @@ -0,0 +1,377 @@ +const fs = require('fs-extra'); +const os = require('node:os'); +const path = require('node:path'); +const { execSync } = require('node:child_process'); +const prompts = require('../prompts'); +const { RegistryClient } = require('./registry-client'); + +const MARKETPLACE_BASE = 'https://raw.githubusercontent.com/bmad-code-org/bmad-plugins-marketplace/main'; +const COMMUNITY_INDEX_URL = `${MARKETPLACE_BASE}/registry/community-index.yaml`; +const CATEGORIES_URL = `${MARKETPLACE_BASE}/categories.yaml`; + +/** + * Manages community modules from the BMad marketplace registry. + * Fetches community-index.yaml and categories.yaml from GitHub. + * Returns empty results when the registry is unreachable. + * Community modules are pinned to approved SHA when set; uses HEAD otherwise. + */ +class CommunityModuleManager { + constructor() { + this._client = new RegistryClient(); + this._cachedIndex = null; + this._cachedCategories = null; + } + + // ─── Data Loading ────────────────────────────────────────────────────────── + + /** + * Load the community module index from the marketplace repo. + * Returns empty when the registry is unreachable. + * @returns {Object} Parsed YAML with modules array + */ + async loadCommunityIndex() { + if (this._cachedIndex) return this._cachedIndex; + + try { + const config = await this._client.fetchYaml(COMMUNITY_INDEX_URL); + if (config?.modules?.length) { + this._cachedIndex = config; + return config; + } + } catch { + // Registry unreachable - no community modules available + } + + return { modules: [] }; + } + + /** + * Load categories from the marketplace repo. + * Returns empty when the registry is unreachable. + * @returns {Object} Parsed categories.yaml content + */ + async loadCategories() { + if (this._cachedCategories) return this._cachedCategories; + + try { + const config = await this._client.fetchYaml(CATEGORIES_URL); + if (config?.categories) { + this._cachedCategories = config; + return config; + } + } catch { + // Registry unreachable - no categories available + } + + return { categories: {} }; + } + + // ─── Listing & Filtering ────────────────────────────────────────────────── + + /** + * Get all community modules, normalized. + * @returns {Array} Normalized community modules + */ + async listAll() { + const index = await this.loadCommunityIndex(); + return (index.modules || []).map((mod) => this._normalizeCommunityModule(mod)); + } + + /** + * Get community modules filtered to a category. + * @param {string} categorySlug - Category slug (e.g., 'design-and-creative') + * @returns {Array} Filtered modules + */ + async listByCategory(categorySlug) { + const all = await this.listAll(); + return all.filter((mod) => mod.category === categorySlug); + } + + /** + * Get promoted/featured community modules, sorted by rank. + * @returns {Array} Featured modules + */ + async listFeatured() { + const all = await this.listAll(); + return all.filter((mod) => mod.promoted === true).sort((a, b) => (a.promotedRank || 999) - (b.promotedRank || 999)); + } + + /** + * Search community modules by keyword. + * Matches against name, display name, description, and keywords array. + * @param {string} query - Search query + * @returns {Array} Matching modules + */ + async searchByKeyword(query) { + const all = await this.listAll(); + const q = query.toLowerCase(); + return all.filter((mod) => { + const searchable = [mod.name, mod.displayName, mod.description, ...(mod.keywords || [])].join(' ').toLowerCase(); + return searchable.includes(q); + }); + } + + /** + * Get categories with module counts for UI display. + * Only returns categories that have at least one community module. + * @returns {Array} Array of { slug, name, moduleCount } + */ + async getCategoryList() { + const all = await this.listAll(); + const categoriesData = await this.loadCategories(); + const categories = categoriesData.categories || {}; + + // Count modules per category + const counts = {}; + for (const mod of all) { + counts[mod.category] = (counts[mod.category] || 0) + 1; + } + + // Build list with display names from categories.yaml + const result = []; + for (const [slug, count] of Object.entries(counts)) { + const catInfo = categories[slug]; + result.push({ + slug, + name: catInfo?.name || slug, + moduleCount: count, + }); + } + + // Sort alphabetically by name + result.sort((a, b) => a.name.localeCompare(b.name)); + return result; + } + + // ─── Module Lookup ──────────────────────────────────────────────────────── + + /** + * Get a community module by its code. + * @param {string} code - Module code (e.g., 'wds') + * @returns {Object|null} Normalized module or null + */ + async getModuleByCode(code) { + const all = await this.listAll(); + return all.find((m) => m.code === code) || null; + } + + // ─── Clone with Tag Pinning ─────────────────────────────────────────────── + + /** + * Get the cache directory for community modules. + * @returns {string} Path to the community modules cache directory + */ + getCacheDir() { + return path.join(os.homedir(), '.bmad', 'cache', 'community-modules'); + } + + /** + * Clone a community module repository, pinned to its approved tag. + * @param {string} moduleCode - Module code + * @param {Object} [options] - Clone options + * @param {boolean} [options.silent] - Suppress spinner output + * @returns {string} Path to the cloned repository + */ + async cloneModule(moduleCode, options = {}) { + const moduleInfo = await this.getModuleByCode(moduleCode); + if (!moduleInfo) { + throw new Error(`Community module '${moduleCode}' not found in the registry`); + } + + const cacheDir = this.getCacheDir(); + const moduleCacheDir = path.join(cacheDir, moduleCode); + const silent = options.silent || false; + + await fs.ensureDir(cacheDir); + + const createSpinner = async () => { + if (silent) { + return { start() {}, stop() {}, error() {}, message() {} }; + } + return await prompts.spinner(); + }; + + const sha = moduleInfo.approvedSha; + let needsDependencyInstall = false; + let wasNewClone = false; + + if (await fs.pathExists(moduleCacheDir)) { + // Already cloned - update to latest HEAD + const fetchSpinner = await createSpinner(); + fetchSpinner.start(`Checking ${moduleInfo.displayName}...`); + try { + const currentRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim(); + execSync('git fetch origin --depth 1', { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + execSync('git reset --hard origin/HEAD', { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + }); + const newRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim(); + if (currentRef !== newRef) needsDependencyInstall = true; + fetchSpinner.stop(`Verified ${moduleInfo.displayName}`); + } catch { + fetchSpinner.error(`Fetch failed, re-downloading ${moduleInfo.displayName}`); + await fs.remove(moduleCacheDir); + wasNewClone = true; + } + } else { + wasNewClone = true; + } + + if (wasNewClone) { + const fetchSpinner = await createSpinner(); + fetchSpinner.start(`Fetching ${moduleInfo.displayName}...`); + try { + execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, { + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + fetchSpinner.stop(`Fetched ${moduleInfo.displayName}`); + needsDependencyInstall = true; + } catch (error) { + fetchSpinner.error(`Failed to fetch ${moduleInfo.displayName}`); + throw new Error(`Failed to clone community module '${moduleCode}': ${error.message}`); + } + } + + // If pinned to a specific SHA, check out that exact commit. + // Refuse to install if the approved SHA cannot be reached - security requirement. + if (sha) { + const headSha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim(); + if (headSha !== sha) { + try { + execSync(`git fetch --depth 1 origin ${sha}`, { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + execSync(`git checkout ${sha}`, { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + }); + needsDependencyInstall = true; + } catch { + await fs.remove(moduleCacheDir); + throw new Error( + `Community module '${moduleCode}' could not be pinned to its approved commit (${sha}). ` + + `Installation refused for security. The module registry entry may need updating.`, + ); + } + } + } + + // Install dependencies if needed + const packageJsonPath = path.join(moduleCacheDir, 'package.json'); + if ((needsDependencyInstall || wasNewClone) && (await fs.pathExists(packageJsonPath))) { + const installSpinner = await createSpinner(); + installSpinner.start(`Installing dependencies for ${moduleInfo.displayName}...`); + try { + execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 120_000, + }); + installSpinner.stop(`Installed dependencies for ${moduleInfo.displayName}`); + } catch (error) { + installSpinner.error(`Failed to install dependencies for ${moduleInfo.displayName}`); + if (!silent) await prompts.log.warn(` ${error.message}`); + } + } + + return moduleCacheDir; + } + + // ─── Source Finding ─────────────────────────────────────────────────────── + + /** + * Find the source path for a community module (clone + locate module.yaml). + * @param {string} moduleCode - Module code + * @param {Object} [options] - Options passed to cloneModule + * @returns {string|null} Path to the module source or null + */ + async findModuleSource(moduleCode, options = {}) { + const moduleInfo = await this.getModuleByCode(moduleCode); + if (!moduleInfo) return null; + + const cloneDir = await this.cloneModule(moduleCode, options); + + // Check configured module_definition path first + if (moduleInfo.moduleDefinition) { + const configuredPath = path.join(cloneDir, moduleInfo.moduleDefinition); + if (await fs.pathExists(configuredPath)) { + return path.dirname(configuredPath); + } + } + + // Fallback: search skills/ and src/ directories + for (const dir of ['skills', 'src']) { + const rootCandidate = path.join(cloneDir, dir, 'module.yaml'); + if (await fs.pathExists(rootCandidate)) { + return path.dirname(rootCandidate); + } + const dirPath = path.join(cloneDir, dir); + if (await fs.pathExists(dirPath)) { + const entries = await fs.readdir(dirPath, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const subCandidate = path.join(dirPath, entry.name, 'module.yaml'); + if (await fs.pathExists(subCandidate)) { + return path.dirname(subCandidate); + } + } + } + } + } + + // Check repo root + const rootCandidate = path.join(cloneDir, 'module.yaml'); + if (await fs.pathExists(rootCandidate)) { + return path.dirname(rootCandidate); + } + + return moduleInfo.moduleDefinition ? path.dirname(path.join(cloneDir, moduleInfo.moduleDefinition)) : null; + } + + // ─── Normalization ──────────────────────────────────────────────────────── + + /** + * Normalize a community module entry to a consistent shape. + * @param {Object} mod - Raw module from community-index.yaml + * @returns {Object} Normalized module info + */ + _normalizeCommunityModule(mod) { + return { + key: mod.name, + code: mod.code, + name: mod.display_name || mod.name, + displayName: mod.display_name || mod.name, + description: mod.description || '', + url: mod.repository || mod.url, + moduleDefinition: mod.module_definition || mod['module-definition'], + npmPackage: mod.npm_package || mod.npmPackage || null, + author: mod.author || '', + license: mod.license || '', + type: 'community', + category: mod.category || '', + subcategory: mod.subcategory || '', + keywords: mod.keywords || [], + version: mod.version || null, + approvedTag: mod.approved_tag || null, + approvedSha: mod.approved_sha || null, + approvedDate: mod.approved_date || null, + reviewer: mod.reviewer || null, + trustTier: mod.trust_tier || 'unverified', + promoted: mod.promoted === true, + promotedRank: mod.promoted_rank || null, + defaultSelected: false, + builtIn: false, + isExternal: true, + }; + } +} + +module.exports = { CommunityModuleManager }; diff --git a/tools/installer/modules/custom-module-manager.js b/tools/installer/modules/custom-module-manager.js new file mode 100644 index 000000000..e0f8b7085 --- /dev/null +++ b/tools/installer/modules/custom-module-manager.js @@ -0,0 +1,617 @@ +const fs = require('fs-extra'); +const os = require('node:os'); +const path = require('node:path'); +const { execSync } = require('node:child_process'); +const prompts = require('../prompts'); + +/** + * Manages custom modules installed from user-provided sources. + * Supports any Git host (GitHub, GitLab, Bitbucket, self-hosted) and local file paths. + * Validates input, clones repos, reads .claude-plugin/marketplace.json, resolves plugins. + */ +class CustomModuleManager { + /** @type {Map} Shared across all instances: module code -> ResolvedModule */ + static _resolutionCache = new Map(); + + // ─── Source Parsing ─────────────────────────────────────────────────────── + + /** + * Parse a user-provided source input into a structured descriptor. + * Accepts local file paths, HTTPS Git URLs, and SSH Git URLs. + * For HTTPS URLs with deep paths (e.g., /tree/main/subdir), extracts the subdir. + * + * @param {string} input - URL or local file path + * @returns {Object} Parsed source descriptor: + * { type: 'url'|'local', cloneUrl, subdir, localPath, cacheKey, displayName, isValid, error } + */ + parseSource(input) { + if (!input || typeof input !== 'string') { + return { + type: null, + cloneUrl: null, + subdir: null, + localPath: null, + cacheKey: null, + displayName: null, + isValid: false, + error: 'Source is required', + }; + } + + const trimmed = input.trim(); + if (!trimmed) { + return { + type: null, + cloneUrl: null, + subdir: null, + localPath: null, + cacheKey: null, + displayName: null, + isValid: false, + error: 'Source is required', + }; + } + + // Local path detection: starts with /, ./, ../, or ~ + if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../') || trimmed.startsWith('~')) { + return this._parseLocalPath(trimmed); + } + + // SSH URL: git@host:owner/repo.git + const sshMatch = trimmed.match(/^git@([^:]+):([^/]+)\/([^/.]+?)(?:\.git)?$/); + if (sshMatch) { + const [, host, owner, repo] = sshMatch; + return { + type: 'url', + cloneUrl: trimmed, + subdir: null, + localPath: null, + cacheKey: `${host}/${owner}/${repo}`, + displayName: `${owner}/${repo}`, + isValid: true, + error: null, + }; + } + + // HTTPS URL: https://host/owner/repo[/tree/branch/subdir][.git] + const httpsMatch = trimmed.match(/^https?:\/\/([^/]+)\/([^/]+)\/([^/.]+?)(?:\.git)?(\/.*)?$/); + if (httpsMatch) { + const [, host, owner, repo, remainder] = httpsMatch; + const cloneUrl = `https://${host}/${owner}/${repo}`; + let subdir = null; + + if (remainder) { + // Extract subdir from deep path patterns used by various Git hosts + const deepPathPatterns = [ + /^\/(?:-\/)?tree\/[^/]+\/(.+)$/, // GitHub /tree/branch/path, GitLab /-/tree/branch/path + /^\/(?:-\/)?blob\/[^/]+\/(.+)$/, // /blob/branch/path (treat same as tree) + /^\/src\/[^/]+\/(.+)$/, // Gitea/Forgejo /src/branch/path + ]; + + for (const pattern of deepPathPatterns) { + const match = remainder.match(pattern); + if (match) { + subdir = match[1].replace(/\/$/, ''); // strip trailing slash + break; + } + } + } + + return { + type: 'url', + cloneUrl, + subdir, + localPath: null, + cacheKey: `${host}/${owner}/${repo}`, + displayName: `${owner}/${repo}`, + isValid: true, + error: null, + }; + } + + return { + type: null, + cloneUrl: null, + subdir: null, + localPath: null, + cacheKey: null, + displayName: null, + isValid: false, + error: 'Not a valid Git URL or local path', + }; + } + + /** + * Parse a local filesystem path. + * @param {string} rawPath - Path string (may contain ~ for home) + * @returns {Object} Parsed source descriptor + */ + _parseLocalPath(rawPath) { + const expanded = rawPath.startsWith('~') ? path.join(os.homedir(), rawPath.slice(1)) : rawPath; + const resolved = path.resolve(expanded); + + if (!fs.pathExistsSync(resolved)) { + return { + type: 'local', + cloneUrl: null, + subdir: null, + localPath: resolved, + cacheKey: null, + displayName: path.basename(resolved), + isValid: false, + error: `Path does not exist: ${resolved}`, + }; + } + + return { + type: 'local', + cloneUrl: null, + subdir: null, + localPath: resolved, + cacheKey: null, + displayName: path.basename(resolved), + isValid: true, + error: null, + }; + } + + // ─── Marketplace JSON ───────────────────────────────────────────────────── + + /** + * Read .claude-plugin/marketplace.json from a local directory. + * @param {string} dirPath - Directory to read from + * @returns {Object|null} Parsed marketplace.json or null if not found + */ + async readMarketplaceJsonFromDisk(dirPath) { + const marketplacePath = path.join(dirPath, '.claude-plugin', 'marketplace.json'); + if (!(await fs.pathExists(marketplacePath))) return null; + try { + return JSON.parse(await fs.readFile(marketplacePath, 'utf8')); + } catch { + return null; + } + } + + // ─── Discovery ──────────────────────────────────────────────────────────── + + /** + * Discover modules from pre-read marketplace.json data. + * @param {Object} marketplaceData - Parsed marketplace.json content + * @param {string|null} sourceUrl - Source URL for tracking (null for local paths) + * @returns {Array} Normalized plugin list + */ + async discoverModules(marketplaceData, sourceUrl) { + const plugins = marketplaceData?.plugins; + + if (!Array.isArray(plugins) || plugins.length === 0) { + throw new Error('marketplace.json contains no plugins'); + } + + return plugins.map((plugin) => this._normalizeCustomModule(plugin, sourceUrl, marketplaceData)); + } + + // ─── Source Resolution ──────────────────────────────────────────────────── + + /** + * High-level coordinator: parse input, clone if URL, determine discovery vs direct mode. + * @param {string} input - URL or local path + * @param {Object} [options] - Options passed to cloneRepo + * @returns {Object} { parsed, rootDir, repoPath, sourceUrl, marketplace, mode: 'discovery'|'direct' } + */ + async resolveSource(input, options = {}) { + const parsed = this.parseSource(input); + if (!parsed.isValid) throw new Error(parsed.error); + + let rootDir; + let repoPath; + let sourceUrl; + + if (parsed.type === 'local') { + rootDir = parsed.localPath; + repoPath = null; + sourceUrl = null; + } else { + repoPath = await this.cloneRepo(input, options); + sourceUrl = parsed.cloneUrl; + rootDir = parsed.subdir ? path.join(repoPath, parsed.subdir) : repoPath; + + if (parsed.subdir && !(await fs.pathExists(rootDir))) { + throw new Error(`Subdirectory '${parsed.subdir}' not found in cloned repository`); + } + } + + const marketplace = await this.readMarketplaceJsonFromDisk(rootDir); + const mode = marketplace ? 'discovery' : 'direct'; + + return { parsed, rootDir, repoPath, sourceUrl, marketplace, mode }; + } + + // ─── Clone ──────────────────────────────────────────────────────────────── + + /** + * Get the cache directory for custom modules. + * @returns {string} Path to the custom modules cache directory + */ + getCacheDir() { + return path.join(os.homedir(), '.bmad', 'cache', 'custom-modules'); + } + + /** + * Clone a custom module repository to cache. + * Supports any Git host (GitHub, GitLab, Bitbucket, self-hosted, etc.). + * @param {string} sourceInput - Git URL (HTTPS or SSH) + * @param {Object} [options] - Clone options + * @param {boolean} [options.silent] - Suppress spinner output + * @param {boolean} [options.skipInstall] - Skip npm install (for browsing before user confirms) + * @returns {string} Path to the cloned repository + */ + async cloneRepo(sourceInput, options = {}) { + const parsed = this.parseSource(sourceInput); + if (!parsed.isValid) throw new Error(parsed.error); + if (parsed.type === 'local') throw new Error('cloneRepo does not accept local paths'); + + const cacheDir = this.getCacheDir(); + const repoCacheDir = path.join(cacheDir, ...parsed.cacheKey.split('/')); + const silent = options.silent || false; + const displayName = parsed.displayName; + + await fs.ensureDir(path.dirname(repoCacheDir)); + + const createSpinner = async () => { + if (silent) { + return { start() {}, stop() {}, error() {} }; + } + return await prompts.spinner(); + }; + + if (await fs.pathExists(repoCacheDir)) { + // Update existing clone + const fetchSpinner = await createSpinner(); + fetchSpinner.start(`Updating ${displayName}...`); + try { + execSync('git fetch origin --depth 1', { + cwd: repoCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + execSync('git reset --hard origin/HEAD', { + cwd: repoCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + }); + fetchSpinner.stop(`Updated ${displayName}`); + } catch { + fetchSpinner.error(`Update failed, re-downloading ${displayName}`); + await fs.remove(repoCacheDir); + } + } + + if (!(await fs.pathExists(repoCacheDir))) { + const fetchSpinner = await createSpinner(); + fetchSpinner.start(`Cloning ${displayName}...`); + try { + execSync(`git clone --depth 1 "${parsed.cloneUrl}" "${repoCacheDir}"`, { + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + fetchSpinner.stop(`Cloned ${displayName}`); + } catch (error_) { + fetchSpinner.error(`Failed to clone ${displayName}`); + throw new Error(`Failed to clone ${parsed.cloneUrl}: ${error_.message}`); + } + } + + // Write source metadata for later URL reconstruction + const metadataPath = path.join(repoCacheDir, '.bmad-source.json'); + await fs.writeJson(metadataPath, { + cloneUrl: parsed.cloneUrl, + cacheKey: parsed.cacheKey, + displayName: parsed.displayName, + clonedAt: new Date().toISOString(), + }); + + // Install dependencies if package.json exists (skip during browsing/analysis) + const packageJsonPath = path.join(repoCacheDir, 'package.json'); + if (!options.skipInstall && (await fs.pathExists(packageJsonPath))) { + const installSpinner = await createSpinner(); + installSpinner.start(`Installing dependencies for ${displayName}...`); + try { + execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', { + cwd: repoCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 120_000, + }); + installSpinner.stop(`Installed dependencies for ${displayName}`); + } catch (error_) { + installSpinner.error(`Failed to install dependencies for ${displayName}`); + if (!silent) await prompts.log.warn(` ${error_.message}`); + } + } + + return repoCacheDir; + } + + // ─── Plugin Resolution ──────────────────────────────────────────────────── + + /** + * Resolve a plugin to determine installation strategy and module registration files. + * Results are cached in _resolutionCache keyed by module code. + * @param {string} repoPath - Absolute path to the cloned repository or local directory + * @param {Object} plugin - Raw plugin object from marketplace.json + * @param {string} [sourceUrl] - Original URL for manifest tracking (null for local) + * @param {string} [localPath] - Local source path for manifest tracking (null for URLs) + * @returns {Promise>} Array of ResolvedModule objects + */ + async resolvePlugin(repoPath, plugin, sourceUrl, localPath) { + const { PluginResolver } = require('./plugin-resolver'); + const resolver = new PluginResolver(); + const resolved = await resolver.resolve(repoPath, plugin); + + // Stamp source info onto each resolved module for manifest tracking + for (const mod of resolved) { + if (sourceUrl) mod.repoUrl = sourceUrl; + if (localPath) mod.localPath = localPath; + CustomModuleManager._resolutionCache.set(mod.code, mod); + } + + return resolved; + } + + /** + * Get a cached resolution result by module code. + * @param {string} moduleCode - Module code to look up + * @returns {Object|null} ResolvedModule or null if not cached + */ + getResolution(moduleCode) { + return CustomModuleManager._resolutionCache.get(moduleCode) || null; + } + + // ─── Source Finding ─────────────────────────────────────────────────────── + + /** + * Find the module source path within a cached or local source directory. + * @param {string} sourceInput - Git URL or local path (used to locate cached clone) + * @param {string} [pluginSource] - Plugin source path from marketplace.json + * @returns {string|null} Path to directory containing module.yaml + */ + async findModuleSource(sourceInput, pluginSource) { + const parsed = this.parseSource(sourceInput); + if (!parsed.isValid) return null; + + let baseDir; + if (parsed.type === 'local') { + baseDir = parsed.localPath; + } else { + baseDir = path.join(this.getCacheDir(), ...parsed.cacheKey.split('/')); + } + + if (!(await fs.pathExists(baseDir))) return null; + + // Try plugin source path first (e.g., "./src/pro-skills") + if (pluginSource) { + const sourcePath = path.join(baseDir, pluginSource); + const moduleYaml = path.join(sourcePath, 'module.yaml'); + if (await fs.pathExists(moduleYaml)) { + return sourcePath; + } + } + + // Fallback: search skills/ and src/ directories + for (const dir of ['skills', 'src']) { + const rootCandidate = path.join(baseDir, dir, 'module.yaml'); + if (await fs.pathExists(rootCandidate)) { + return path.dirname(rootCandidate); + } + const dirPath = path.join(baseDir, dir); + if (await fs.pathExists(dirPath)) { + const entries = await fs.readdir(dirPath, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const subCandidate = path.join(dirPath, entry.name, 'module.yaml'); + if (await fs.pathExists(subCandidate)) { + return path.dirname(subCandidate); + } + } + } + } + } + + // Check base directory root + const rootCandidate = path.join(baseDir, 'module.yaml'); + if (await fs.pathExists(rootCandidate)) { + return baseDir; + } + + return null; + } + + /** + * Find module source by module code, searching the custom cache. + * Handles both new 3-level cache structure (host/owner/repo) and + * legacy 2-level structure (owner/repo). + * @param {string} moduleCode - Module code to search for + * @param {Object} [options] - Options + * @returns {string|null} Path to the module source or null + */ + async findModuleSourceByCode(moduleCode, options = {}) { + // Check resolution cache first (populated by resolvePlugin) + const resolved = CustomModuleManager._resolutionCache.get(moduleCode); + if (resolved) { + // For strategies 1-2: the common parent or setup skill's parent has the module files + if (resolved.moduleYamlPath) { + return path.dirname(resolved.moduleYamlPath); + } + // For strategy 5 (synthesized): return the first skill's parent as a reference path + if (resolved.skillPaths && resolved.skillPaths.length > 0) { + return path.dirname(resolved.skillPaths[0]); + } + } + + const cacheDir = this.getCacheDir(); + if (!(await fs.pathExists(cacheDir))) return null; + + // Search through all cached repo roots + try { + const { PluginResolver } = require('./plugin-resolver'); + const resolver = new PluginResolver(); + const repoRoots = await this._findCacheRepoRoots(cacheDir); + + for (const { repoPath, metadata } of repoRoots) { + // Check marketplace.json for matching module code + const marketplacePath = path.join(repoPath, '.claude-plugin', 'marketplace.json'); + if (!(await fs.pathExists(marketplacePath))) continue; + + try { + const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8')); + for (const plugin of data.plugins || []) { + // Direct name match (legacy behavior) + if (plugin.name === moduleCode) { + const sourcePath = plugin.source ? path.join(repoPath, plugin.source) : repoPath; + const moduleYaml = path.join(sourcePath, 'module.yaml'); + if (await fs.pathExists(moduleYaml)) { + return sourcePath; + } + } + + // Resolve plugin to check if any module.yaml code matches + if (plugin.skills && plugin.skills.length > 0) { + try { + const resolvedMods = await resolver.resolve(repoPath, plugin); + for (const mod of resolvedMods) { + if (mod.code === moduleCode) { + // Use metadata for URL reconstruction instead of deriving from path + mod.repoUrl = metadata?.cloneUrl || null; + CustomModuleManager._resolutionCache.set(mod.code, mod); + if (mod.moduleYamlPath) { + return path.dirname(mod.moduleYamlPath); + } + if (mod.skillPaths && mod.skillPaths.length > 0) { + return path.dirname(mod.skillPaths[0]); + } + } + } + } catch { + // Skip unresolvable plugins + } + } + } + } catch { + // Skip malformed marketplace.json + } + } + } catch { + // Cache doesn't exist or is inaccessible + } + + // Fallback: check manifest for localPath (local-source modules not in cache) + return this._findLocalSourceFromManifest(moduleCode, options); + } + + /** + * Check the installation manifest for a localPath entry for this module. + * Used as fallback when the module was installed from a local source (no cache entry). + * Returns the path only if it still exists on disk; never removes installed files. + * @param {string} moduleCode - Module code to search for + * @param {Object} [options] - Options (must include bmadDir or will search common locations) + * @returns {string|null} Path to the local module source or null + */ + async _findLocalSourceFromManifest(moduleCode, options = {}) { + try { + const { Manifest } = require('../core/manifest'); + const manifestObj = new Manifest(); + + // Try to find bmadDir from options or common locations + const bmadDir = options.bmadDir; + if (!bmadDir) return null; + + const manifestData = await manifestObj.read(bmadDir); + if (!manifestData?.modulesDetailed) return null; + + const moduleEntry = manifestData.modulesDetailed.find((m) => m.name === moduleCode); + if (!moduleEntry?.localPath) return null; + + // Only return the path if it still exists (source not removed) + if (await fs.pathExists(moduleEntry.localPath)) { + return moduleEntry.localPath; + } + + return null; + } catch { + return null; + } + } + + /** + * Recursively find repo root directories within the cache. + * A repo root is identified by containing .bmad-source.json (new) or .claude-plugin/ (legacy). + * Handles both 3-level (host/owner/repo) and legacy 2-level (owner/repo) cache layouts. + * @param {string} dir - Directory to search + * @param {number} [depth=0] - Current recursion depth + * @param {number} [maxDepth=4] - Maximum recursion depth + * @returns {Promise>} + */ + async _findCacheRepoRoots(dir, depth = 0, maxDepth = 4) { + const results = []; + + // Check if this directory is a repo root + const metadataPath = path.join(dir, '.bmad-source.json'); + const claudePluginDir = path.join(dir, '.claude-plugin'); + + if (await fs.pathExists(metadataPath)) { + try { + const metadata = JSON.parse(await fs.readFile(metadataPath, 'utf8')); + results.push({ repoPath: dir, metadata }); + } catch { + results.push({ repoPath: dir, metadata: null }); + } + return results; // Don't recurse into repo contents + } + if (await fs.pathExists(claudePluginDir)) { + results.push({ repoPath: dir, metadata: null }); + return results; + } + + // Recurse into subdirectories + if (depth >= maxDepth) return results; + try { + const entries = await fs.readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory() || entry.name.startsWith('.')) continue; + const subResults = await this._findCacheRepoRoots(path.join(dir, entry.name), depth + 1, maxDepth); + results.push(...subResults); + } + } catch { + // Directory not readable + } + return results; + } + + // ─── Normalization ──────────────────────────────────────────────────────── + + /** + * Normalize a plugin from marketplace.json to a consistent shape. + * @param {Object} plugin - Plugin object from marketplace.json + * @param {string|null} sourceUrl - Source URL (null for local paths) + * @param {Object} data - Full marketplace.json data + * @returns {Object} Normalized module info + */ + _normalizeCustomModule(plugin, sourceUrl, data) { + return { + code: plugin.name, + name: plugin.name, + displayName: plugin.name, + description: plugin.description || '', + version: plugin.version || null, + author: plugin.author || data.owner || '', + url: sourceUrl || null, + source: plugin.source || null, + skills: plugin.skills || [], + rawPlugin: plugin, + type: 'custom', + trustTier: 'unverified', + builtIn: false, + isExternal: true, + }; + } +} + +module.exports = { CustomModuleManager }; diff --git a/tools/installer/modules/external-manager.js b/tools/installer/modules/external-manager.js new file mode 100644 index 000000000..0b8f5074c --- /dev/null +++ b/tools/installer/modules/external-manager.js @@ -0,0 +1,330 @@ +const fs = require('fs-extra'); +const os = require('node:os'); +const path = require('node:path'); +const { execSync } = require('node:child_process'); +const yaml = require('yaml'); +const prompts = require('../prompts'); +const { RegistryClient } = require('./registry-client'); + +const REGISTRY_RAW_URL = 'https://raw.githubusercontent.com/bmad-code-org/bmad-plugins-marketplace/main/registry/official.yaml'; +const FALLBACK_CONFIG_PATH = path.join(__dirname, 'registry-fallback.yaml'); + +/** + * Manages official modules from the remote BMad marketplace registry. + * Fetches registry/official.yaml from GitHub; falls back to the bundled + * external-official-modules.yaml when the network is unavailable. + * + * @class ExternalModuleManager + */ +class ExternalModuleManager { + constructor() { + this._client = new RegistryClient(); + } + + /** + * Load the official modules registry from GitHub, falling back to the + * bundled YAML file if the fetch fails. + * @returns {Object} Parsed YAML content with modules array + */ + async loadExternalModulesConfig() { + if (this.cachedModules) { + return this.cachedModules; + } + + // Try remote registry first + try { + const content = await this._client.fetch(REGISTRY_RAW_URL); + const config = yaml.parse(content); + if (config?.modules?.length) { + this.cachedModules = config; + return config; + } + } catch { + // Fall through to local fallback + } + + // Fallback to bundled file + try { + const content = await fs.readFile(FALLBACK_CONFIG_PATH, 'utf8'); + const config = yaml.parse(content); + this.cachedModules = config; + await prompts.log.warn('Could not reach BMad registry; using bundled module list.'); + return config; + } catch (error) { + await prompts.log.warn(`Failed to load modules config: ${error.message}`); + return { modules: [] }; + } + } + + /** + * Normalize a module entry from either the remote registry format + * (snake_case, array) or the legacy bundled format (kebab-case, object map). + * @param {Object} mod - Raw module config from YAML + * @param {string} [key] - Key name (only for legacy map format) + * @returns {Object} Normalized module info + */ + _normalizeModule(mod, key) { + return { + key: key || mod.name, + url: mod.repository || mod.url, + moduleDefinition: mod.module_definition || mod['module-definition'], + code: mod.code, + name: mod.display_name || mod.name, + description: mod.description || '', + defaultSelected: mod.default_selected === true || mod.defaultSelected === true, + type: mod.type || 'bmad-org', + npmPackage: mod.npm_package || mod.npmPackage || null, + builtIn: mod.built_in === true, + isExternal: mod.built_in !== true, + }; + } + + /** + * Get list of available modules from the registry + * @returns {Array} Array of module info objects + */ + async listAvailable() { + const config = await this.loadExternalModulesConfig(); + + // Remote format: modules is an array + if (Array.isArray(config.modules)) { + return config.modules.map((mod) => this._normalizeModule(mod)); + } + + // Legacy bundled format: modules is an object map + const modules = []; + for (const [key, mod] of Object.entries(config.modules || {})) { + modules.push(this._normalizeModule(mod, key)); + } + return modules; + } + + /** + * Get module info by code + * @param {string} code - The module code (e.g., 'cis') + * @returns {Object|null} Module info or null if not found + */ + async getModuleByCode(code) { + const modules = await this.listAvailable(); + return modules.find((m) => m.code === code) || null; + } + + /** + * Get the cache directory for external modules + * @returns {string} Path to the external modules cache directory + */ + getExternalCacheDir() { + const cacheDir = path.join(os.homedir(), '.bmad', 'cache', 'external-modules'); + return cacheDir; + } + + /** + * Clone an external module repository to cache + * @param {string} moduleCode - Code of the external module + * @param {Object} options - Clone options + * @param {boolean} options.silent - Suppress spinner output + * @returns {string} Path to the cloned repository + */ + async cloneExternalModule(moduleCode, options = {}) { + const moduleInfo = await this.getModuleByCode(moduleCode); + + if (!moduleInfo) { + throw new Error(`External module '${moduleCode}' not found in the BMad registry`); + } + + const cacheDir = this.getExternalCacheDir(); + const moduleCacheDir = path.join(cacheDir, moduleCode); + const silent = options.silent || false; + + // Create cache directory if it doesn't exist + await fs.ensureDir(cacheDir); + + // Helper to create a spinner or a no-op when silent + const createSpinner = async () => { + if (silent) { + return { + start() {}, + stop() {}, + error() {}, + message() {}, + cancel() {}, + clear() {}, + get isSpinning() { + return false; + }, + get isCancelled() { + return false; + }, + }; + } + return await prompts.spinner(); + }; + + // Track if we need to install dependencies + let needsDependencyInstall = false; + let wasNewClone = false; + + // Check if already cloned + if (await fs.pathExists(moduleCacheDir)) { + // Try to update if it's a git repo + const fetchSpinner = await createSpinner(); + fetchSpinner.start(`Fetching ${moduleInfo.name}...`); + try { + const currentRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim(); + // Fetch and reset to remote - works better with shallow clones than pull + execSync('git fetch origin --depth 1', { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + execSync('git reset --hard origin/HEAD', { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + const newRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim(); + + fetchSpinner.stop(`Fetched ${moduleInfo.name}`); + // Force dependency install if we got new code + if (currentRef !== newRef) { + needsDependencyInstall = true; + } + } catch { + fetchSpinner.error(`Fetch failed, re-downloading ${moduleInfo.name}`); + // If update fails, remove and re-clone + await fs.remove(moduleCacheDir); + wasNewClone = true; + } + } else { + wasNewClone = true; + } + + // Clone if not exists or was removed + if (wasNewClone) { + const fetchSpinner = await createSpinner(); + fetchSpinner.start(`Fetching ${moduleInfo.name}...`); + try { + execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, { + stdio: ['ignore', 'pipe', 'pipe'], + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + fetchSpinner.stop(`Fetched ${moduleInfo.name}`); + } catch (error) { + fetchSpinner.error(`Failed to fetch ${moduleInfo.name}`); + throw new Error(`Failed to clone external module '${moduleCode}': ${error.message}`); + } + } + + // Install dependencies if package.json exists + const packageJsonPath = path.join(moduleCacheDir, 'package.json'); + const nodeModulesPath = path.join(moduleCacheDir, 'node_modules'); + if (await fs.pathExists(packageJsonPath)) { + // Install if node_modules doesn't exist, or if package.json is newer (dependencies changed) + const nodeModulesMissing = !(await fs.pathExists(nodeModulesPath)); + + // Force install if we updated or cloned new + if (needsDependencyInstall || wasNewClone || nodeModulesMissing) { + const installSpinner = await createSpinner(); + installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`); + try { + execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 120_000, // 2 minute timeout + }); + installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`); + } catch (error) { + installSpinner.error(`Failed to install dependencies for ${moduleInfo.name}`); + if (!silent) await prompts.log.warn(` ${error.message}`); + } + } else { + // Check if package.json is newer than node_modules + let packageJsonNewer = false; + try { + const packageStats = await fs.stat(packageJsonPath); + const nodeModulesStats = await fs.stat(nodeModulesPath); + packageJsonNewer = packageStats.mtime > nodeModulesStats.mtime; + } catch { + // If stat fails, assume we need to install + packageJsonNewer = true; + } + + if (packageJsonNewer) { + const installSpinner = await createSpinner(); + installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`); + try { + execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', { + cwd: moduleCacheDir, + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 120_000, // 2 minute timeout + }); + installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`); + } catch (error) { + installSpinner.error(`Failed to install dependencies for ${moduleInfo.name}`); + if (!silent) await prompts.log.warn(` ${error.message}`); + } + } + } + } + + return moduleCacheDir; + } + + /** + * Find the source path for an external module + * @param {string} moduleCode - Code of the external module + * @param {Object} options - Options passed to cloneExternalModule + * @returns {string|null} Path to the module source or null if not found + */ + async findExternalModuleSource(moduleCode, options = {}) { + const moduleInfo = await this.getModuleByCode(moduleCode); + + if (!moduleInfo || moduleInfo.builtIn) { + return null; + } + + // Clone the external module repo + const cloneDir = await this.cloneExternalModule(moduleCode, options); + + // The module-definition specifies the path to module.yaml relative to repo root + // We need to return the directory containing module.yaml + const moduleDefinitionPath = moduleInfo.moduleDefinition; // e.g., 'skills/module.yaml' + const configuredPath = path.join(cloneDir, moduleDefinitionPath); + + if (await fs.pathExists(configuredPath)) { + return path.dirname(configuredPath); + } + + // Fallback: search skills/ and src/ (root level and one level deep for subfolders) + for (const dir of ['skills', 'src']) { + const rootCandidate = path.join(cloneDir, dir, 'module.yaml'); + if (await fs.pathExists(rootCandidate)) { + return path.dirname(rootCandidate); + } + const dirPath = path.join(cloneDir, dir); + if (await fs.pathExists(dirPath)) { + const entries = await fs.readdir(dirPath, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const subCandidate = path.join(dirPath, entry.name, 'module.yaml'); + if (await fs.pathExists(subCandidate)) { + return path.dirname(subCandidate); + } + } + } + } + } + + // Check repo root as last fallback + const rootCandidate = path.join(cloneDir, 'module.yaml'); + if (await fs.pathExists(rootCandidate)) { + return path.dirname(rootCandidate); + } + + // Nothing found: return configured path (preserves old behavior for error messaging) + return path.dirname(configuredPath); + } + cachedModules = null; +} + +module.exports = { ExternalModuleManager }; diff --git a/tools/cli/installers/lib/core/config-collector.js b/tools/installer/modules/official-modules.js similarity index 61% rename from tools/cli/installers/lib/core/config-collector.js rename to tools/installer/modules/official-modules.js index 665c7957a..6158a7863 100644 --- a/tools/cli/installers/lib/core/config-collector.js +++ b/tools/installer/modules/official-modules.js @@ -1,30 +1,735 @@ const path = require('node:path'); const fs = require('fs-extra'); const yaml = require('yaml'); -const { getProjectRoot, getModulePath } = require('../../../lib/project-root'); -const { CLIUtils } = require('../../../lib/cli-utils'); -const prompts = require('../../../lib/prompts'); +const prompts = require('../prompts'); +const { getProjectRoot, getSourcePath, getModulePath } = require('../project-root'); +const { CLIUtils } = require('../cli-utils'); +const { ExternalModuleManager } = require('./external-manager'); -class ConfigCollector { - constructor() { +class OfficialModules { + constructor(options = {}) { + this.externalModuleManager = new ExternalModuleManager(); + // Config collection state (merged from ConfigCollector) this.collectedConfig = {}; - this.existingConfig = null; + this._existingConfig = null; + // Tracked during interactive config collection so {directory_name} + // placeholder defaults can be resolved in buildQuestion(). this.currentProjectDir = null; - this._moduleManagerInstance = null; } /** - * Get or create a cached ModuleManager instance (lazy initialization) - * @returns {Object} ModuleManager instance + * Module configurations collected during install. */ - _getModuleManager() { - if (!this._moduleManagerInstance) { - const { ModuleManager } = require('../modules/manager'); - this._moduleManagerInstance = new ModuleManager(); - } - return this._moduleManagerInstance; + get moduleConfigs() { + return this.collectedConfig; } + /** + * Existing module configurations read from a previous installation. + */ + get existingConfig() { + return this._existingConfig; + } + + /** + * Build a configured OfficialModules instance from install config. + * @param {Object} config - Clean install config (from Config.build) + * @param {Object} paths - InstallPaths instance + * @returns {OfficialModules} + */ + static async build(config, paths) { + const instance = new OfficialModules(); + + // Pre-collected by UI or quickUpdate — store and load existing for path-change detection + if (config.moduleConfigs) { + instance.collectedConfig = config.moduleConfigs; + await instance.loadExistingConfig(paths.projectRoot); + return instance; + } + + // Headless collection (--yes flag from CLI without UI, tests) + if (config.hasCoreConfig()) { + instance.collectedConfig.core = config.coreConfig; + instance.allAnswers = {}; + for (const [key, value] of Object.entries(config.coreConfig)) { + instance.allAnswers[`core_${key}`] = value; + } + } + + const toCollect = config.hasCoreConfig() ? config.modules.filter((m) => m !== 'core') : [...config.modules]; + + await instance.collectAllConfigurations(toCollect, paths.projectRoot, { + skipPrompts: config.skipPrompts, + }); + + return instance; + } + + /** + * Copy a file to the target location + * @param {string} sourcePath - Source file path + * @param {string} targetPath - Target file path + * @param {boolean} overwrite - Whether to overwrite existing files (default: true) + */ + async copyFile(sourcePath, targetPath, overwrite = true) { + await fs.copy(sourcePath, targetPath, { overwrite }); + } + + /** + * Copy a directory recursively + * @param {string} sourceDir - Source directory path + * @param {string} targetDir - Target directory path + * @param {boolean} overwrite - Whether to overwrite existing files (default: true) + */ + async copyDirectory(sourceDir, targetDir, overwrite = true) { + await fs.ensureDir(targetDir); + const entries = await fs.readdir(sourceDir, { withFileTypes: true }); + + for (const entry of entries) { + const sourcePath = path.join(sourceDir, entry.name); + const targetPath = path.join(targetDir, entry.name); + + if (entry.isDirectory()) { + await this.copyDirectory(sourcePath, targetPath, overwrite); + } else { + await this.copyFile(sourcePath, targetPath, overwrite); + } + } + } + + /** + * List all available built-in modules (core and bmm). + * All other modules come from external-official-modules.yaml + * @returns {Object} Object with modules array + */ + async listAvailable() { + const modules = []; + + // Add built-in core module (directly under src/core-skills) + const corePath = getSourcePath('core-skills'); + if (await fs.pathExists(corePath)) { + const coreInfo = await this.getModuleInfo(corePath, 'core', 'src/core-skills'); + if (coreInfo) { + modules.push(coreInfo); + } + } + + // Add built-in bmm module (directly under src/bmm-skills) + const bmmPath = getSourcePath('bmm-skills'); + if (await fs.pathExists(bmmPath)) { + const bmmInfo = await this.getModuleInfo(bmmPath, 'bmm', 'src/bmm-skills'); + if (bmmInfo) { + modules.push(bmmInfo); + } + } + + return { modules }; + } + + /** + * Get module information from a module path + * @param {string} modulePath - Path to the module directory + * @param {string} defaultName - Default name for the module + * @param {string} sourceDescription - Description of where the module was found + * @returns {Object|null} Module info or null if not a valid module + */ + async getModuleInfo(modulePath, defaultName, sourceDescription) { + const moduleConfigPath = path.join(modulePath, 'module.yaml'); + + if (!(await fs.pathExists(moduleConfigPath))) { + // Check resolution cache for strategy 5 modules (no module.yaml on disk) + const { CustomModuleManager } = require('./custom-module-manager'); + const customMgr = new CustomModuleManager(); + const resolved = customMgr.getResolution(defaultName); + if (resolved && resolved.synthesizedModuleYaml) { + return { + id: resolved.code, + path: modulePath, + name: resolved.name, + description: resolved.description, + version: resolved.version || '1.0.0', + source: sourceDescription, + dependencies: [], + defaultSelected: false, + }; + } + return null; + } + + const moduleInfo = { + id: defaultName, + path: modulePath, + name: defaultName + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '), + description: 'BMAD Module', + version: '5.0.0', + source: sourceDescription, + }; + + // Read module config for metadata + try { + const configContent = await fs.readFile(moduleConfigPath, 'utf8'); + const config = yaml.parse(configContent); + + // Use the code property as the id if available + if (config.code) { + moduleInfo.id = config.code; + } + + moduleInfo.name = config.name || moduleInfo.name; + moduleInfo.description = config.description || moduleInfo.description; + moduleInfo.version = config.version || moduleInfo.version; + moduleInfo.dependencies = config.dependencies || []; + moduleInfo.defaultSelected = config.default_selected === undefined ? false : config.default_selected; + } catch (error) { + await prompts.log.warn(`Failed to read config for ${defaultName}: ${error.message}`); + } + + return moduleInfo; + } + + /** + * Find the source path for a module by searching all possible locations + * @param {string} moduleCode - Code of the module to find (from module.yaml) + * @returns {string|null} Path to the module source or null if not found + */ + async findModuleSource(moduleCode, options = {}) { + const projectRoot = getProjectRoot(); + + // Check for core module (directly under src/core-skills) + if (moduleCode === 'core') { + const corePath = getSourcePath('core-skills'); + if (await fs.pathExists(corePath)) { + return corePath; + } + } + + // Check for built-in bmm module (directly under src/bmm-skills) + if (moduleCode === 'bmm') { + const bmmPath = getSourcePath('bmm-skills'); + if (await fs.pathExists(bmmPath)) { + return bmmPath; + } + } + + // Check external official modules + const externalSource = await this.externalModuleManager.findExternalModuleSource(moduleCode, options); + if (externalSource) { + return externalSource; + } + + // Check community modules + const { CommunityModuleManager } = require('./community-manager'); + const communityMgr = new CommunityModuleManager(); + const communitySource = await communityMgr.findModuleSource(moduleCode, options); + if (communitySource) { + return communitySource; + } + + // Check custom modules (from user-provided URLs, already cloned to cache) + const { CustomModuleManager } = require('./custom-module-manager'); + const customMgr = new CustomModuleManager(); + const customSource = await customMgr.findModuleSourceByCode(moduleCode, options); + if (customSource) { + return customSource; + } + + return null; + } + + /** + * Install a module + * @param {string} moduleName - Code of the module to install (from module.yaml) + * @param {string} bmadDir - Target bmad directory + * @param {Function} fileTrackingCallback - Optional callback to track installed files + * @param {Object} options - Additional installation options + * @param {Array} options.installedIDEs - Array of IDE codes that were installed + * @param {Object} options.moduleConfig - Module configuration from config collector + * @param {Object} options.logger - Logger instance for output + */ + async install(moduleName, bmadDir, fileTrackingCallback = null, options = {}) { + // Check if this module has a plugin resolution (custom marketplace install) + const { CustomModuleManager } = require('./custom-module-manager'); + const customMgr = new CustomModuleManager(); + const resolved = customMgr.getResolution(moduleName); + if (resolved) { + return this.installFromResolution(resolved, bmadDir, fileTrackingCallback, options); + } + + const sourcePath = await this.findModuleSource(moduleName, { silent: options.silent }); + const targetPath = path.join(bmadDir, moduleName); + + if (!sourcePath) { + throw new Error( + `Source for module '${moduleName}' is not available. It will be retained but cannot be updated without its source files.`, + ); + } + + if (await fs.pathExists(targetPath)) { + await fs.remove(targetPath); + } + + await this.copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback, options.moduleConfig); + + if (!options.skipModuleInstaller) { + await this.createModuleDirectories(moduleName, bmadDir, options); + } + + const { Manifest } = require('../core/manifest'); + const manifestObj = new Manifest(); + const versionInfo = await manifestObj.getModuleVersionInfo(moduleName, bmadDir, sourcePath); + + await manifestObj.addModule(bmadDir, moduleName, { + version: versionInfo.version, + source: versionInfo.source, + npmPackage: versionInfo.npmPackage, + repoUrl: versionInfo.repoUrl, + }); + + return { success: true, module: moduleName, path: targetPath, versionInfo }; + } + + /** + * Install a module from a PluginResolver resolution result. + * Copies specific skill directories and places module-help.csv at the target root. + * @param {Object} resolved - ResolvedModule from PluginResolver + * @param {string} bmadDir - Target bmad directory + * @param {Function} fileTrackingCallback - Optional callback to track installed files + * @param {Object} options - Installation options + */ + async installFromResolution(resolved, bmadDir, fileTrackingCallback = null, options = {}) { + const targetPath = path.join(bmadDir, resolved.code); + + if (await fs.pathExists(targetPath)) { + await fs.remove(targetPath); + } + + await fs.ensureDir(targetPath); + + // Copy each skill directory, flattened by leaf name + for (const skillPath of resolved.skillPaths) { + const skillDirName = path.basename(skillPath); + const skillTarget = path.join(targetPath, skillDirName); + await this.copyModuleWithFiltering(skillPath, skillTarget, fileTrackingCallback, options.moduleConfig); + } + + // Place module-help.csv at the module root + if (resolved.moduleHelpCsvPath) { + // Strategies 1-4: copy the existing file + const helpTarget = path.join(targetPath, 'module-help.csv'); + await fs.copy(resolved.moduleHelpCsvPath, helpTarget, { overwrite: true }); + if (fileTrackingCallback) fileTrackingCallback(helpTarget); + } else if (resolved.synthesizedHelpCsv) { + // Strategy 5: write synthesized content + const helpTarget = path.join(targetPath, 'module-help.csv'); + await fs.writeFile(helpTarget, resolved.synthesizedHelpCsv, 'utf8'); + if (fileTrackingCallback) fileTrackingCallback(helpTarget); + } + + // Create directories declared in module.yaml (strategies 1-4 may have these) + if (!options.skipModuleInstaller) { + await this.createModuleDirectories(resolved.code, bmadDir, options); + } + + // Update manifest + const { Manifest } = require('../core/manifest'); + const manifestObj = new Manifest(); + + await manifestObj.addModule(bmadDir, resolved.code, { + version: resolved.version || null, + source: 'custom', + npmPackage: null, + repoUrl: resolved.repoUrl || null, + }); + + return { success: true, module: resolved.code, path: targetPath, versionInfo: { version: resolved.version || '' } }; + } + + /** + * Update an existing module + * @param {string} moduleName - Name of the module to update + * @param {string} bmadDir - Target bmad directory + */ + async update(moduleName, bmadDir) { + const sourcePath = await this.findModuleSource(moduleName); + const targetPath = path.join(bmadDir, moduleName); + + if (!sourcePath) { + throw new Error(`Module '${moduleName}' not found in any source location`); + } + + if (!(await fs.pathExists(targetPath))) { + throw new Error(`Module '${moduleName}' is not installed`); + } + + await this.syncModule(sourcePath, targetPath); + + return { + success: true, + module: moduleName, + path: targetPath, + }; + } + + /** + * Remove a module + * @param {string} moduleName - Name of the module to remove + * @param {string} bmadDir - Target bmad directory + */ + async remove(moduleName, bmadDir) { + const targetPath = path.join(bmadDir, moduleName); + + if (!(await fs.pathExists(targetPath))) { + throw new Error(`Module '${moduleName}' is not installed`); + } + + await fs.remove(targetPath); + + return { + success: true, + module: moduleName, + }; + } + + /** + * Check if a module is installed + * @param {string} moduleName - Name of the module + * @param {string} bmadDir - Target bmad directory + * @returns {boolean} True if module is installed + */ + async isInstalled(moduleName, bmadDir) { + const targetPath = path.join(bmadDir, moduleName); + return await fs.pathExists(targetPath); + } + + /** + * Get installed module info + * @param {string} moduleName - Name of the module + * @param {string} bmadDir - Target bmad directory + * @returns {Object|null} Module info or null if not installed + */ + async getInstalledInfo(moduleName, bmadDir) { + const targetPath = path.join(bmadDir, moduleName); + + if (!(await fs.pathExists(targetPath))) { + return null; + } + + const configPath = path.join(targetPath, 'config.yaml'); + const moduleInfo = { + id: moduleName, + path: targetPath, + installed: true, + }; + + if (await fs.pathExists(configPath)) { + try { + const configContent = await fs.readFile(configPath, 'utf8'); + const config = yaml.parse(configContent); + Object.assign(moduleInfo, config); + } catch (error) { + await prompts.log.warn(`Failed to read installed module config: ${error.message}`); + } + } + + return moduleInfo; + } + + /** + * Copy module with filtering for localskip agents and conditional content + * @param {string} sourcePath - Source module path + * @param {string} targetPath - Target module path + * @param {Function} fileTrackingCallback - Optional callback to track installed files + * @param {Object} moduleConfig - Module configuration with conditional flags + */ + async copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback = null, moduleConfig = {}) { + // Get all files in source + const sourceFiles = await this.getFileList(sourcePath); + + for (const file of sourceFiles) { + // Skip sub-modules directory - these are IDE-specific and handled separately + if (file.startsWith('sub-modules/')) { + continue; + } + + // Skip sidecar directories - these contain agent-specific assets not needed at install time + const isInSidecarDirectory = path + .dirname(file) + .split('/') + .some((dir) => dir.toLowerCase().endsWith('-sidecar')); + + if (isInSidecarDirectory) { + continue; + } + + // Skip module.yaml at root - it's only needed at install time + if (file === 'module.yaml') { + continue; + } + + // Skip module root config.yaml only - generated by config collector with actual values + // Workflow-level config.yaml (e.g. workflows/orchestrate-story/config.yaml) must be copied + // for custom modules that use workflow-specific configuration + if (file === 'config.yaml') { + continue; + } + + const sourceFile = path.join(sourcePath, file); + const targetFile = path.join(targetPath, file); + + // Check if this is an agent file + if (file.startsWith('agents/') && file.endsWith('.md')) { + // Read the file to check for localskip + const content = await fs.readFile(sourceFile, 'utf8'); + + // Check for localskip="true" in the agent tag + const agentMatch = content.match(/]*\slocalskip="true"[^>]*>/); + if (agentMatch) { + await prompts.log.message(` Skipping web-only agent: ${path.basename(file)}`); + continue; // Skip this agent + } + } + + // Copy the file with placeholder replacement + await this.copyFile(sourceFile, targetFile); + + // Track the file if callback provided + if (fileTrackingCallback) { + fileTrackingCallback(targetFile); + } + } + } + + /** + * Create directories declared in module.yaml's `directories` key + * This replaces the security-risky module installer pattern with declarative config + * During updates, if a directory path changed, moves the old directory to the new path + * @param {string} moduleName - Name of the module + * @param {string} bmadDir - Target bmad directory + * @param {Object} options - Installation options + * @param {Object} options.moduleConfig - Module configuration from config collector + * @param {Object} options.existingModuleConfig - Previous module config (for detecting path changes during updates) + * @param {Object} options.coreConfig - Core configuration + * @returns {Promise<{createdDirs: string[], movedDirs: string[], createdWdsFolders: string[]}>} Created directories info + */ + async createModuleDirectories(moduleName, bmadDir, options = {}) { + const moduleConfig = options.moduleConfig || {}; + const existingModuleConfig = options.existingModuleConfig || {}; + const projectRoot = path.dirname(bmadDir); + const emptyResult = { createdDirs: [], movedDirs: [], createdWdsFolders: [] }; + + // Special handling for core module - it's in src/core-skills not src/modules + let sourcePath; + if (moduleName === 'core') { + sourcePath = getSourcePath('core-skills'); + } else { + sourcePath = await this.findModuleSource(moduleName, { silent: true }); + if (!sourcePath) { + return emptyResult; // No source found, skip + } + } + + // Read module.yaml to find the `directories` key + const moduleYamlPath = path.join(sourcePath, 'module.yaml'); + if (!(await fs.pathExists(moduleYamlPath))) { + return emptyResult; // No module.yaml, skip + } + + let moduleYaml; + try { + const yamlContent = await fs.readFile(moduleYamlPath, 'utf8'); + moduleYaml = yaml.parse(yamlContent); + } catch (error) { + await prompts.log.warn(`Invalid module.yaml for ${moduleName}: ${error.message}`); + return emptyResult; + } + + if (!moduleYaml || !moduleYaml.directories) { + return emptyResult; // No directories declared, skip + } + + const directories = moduleYaml.directories; + const wdsFolders = moduleYaml.wds_folders || []; + const createdDirs = []; + const movedDirs = []; + const createdWdsFolders = []; + + for (const dirRef of directories) { + // Parse variable reference like "{design_artifacts}" + const varMatch = dirRef.match(/^\{([^}]+)\}$/); + if (!varMatch) { + // Not a variable reference, skip + continue; + } + + const configKey = varMatch[1]; + const dirValue = moduleConfig[configKey]; + if (!dirValue || typeof dirValue !== 'string') { + continue; // No value or not a string, skip + } + + // Strip {project-root}/ prefix if present + let dirPath = dirValue.replace(/^\{project-root\}\/?/, ''); + + // Handle remaining {project-root} anywhere in the path + dirPath = dirPath.replaceAll('{project-root}', ''); + + // Resolve to absolute path + const fullPath = path.join(projectRoot, dirPath); + + // Validate path is within project root (prevent directory traversal) + const normalizedPath = path.normalize(fullPath); + const normalizedRoot = path.normalize(projectRoot); + if (!normalizedPath.startsWith(normalizedRoot + path.sep) && normalizedPath !== normalizedRoot) { + const color = await prompts.getColor(); + await prompts.log.warn(color.yellow(`${configKey} path escapes project root, skipping: ${dirPath}`)); + continue; + } + + // Check if directory path changed from previous config (update/modify scenario) + const oldDirValue = existingModuleConfig[configKey]; + let oldFullPath = null; + let oldDirPath = null; + if (oldDirValue && typeof oldDirValue === 'string') { + // F3: Normalize both values before comparing to avoid false negatives + // from trailing slashes, separator differences, or prefix format variations + let normalizedOld = oldDirValue.replace(/^\{project-root\}\/?/, ''); + normalizedOld = path.normalize(normalizedOld.replaceAll('{project-root}', '')); + const normalizedNew = path.normalize(dirPath); + + if (normalizedOld !== normalizedNew) { + oldDirPath = normalizedOld; + oldFullPath = path.join(projectRoot, oldDirPath); + const normalizedOldAbsolute = path.normalize(oldFullPath); + if (!normalizedOldAbsolute.startsWith(normalizedRoot + path.sep) && normalizedOldAbsolute !== normalizedRoot) { + oldFullPath = null; // Old path escapes project root, ignore it + } + + // F13: Prevent parent/child move (e.g. docs/planning → docs/planning/v2) + if (oldFullPath) { + const normalizedNewAbsolute = path.normalize(fullPath); + if ( + normalizedOldAbsolute.startsWith(normalizedNewAbsolute + path.sep) || + normalizedNewAbsolute.startsWith(normalizedOldAbsolute + path.sep) + ) { + const color = await prompts.getColor(); + await prompts.log.warn( + color.yellow( + `${configKey}: cannot move between parent/child paths (${oldDirPath} / ${dirPath}), creating new directory instead`, + ), + ); + oldFullPath = null; + } + } + } + } + + const dirName = configKey.replaceAll('_', ' '); + + if (oldFullPath && (await fs.pathExists(oldFullPath)) && !(await fs.pathExists(fullPath))) { + // Path changed and old dir exists → move old to new location + // F1: Use fs.move() instead of fs.rename() for cross-device/volume support + // F2: Wrap in try/catch — fallback to creating new dir on failure + try { + await fs.ensureDir(path.dirname(fullPath)); + await fs.move(oldFullPath, fullPath); + movedDirs.push(`${dirName}: ${oldDirPath} → ${dirPath}`); + } catch (moveError) { + const color = await prompts.getColor(); + await prompts.log.warn( + color.yellow( + `Failed to move ${oldDirPath} → ${dirPath}: ${moveError.message}\n Creating new directory instead. Please move contents from the old directory manually.`, + ), + ); + await fs.ensureDir(fullPath); + createdDirs.push(`${dirName}: ${dirPath}`); + } + } else if (oldFullPath && (await fs.pathExists(oldFullPath)) && (await fs.pathExists(fullPath))) { + // F5: Both old and new directories exist — warn user about potential orphaned documents + const color = await prompts.getColor(); + await prompts.log.warn( + color.yellow( + `${dirName}: path changed but both directories exist:\n Old: ${oldDirPath}\n New: ${dirPath}\n Old directory may contain orphaned documents — please review and merge manually.`, + ), + ); + } else if (!(await fs.pathExists(fullPath))) { + // New directory doesn't exist yet → create it + createdDirs.push(`${dirName}: ${dirPath}`); + await fs.ensureDir(fullPath); + } + + // Create WDS subfolders if this is the design_artifacts directory + if (configKey === 'design_artifacts' && wdsFolders.length > 0) { + for (const subfolder of wdsFolders) { + const subPath = path.join(fullPath, subfolder); + if (!(await fs.pathExists(subPath))) { + await fs.ensureDir(subPath); + createdWdsFolders.push(subfolder); + } + } + } + } + + return { createdDirs, movedDirs, createdWdsFolders }; + } + + /** + * Private: Sync module files (preserving user modifications) + * @param {string} sourcePath - Source module path + * @param {string} targetPath - Target module path + */ + async syncModule(sourcePath, targetPath) { + // Get list of all source files + const sourceFiles = await this.getFileList(sourcePath); + + for (const file of sourceFiles) { + const sourceFile = path.join(sourcePath, file); + const targetFile = path.join(targetPath, file); + + // Check if target file exists and has been modified + if (await fs.pathExists(targetFile)) { + const sourceStats = await fs.stat(sourceFile); + const targetStats = await fs.stat(targetFile); + + // Skip if target is newer (user modified) + if (targetStats.mtime > sourceStats.mtime) { + continue; + } + } + + // Copy file with placeholder replacement + await this.copyFile(sourceFile, targetFile); + } + } + + /** + * Private: Get list of all files in a directory + * @param {string} dir - Directory path + * @param {string} baseDir - Base directory for relative paths + * @returns {Array} List of relative file paths + */ + async getFileList(dir, baseDir = dir) { + const files = []; + const entries = await fs.readdir(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + const subFiles = await this.getFileList(fullPath, baseDir); + files.push(...subFiles); + } else { + files.push(path.relative(baseDir, fullPath)); + } + } + + return files; + } + + // ─── Config collection methods (merged from ConfigCollector) ─── + /** * Find the bmad installation directory in a project * V6+ installations can use ANY folder name but ALWAYS have _config/manifest.yaml @@ -95,7 +800,7 @@ class ConfigCollector { * @param {string} projectDir - Target project directory */ async loadExistingConfig(projectDir) { - this.existingConfig = {}; + this._existingConfig = {}; // Check if project directory exists first if (!(await fs.pathExists(projectDir))) { @@ -129,7 +834,7 @@ class ConfigCollector { const content = await fs.readFile(moduleConfigPath, 'utf8'); const moduleConfig = yaml.parse(content); if (moduleConfig) { - this.existingConfig[entry.name] = moduleConfig; + this._existingConfig[entry.name] = moduleConfig; foundAny = true; } } catch { @@ -153,20 +858,15 @@ class ConfigCollector { const results = []; for (const moduleName of modules) { - // Resolve module.yaml path - custom paths first, then standard location, then ModuleManager search + // Resolve module.yaml path - standard location first, then OfficialModules search let moduleConfigPath = null; - const customPath = this.customModulePaths?.get(moduleName); - if (customPath) { - moduleConfigPath = path.join(customPath, 'module.yaml'); + const standardPath = path.join(getModulePath(moduleName), 'module.yaml'); + if (await fs.pathExists(standardPath)) { + moduleConfigPath = standardPath; } else { - const standardPath = path.join(getModulePath(moduleName), 'module.yaml'); - if (await fs.pathExists(standardPath)) { - moduleConfigPath = standardPath; - } else { - const moduleSourcePath = await this._getModuleManager().findModuleSource(moduleName, { silent: true }); - if (moduleSourcePath) { - moduleConfigPath = path.join(moduleSourcePath, 'module.yaml'); - } + const moduleSourcePath = await this.findModuleSource(moduleName, { silent: true }); + if (moduleSourcePath) { + moduleConfigPath = path.join(moduleSourcePath, 'module.yaml'); } } @@ -211,12 +911,9 @@ class ConfigCollector { * @param {Array} modules - List of modules to configure (including 'core') * @param {string} projectDir - Target project directory * @param {Object} options - Additional options - * @param {Map} options.customModulePaths - Map of module ID to source path for custom modules * @param {boolean} options.skipPrompts - Skip prompts and use defaults (for --yes flag) */ async collectAllConfigurations(modules, projectDir, options = {}) { - // Store custom module paths for use in collectModuleConfig - this.customModulePaths = options.customModulePaths || new Map(); this.skipPrompts = options.skipPrompts || false; this.modulesToCustomize = undefined; await this.loadExistingConfig(projectDir); @@ -347,9 +1044,8 @@ class ConfigCollector { */ async collectModuleConfigQuick(moduleName, projectDir, silentMode = true) { this.currentProjectDir = projectDir; - // Load existing config if not already loaded - if (!this.existingConfig) { + if (!this._existingConfig) { await this.loadExistingConfig(projectDir); } @@ -364,43 +1060,25 @@ class ConfigCollector { // If not found in src/modules, we need to find it by searching the project if (!(await fs.pathExists(moduleConfigPath))) { - const moduleSourcePath = await this._getModuleManager().findModuleSource(moduleName, { silent: true }); + const moduleSourcePath = await this.findModuleSource(moduleName, { silent: true }); if (moduleSourcePath) { moduleConfigPath = path.join(moduleSourcePath, 'module.yaml'); } } - let configPath = null; - let isCustomModule = false; - - if (await fs.pathExists(moduleConfigPath)) { - configPath = moduleConfigPath; - } else { - // Check if this is a custom module with custom.yaml - const moduleSourcePath = await this._getModuleManager().findModuleSource(moduleName, { silent: true }); - - if (moduleSourcePath) { - const rootCustomConfigPath = path.join(moduleSourcePath, 'custom.yaml'); - - if (await fs.pathExists(rootCustomConfigPath)) { - isCustomModule = true; - // For custom modules, we don't have an install-config schema, so just use existing values - // The custom.yaml values will be loaded and merged during installation - } - } - + if (!(await fs.pathExists(moduleConfigPath))) { // No config schema for this module - use existing values - if (this.existingConfig && this.existingConfig[moduleName]) { + if (this._existingConfig && this._existingConfig[moduleName]) { if (!this.collectedConfig[moduleName]) { this.collectedConfig[moduleName] = {}; } - this.collectedConfig[moduleName] = { ...this.existingConfig[moduleName] }; + this.collectedConfig[moduleName] = { ...this._existingConfig[moduleName] }; } return false; } - const configContent = await fs.readFile(configPath, 'utf8'); + const configContent = await fs.readFile(moduleConfigPath, 'utf8'); const moduleConfig = yaml.parse(configContent); if (!moduleConfig) { @@ -409,7 +1087,7 @@ class ConfigCollector { // Compare schema with existing config to find new/missing fields const configKeys = Object.keys(moduleConfig).filter((key) => key !== 'prompt'); - const existingKeys = this.existingConfig && this.existingConfig[moduleName] ? Object.keys(this.existingConfig[moduleName]) : []; + const existingKeys = this._existingConfig && this._existingConfig[moduleName] ? Object.keys(this._existingConfig[moduleName]) : []; // Check if this module has no configuration keys at all (like CIS) // Filter out metadata fields and only count actual config objects @@ -440,11 +1118,11 @@ class ConfigCollector { // If in silent mode and no new keys (neither interactive nor static), use existing config and skip prompts if (silentMode && newKeys.length === 0 && newStaticKeys.length === 0) { - if (this.existingConfig && this.existingConfig[moduleName]) { + if (this._existingConfig && this._existingConfig[moduleName]) { if (!this.collectedConfig[moduleName]) { this.collectedConfig[moduleName] = {}; } - this.collectedConfig[moduleName] = { ...this.existingConfig[moduleName] }; + this.collectedConfig[moduleName] = { ...this._existingConfig[moduleName] }; // Special handling for user_name: ensure it has a value if ( @@ -455,7 +1133,7 @@ class ConfigCollector { } // Also populate allAnswers for cross-referencing - for (const [key, value] of Object.entries(this.existingConfig[moduleName])) { + for (const [key, value] of Object.entries(this._existingConfig[moduleName])) { // Ensure user_name is properly set in allAnswers too let finalValue = value; if (moduleName === 'core' && key === 'user_name' && (!value || value === '[USER_NAME]')) { @@ -501,7 +1179,13 @@ class ConfigCollector { // Collect all answers (static + prompted) let allAnswers = { ...staticAnswers }; - if (questions.length > 0) { + if (questions.length > 0 && silentMode) { + // In silent mode (quick update), use defaults for new fields instead of prompting + for (const q of questions) { + allAnswers[q.name] = typeof q.default === 'function' ? q.default({}) : q.default; + } + await prompts.log.message(` \u2713 ${moduleName.toUpperCase()} module configured with defaults`); + } else if (questions.length > 0) { // Only show header if we actually have questions await CLIUtils.displayModuleConfigHeader(moduleName, moduleConfig.header, moduleConfig.subheader); await prompts.log.message(''); @@ -519,8 +1203,8 @@ class ConfigCollector { // Process all answers (both static and prompted) // First, copy existing config to preserve values that aren't being updated - if (this.existingConfig && this.existingConfig[moduleName]) { - this.collectedConfig[moduleName] = { ...this.existingConfig[moduleName] }; + if (this._existingConfig && this._existingConfig[moduleName]) { + this.collectedConfig[moduleName] = { ...this._existingConfig[moduleName] }; } else { this.collectedConfig[moduleName] = {}; } @@ -545,11 +1229,11 @@ class ConfigCollector { } // Copy over existing values for fields that weren't prompted - if (this.existingConfig && this.existingConfig[moduleName]) { + if (this._existingConfig && this._existingConfig[moduleName]) { if (!this.collectedConfig[moduleName]) { this.collectedConfig[moduleName] = {}; } - for (const [key, value] of Object.entries(this.existingConfig[moduleName])) { + for (const [key, value] of Object.entries(this._existingConfig[moduleName])) { if (!this.collectedConfig[moduleName][key]) { this.collectedConfig[moduleName][key] = value; this.allAnswers[`${moduleName}_${key}`] = value; @@ -652,7 +1336,7 @@ class ConfigCollector { async collectModuleConfig(moduleName, projectDir, skipLoadExisting = false, skipCompletion = false) { this.currentProjectDir = projectDir; // Load existing config if needed and not already loaded - if (!skipLoadExisting && !this.existingConfig) { + if (!skipLoadExisting && !this._existingConfig) { await this.loadExistingConfig(projectDir); } @@ -661,20 +1345,11 @@ class ConfigCollector { this.allAnswers = {}; } // Load module's config - // First, check if we have a custom module path for this module - let moduleConfigPath = null; - - if (this.customModulePaths && this.customModulePaths.has(moduleName)) { - const customPath = this.customModulePaths.get(moduleName); - moduleConfigPath = path.join(customPath, 'module.yaml'); - } else { - // Try the standard src/modules location - moduleConfigPath = path.join(getModulePath(moduleName), 'module.yaml'); - } + let moduleConfigPath = path.join(getModulePath(moduleName), 'module.yaml'); // If not found in src/modules or custom paths, search the project if (!(await fs.pathExists(moduleConfigPath))) { - const moduleSourcePath = await this._getModuleManager().findModuleSource(moduleName, { silent: true }); + const moduleSourcePath = await this.findModuleSource(moduleName, { silent: true }); if (moduleSourcePath) { moduleConfigPath = path.join(moduleSourcePath, 'module.yaml'); @@ -994,8 +1669,8 @@ class ConfigCollector { } // Prefer the current module's persisted value when re-prompting an existing install - if (!configValue && currentModule && this.existingConfig?.[currentModule]?.[configKey] !== undefined) { - configValue = this.existingConfig[currentModule][configKey]; + if (!configValue && currentModule && this._existingConfig?.[currentModule]?.[configKey] !== undefined) { + configValue = this._existingConfig[currentModule][configKey]; } // Check in already collected config @@ -1009,10 +1684,10 @@ class ConfigCollector { } // Fall back to other existing module config values - if (!configValue && this.existingConfig) { - for (const mod of Object.keys(this.existingConfig)) { - if (mod !== '_meta' && this.existingConfig[mod] && this.existingConfig[mod][configKey]) { - configValue = this.existingConfig[mod][configKey]; + if (!configValue && this._existingConfig) { + for (const mod of Object.keys(this._existingConfig)) { + if (mod !== '_meta' && this._existingConfig[mod] && this._existingConfig[mod][configKey]) { + configValue = this._existingConfig[mod][configKey]; break; } } @@ -1083,8 +1758,8 @@ class ConfigCollector { // Check for existing value let existingValue = null; - if (this.existingConfig && this.existingConfig[moduleName]) { - existingValue = this.existingConfig[moduleName][key]; + if (this._existingConfig && this._existingConfig[moduleName]) { + existingValue = this._existingConfig[moduleName][key]; existingValue = this.normalizeExistingValueForPrompt(existingValue, moduleName, item, moduleConfig); } @@ -1369,4 +2044,4 @@ class ConfigCollector { } } -module.exports = { ConfigCollector }; +module.exports = { OfficialModules }; diff --git a/tools/installer/modules/plugin-resolver.js b/tools/installer/modules/plugin-resolver.js new file mode 100644 index 000000000..9fbf325a2 --- /dev/null +++ b/tools/installer/modules/plugin-resolver.js @@ -0,0 +1,398 @@ +const fs = require('fs-extra'); +const path = require('node:path'); +const yaml = require('yaml'); + +/** + * Resolves how to install a plugin from marketplace.json by analyzing + * where module.yaml and module-help.csv live relative to the listed skills. + * + * Five strategies, tried in order: + * 1. Root module files at the common parent of all skills + * 2. A -setup skill with assets/module.yaml + assets/module-help.csv + * 3. Single standalone skill with both files in its assets/ + * 4. Multiple standalone skills, each with both files in assets/ + * 5. Fallback: synthesize from marketplace.json + SKILL.md frontmatter + */ +class PluginResolver { + /** + * Resolve a plugin to one or more installable module definitions. + * @param {string} repoPath - Absolute path to the cloned repository root + * @param {Object} plugin - Plugin object from marketplace.json + * @param {string} plugin.name - Plugin identifier + * @param {string} [plugin.source] - Relative path from repo root + * @param {string} [plugin.version] - Semantic version + * @param {string} [plugin.description] - Plugin description + * @param {string[]} [plugin.skills] - Relative paths to skill directories + * @returns {Promise} Array of resolved module definitions + */ + async resolve(repoPath, plugin) { + const skillRelPaths = plugin.skills || []; + + // No skills array: legacy behavior - caller should use existing findModuleSource + if (skillRelPaths.length === 0) { + return []; + } + + // Resolve skill paths to absolute, constrain to repo root, filter non-existent + const repoRoot = path.resolve(repoPath); + const skillPaths = []; + for (const rel of skillRelPaths) { + const normalized = rel.replace(/^\.\//, ''); + const abs = path.resolve(repoPath, normalized); + // Guard against path traversal (.. segments, absolute paths in marketplace.json) + if (!abs.startsWith(repoRoot + path.sep) && abs !== repoRoot) { + continue; + } + if (await fs.pathExists(abs)) { + skillPaths.push(abs); + } + } + + if (skillPaths.length === 0) { + return []; + } + + // Try each strategy in order + const result = + (await this._tryRootModuleFiles(repoPath, plugin, skillPaths)) || + (await this._trySetupSkill(repoPath, plugin, skillPaths)) || + (await this._trySingleStandalone(repoPath, plugin, skillPaths)) || + (await this._tryMultipleStandalone(repoPath, plugin, skillPaths)) || + (await this._synthesizeFallback(repoPath, plugin, skillPaths)); + + return result; + } + + // ─── Strategy 1: Root Module Files ────────────────────────────────────────── + + /** + * Check if module.yaml + module-help.csv exist at the common parent of all skills. + */ + async _tryRootModuleFiles(repoPath, plugin, skillPaths) { + const commonParent = this._computeCommonParent(skillPaths); + const moduleYamlPath = path.join(commonParent, 'module.yaml'); + const moduleHelpPath = path.join(commonParent, 'module-help.csv'); + + if (!(await fs.pathExists(moduleYamlPath)) || !(await fs.pathExists(moduleHelpPath))) { + return null; + } + + const moduleData = await this._readModuleYaml(moduleYamlPath); + if (!moduleData) return null; + + return [ + { + code: moduleData.code || plugin.name, + name: moduleData.name || plugin.name, + version: plugin.version || moduleData.module_version || null, + description: moduleData.description || plugin.description || '', + strategy: 1, + pluginName: plugin.name, + moduleYamlPath, + moduleHelpCsvPath: moduleHelpPath, + skillPaths, + synthesizedModuleYaml: null, + synthesizedHelpCsv: null, + }, + ]; + } + + // ─── Strategy 2: Setup Skill ──────────────────────────────────────────────── + + /** + * Search for a skill ending in -setup with assets/module.yaml + assets/module-help.csv. + */ + async _trySetupSkill(repoPath, plugin, skillPaths) { + for (const skillPath of skillPaths) { + const dirName = path.basename(skillPath); + if (!dirName.endsWith('-setup')) continue; + + const moduleYamlPath = path.join(skillPath, 'assets', 'module.yaml'); + const moduleHelpPath = path.join(skillPath, 'assets', 'module-help.csv'); + + if (!(await fs.pathExists(moduleYamlPath)) || !(await fs.pathExists(moduleHelpPath))) { + continue; + } + + const moduleData = await this._readModuleYaml(moduleYamlPath); + if (!moduleData) continue; + + return [ + { + code: moduleData.code || plugin.name, + name: moduleData.name || plugin.name, + version: plugin.version || moduleData.module_version || null, + description: moduleData.description || plugin.description || '', + strategy: 2, + pluginName: plugin.name, + moduleYamlPath, + moduleHelpCsvPath: moduleHelpPath, + skillPaths, + synthesizedModuleYaml: null, + synthesizedHelpCsv: null, + }, + ]; + } + + return null; + } + + // ─── Strategy 3: Single Standalone Skill ──────────────────────────────────── + + /** + * One skill listed, with assets/module.yaml + assets/module-help.csv. + */ + async _trySingleStandalone(repoPath, plugin, skillPaths) { + if (skillPaths.length !== 1) return null; + + const skillPath = skillPaths[0]; + const moduleYamlPath = path.join(skillPath, 'assets', 'module.yaml'); + const moduleHelpPath = path.join(skillPath, 'assets', 'module-help.csv'); + + if (!(await fs.pathExists(moduleYamlPath)) || !(await fs.pathExists(moduleHelpPath))) { + return null; + } + + const moduleData = await this._readModuleYaml(moduleYamlPath); + if (!moduleData) return null; + + return [ + { + code: moduleData.code || plugin.name, + name: moduleData.name || plugin.name, + version: plugin.version || moduleData.module_version || null, + description: moduleData.description || plugin.description || '', + strategy: 3, + pluginName: plugin.name, + moduleYamlPath, + moduleHelpCsvPath: moduleHelpPath, + skillPaths, + synthesizedModuleYaml: null, + synthesizedHelpCsv: null, + }, + ]; + } + + // ─── Strategy 4: Multiple Standalone Skills ───────────────────────────────── + + /** + * Multiple skills, each with assets/module.yaml + assets/module-help.csv. + * Each becomes its own installable module. + */ + async _tryMultipleStandalone(repoPath, plugin, skillPaths) { + if (skillPaths.length < 2) return null; + + const resolved = []; + + for (const skillPath of skillPaths) { + const moduleYamlPath = path.join(skillPath, 'assets', 'module.yaml'); + const moduleHelpPath = path.join(skillPath, 'assets', 'module-help.csv'); + + if (!(await fs.pathExists(moduleYamlPath)) || !(await fs.pathExists(moduleHelpPath))) { + continue; + } + + const moduleData = await this._readModuleYaml(moduleYamlPath); + if (!moduleData) continue; + + resolved.push({ + code: moduleData.code || path.basename(skillPath), + name: moduleData.name || path.basename(skillPath), + version: plugin.version || moduleData.module_version || null, + description: moduleData.description || '', + strategy: 4, + pluginName: plugin.name, + moduleYamlPath, + moduleHelpCsvPath: moduleHelpPath, + skillPaths: [skillPath], + synthesizedModuleYaml: null, + synthesizedHelpCsv: null, + }); + } + + // Only use strategy 4 if ALL skills have module files + if (resolved.length === skillPaths.length) { + return resolved; + } + + // Partial match: fall through to strategy 5 + return null; + } + + // ─── Strategy 5: Fallback (Synthesized) ───────────────────────────────────── + + /** + * No module files found anywhere. Synthesize from marketplace.json metadata + * and SKILL.md frontmatter. + */ + async _synthesizeFallback(repoPath, plugin, skillPaths) { + const skillInfos = []; + + for (const skillPath of skillPaths) { + const frontmatter = await this._parseSkillFrontmatter(skillPath); + skillInfos.push({ + dirName: path.basename(skillPath), + name: frontmatter.name || path.basename(skillPath), + description: frontmatter.description || '', + }); + } + + const moduleName = this._formatDisplayName(plugin.name); + const code = plugin.name; + + const synthesizedYaml = { + code, + name: moduleName, + description: plugin.description || '', + module_version: plugin.version || '1.0.0', + default_selected: false, + }; + + const synthesizedCsv = this._buildSynthesizedHelpCsv(moduleName, skillInfos); + + return [ + { + code, + name: moduleName, + version: plugin.version || null, + description: plugin.description || '', + strategy: 5, + pluginName: plugin.name, + moduleYamlPath: null, + moduleHelpCsvPath: null, + skillPaths, + synthesizedModuleYaml: synthesizedYaml, + synthesizedHelpCsv: synthesizedCsv, + }, + ]; + } + + // ─── Helpers ──────────────────────────────────────────────────────────────── + + /** + * Compute the deepest common ancestor directory of an array of absolute paths. + * @param {string[]} absPaths - Absolute directory paths + * @returns {string} Common parent directory + */ + _computeCommonParent(absPaths) { + if (absPaths.length === 0) return '/'; + if (absPaths.length === 1) return path.dirname(absPaths[0]); + + const segments = absPaths.map((p) => p.split(path.sep)); + const minLen = Math.min(...segments.map((s) => s.length)); + const common = []; + + for (let i = 0; i < minLen; i++) { + const segment = segments[0][i]; + if (segments.every((s) => s[i] === segment)) { + common.push(segment); + } else { + break; + } + } + + return common.join(path.sep) || '/'; + } + + /** + * Read and parse a module.yaml file. + * @param {string} yamlPath - Absolute path to module.yaml + * @returns {Object|null} Parsed content or null on failure + */ + async _readModuleYaml(yamlPath) { + try { + const content = await fs.readFile(yamlPath, 'utf8'); + return yaml.parse(content); + } catch { + return null; + } + } + + /** + * Extract name and description from a SKILL.md YAML frontmatter block. + * @param {string} skillDirPath - Absolute path to the skill directory + * @returns {Object} { name, description } or empty strings + */ + async _parseSkillFrontmatter(skillDirPath) { + const skillMdPath = path.join(skillDirPath, 'SKILL.md'); + try { + const content = await fs.readFile(skillMdPath, 'utf8'); + const match = content.match(/^---\s*\n([\s\S]*?)\n---/); + if (!match) return { name: '', description: '' }; + + const parsed = yaml.parse(match[1]); + return { + name: parsed.name || '', + description: parsed.description || '', + }; + } catch { + return { name: '', description: '' }; + } + } + + /** + * Build a synthesized module-help.csv from plugin metadata and skill frontmatter. + * Uses the standard 13-column format. + * @param {string} moduleName - Display name for the module column + * @param {Array<{dirName: string, name: string, description: string}>} skillInfos + * @returns {string} CSV content + */ + _buildSynthesizedHelpCsv(moduleName, skillInfos) { + const header = 'module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs'; + const rows = [header]; + + for (const info of skillInfos) { + const displayName = this._formatDisplayName(info.name || info.dirName); + const menuCode = this._generateMenuCode(info.name || info.dirName); + const description = this._escapeCSVField(info.description); + + rows.push(`${moduleName},${info.dirName},${displayName},${menuCode},${description},activate,,anytime,,,false,,`); + } + + return rows.join('\n') + '\n'; + } + + /** + * Format a kebab-case or snake_case name into a display name. + * Strips common prefixes like "bmad-" or "bmad-agent-". + * @param {string} name - Raw name + * @returns {string} Formatted display name + */ + _formatDisplayName(name) { + let cleaned = name.replace(/^bmad-agent-/, '').replace(/^bmad-/, ''); + return cleaned + .split(/[-_]/) + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + } + + /** + * Generate a short menu code from a skill name. + * Takes first letter of each significant word, uppercased, max 3 chars. + * @param {string} name - Skill name (kebab-case) + * @returns {string} Menu code (e.g., "CC" for "code-coach") + */ + _generateMenuCode(name) { + const cleaned = name.replace(/^bmad-agent-/, '').replace(/^bmad-/, ''); + const words = cleaned.split(/[-_]/).filter((w) => w.length > 0); + return words + .map((w) => w.charAt(0).toUpperCase()) + .join('') + .slice(0, 3); + } + + /** + * Escape a value for CSV output (wrap in quotes if it contains commas, quotes, or newlines). + * @param {string} value + * @returns {string} + */ + _escapeCSVField(value) { + if (!value) return ''; + if (value.includes(',') || value.includes('"') || value.includes('\n')) { + return `"${value.replaceAll('"', '""')}"`; + } + return value; + } +} + +module.exports = { PluginResolver }; diff --git a/tools/installer/modules/registry-client.js b/tools/installer/modules/registry-client.js new file mode 100644 index 000000000..53d220678 --- /dev/null +++ b/tools/installer/modules/registry-client.js @@ -0,0 +1,55 @@ +const https = require('node:https'); +const yaml = require('yaml'); + +/** + * Shared HTTP client for fetching registry data from GitHub. + * Used by ExternalModuleManager, CommunityModuleManager, and CustomModuleManager. + */ +class RegistryClient { + constructor(options = {}) { + this.timeout = options.timeout || 10_000; + } + + /** + * Fetch a URL and return the response body as a string. + * Follows one redirect (GitHub sometimes 301s). + * @param {string} url - URL to fetch + * @param {number} [timeout] - Timeout in ms (overrides default) + * @returns {Promise} Response body + */ + fetch(url, timeout) { + const timeoutMs = timeout || this.timeout; + return new Promise((resolve, reject) => { + const req = https + .get(url, { timeout: timeoutMs }, (res) => { + if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { + return this.fetch(res.headers.location, timeoutMs).then(resolve, reject); + } + if (res.statusCode !== 200) { + return reject(new Error(`HTTP ${res.statusCode}`)); + } + let data = ''; + res.on('data', (chunk) => (data += chunk)); + res.on('end', () => resolve(data)); + }) + .on('error', reject) + .on('timeout', () => { + req.destroy(); + reject(new Error('Request timed out')); + }); + }); + } + + /** + * Fetch a URL and parse the response as YAML. + * @param {string} url - URL to fetch + * @param {number} [timeout] - Timeout in ms + * @returns {Promise} Parsed YAML content + */ + async fetchYaml(url, timeout) { + const content = await this.fetch(url, timeout); + return yaml.parse(content); + } +} + +module.exports = { RegistryClient }; diff --git a/tools/cli/external-official-modules.yaml b/tools/installer/modules/registry-fallback.yaml similarity index 71% rename from tools/cli/external-official-modules.yaml rename to tools/installer/modules/registry-fallback.yaml index b62f3dc21..29b2cc07d 100644 --- a/tools/cli/external-official-modules.yaml +++ b/tools/installer/modules/registry-fallback.yaml @@ -1,5 +1,6 @@ -# This file allows these modules under bmad-code-org to also be installed with the bmad method installer, while -# allowing us to keep the source of these projects in separate repos. +# Fallback module registry — used only when the BMad Marketplace repo +# (bmad-code-org/bmad-plugins-marketplace) is unreachable. +# The remote registry/official.yaml is the source of truth. modules: bmad-builder: @@ -41,13 +42,3 @@ modules: defaultSelected: false type: bmad-org npmPackage: bmad-method-test-architecture-enterprise - - whiteport-design-studio: - url: https://github.com/bmad-code-org/bmad-method-wds-expansion - module-definition: src/module.yaml - code: wds - name: "Whiteport Design Studio (For UX Professionals)" - description: "Whiteport Design Studio (For UX Professionals)" - defaultSelected: false - type: community - npmPackage: bmad-method-wds-expansion diff --git a/tools/cli/lib/project-root.js b/tools/installer/project-root.js similarity index 100% rename from tools/cli/lib/project-root.js rename to tools/installer/project-root.js diff --git a/tools/cli/lib/prompts.js b/tools/installer/prompts.js similarity index 88% rename from tools/cli/lib/prompts.js rename to tools/installer/prompts.js index 24500700b..4f46e69b1 100644 --- a/tools/cli/lib/prompts.js +++ b/tools/installer/prompts.js @@ -498,26 +498,6 @@ async function password(options) { return result; } -/** - * Group multiple prompts together - * @param {Object} prompts - Object of prompt functions - * @param {Object} [options] - Group options - * @returns {Promise} Object with all answers - */ -async function group(prompts, options = {}) { - const clack = await getClack(); - - const result = await clack.group(prompts, { - onCancel: () => { - clack.cancel('Operation cancelled'); - process.exit(0); - }, - ...options, - }); - - return result; -} - /** * Run tasks with spinner feedback * @param {Array} tasks - Array of task objects [{title, task, enabled?}] @@ -578,42 +558,6 @@ async function box(content, title, options) { clack.box(content, title, options); } -/** - * Create a progress bar for visualizing task completion - * @param {Object} [options] - Progress options (max, style, etc.) - * @returns {Promise} Progress controller with start, advance, stop methods - */ -async function progress(options) { - const clack = await getClack(); - return clack.progress(options); -} - -/** - * Create a task log for displaying scrolling subprocess output - * @param {Object} options - TaskLog options (title, limit, retainLog) - * @returns {Promise} TaskLog controller with message, success, error methods - */ -async function taskLog(options) { - const clack = await getClack(); - return clack.taskLog(options); -} - -/** - * File system path prompt with autocomplete - * @param {Object} options - Path options - * @param {string} options.message - The prompt message - * @param {string} [options.initialValue] - Initial path value - * @param {boolean} [options.directory=false] - Only allow directories - * @param {Function} [options.validate] - Validation function - * @returns {Promise} Selected path - */ -async function pathPrompt(options) { - const clack = await getClack(); - const result = await clack.path(options); - await handleCancel(result); - return result; -} - /** * Autocomplete single-select prompt with type-ahead filtering * @param {Object} options - Autocomplete options @@ -631,50 +575,6 @@ async function autocomplete(options) { return result; } -/** - * Key-based instant selection prompt - * @param {Object} options - SelectKey options - * @param {string} options.message - The prompt message - * @param {Array} options.options - Array of choices [{value, label, hint?}] - * @returns {Promise} Selected value - */ -async function selectKey(options) { - const clack = await getClack(); - const result = await clack.selectKey(options); - await handleCancel(result); - return result; -} - -/** - * Stream messages with dynamic content (for LLMs, generators, etc.) - */ -const stream = { - async info(generator) { - const clack = await getClack(); - return clack.stream.info(generator); - }, - async success(generator) { - const clack = await getClack(); - return clack.stream.success(generator); - }, - async step(generator) { - const clack = await getClack(); - return clack.stream.step(generator); - }, - async warn(generator) { - const clack = await getClack(); - return clack.stream.warn(generator); - }, - async error(generator) { - const clack = await getClack(); - return clack.stream.error(generator); - }, - async message(generator, options) { - const clack = await getClack(); - return clack.stream.message(generator, options); - }, -}; - /** * Get the color utility (picocolors instance from @clack/prompts) * @returns {Promise} The color utility (picocolors) @@ -790,20 +690,14 @@ module.exports = { note, box, spinner, - progress, - taskLog, select, multiselect, autocompleteMultiselect, autocomplete, - selectKey, confirm, text, - path: pathPrompt, password, - group, tasks, log, - stream, prompt, }; diff --git a/tools/installer/ui.js b/tools/installer/ui.js new file mode 100644 index 000000000..9e48c647a --- /dev/null +++ b/tools/installer/ui.js @@ -0,0 +1,1599 @@ +const path = require('node:path'); +const os = require('node:os'); +const fs = require('fs-extra'); +const { CLIUtils } = require('./cli-utils'); +const { ExternalModuleManager } = require('./modules/external-manager'); +const { getProjectRoot } = require('./project-root'); +const prompts = require('./prompts'); + +/** + * Read module version from .claude-plugin/marketplace.json + * @param {string} moduleCode - Module code (e.g., 'core', 'bmm', 'cis') + * @returns {string} Version string or empty string + */ +async function getMarketplaceVersion(moduleCode) { + let marketplacePath; + if (moduleCode === 'core' || moduleCode === 'bmm') { + marketplacePath = path.join(getProjectRoot(), '.claude-plugin', 'marketplace.json'); + } else { + const cacheDir = path.join(os.homedir(), '.bmad', 'cache', 'external-modules', moduleCode); + marketplacePath = path.join(cacheDir, '.claude-plugin', 'marketplace.json'); + } + try { + if (await fs.pathExists(marketplacePath)) { + const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8')); + return _extractMarketplaceVersion(data); + } + } catch { + // ignore + } + return ''; +} + +/** + * Extract the highest version from marketplace.json plugins array. + * Handles multiple plugins per file safely. + * @param {Object} data - Parsed marketplace.json + * @returns {string} Version string or empty string + */ +function _extractMarketplaceVersion(data) { + const plugins = data?.plugins; + if (!Array.isArray(plugins) || plugins.length === 0) return ''; + // Use the highest version across all plugins in the file + let best = ''; + for (const p of plugins) { + if (p.version && (!best || p.version > best)) best = p.version; + } + return best; +} + +/** + * UI utilities for the installer + */ +class UI { + /** + * Prompt for installation configuration + * @param {Object} options - Command-line options from install command + * @returns {Object} Installation configuration + */ + async promptInstall(options = {}) { + await CLIUtils.displayLogo(); + + // Display version-specific start message from install-messages.yaml + const { MessageLoader } = require('./message-loader'); + const messageLoader = new MessageLoader(); + await messageLoader.displayStartMessage(); + + // Get directory from options or prompt + let confirmedDirectory; + if (options.directory) { + // Use provided directory from command-line + const expandedDir = this.expandUserPath(options.directory); + const validation = this.validateDirectorySync(expandedDir); + if (validation) { + throw new Error(`Invalid directory: ${validation}`); + } + confirmedDirectory = expandedDir; + await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`); + } else { + confirmedDirectory = await this.getConfirmedDirectory(); + } + + const { Installer } = require('./core/installer'); + const installer = new Installer(); + const { bmadDir } = await installer.findBmadDir(confirmedDirectory); + + // Check if there's an existing BMAD installation + const hasExistingInstall = await fs.pathExists(bmadDir); + + // Track action type (only set if there's an existing installation) + let actionType; + + // Only show action menu if there's an existing installation + if (hasExistingInstall) { + // Get version information + const { existingInstall, bmadDir } = await this.getExistingInstallation(confirmedDirectory); + + // Build menu choices dynamically + const choices = []; + + // Always show Quick Update first (allows refreshing installation even on same version) + if (existingInstall.installed) { + choices.push({ + name: 'Quick Update', + value: 'quick-update', + }); + } + + // Common actions + choices.push({ name: 'Modify BMAD Installation', value: 'update' }); + + // Check if action is provided via command-line + if (options.action) { + const validActions = choices.map((c) => c.value); + if (!validActions.includes(options.action)) { + throw new Error(`Invalid action: ${options.action}. Valid actions: ${validActions.join(', ')}`); + } + actionType = options.action; + await prompts.log.info(`Using action from command-line: ${actionType}`); + } else if (options.yes) { + // Default to quick-update if available, otherwise first available choice + if (choices.length === 0) { + throw new Error('No valid actions available for this installation'); + } + const hasQuickUpdate = choices.some((c) => c.value === 'quick-update'); + actionType = hasQuickUpdate ? 'quick-update' : choices[0].value; + await prompts.log.info(`Non-interactive mode (--yes): defaulting to ${actionType}`); + } else { + actionType = await prompts.select({ + message: 'How would you like to proceed?', + choices: choices, + default: choices[0].value, + }); + } + + // Handle quick update separately + if (actionType === 'quick-update') { + return { + actionType: 'quick-update', + directory: confirmedDirectory, + skipPrompts: options.yes || false, + }; + } + + // If actionType === 'update', handle it with the new flow + // Return early with modify configuration + if (actionType === 'update') { + // Get existing installation info + const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory); + + await prompts.log.message(`Found existing modules: ${[...installedModuleIds].join(', ')}`); + + // Unified module selection - all modules in one grouped multiselect + let selectedModules; + if (options.modules) { + // Use modules from command-line + selectedModules = options.modules + .split(',') + .map((m) => m.trim()) + .filter(Boolean); + await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`); + } else if (options.customSource) { + // Custom source without --modules: start with empty list (core added below) + selectedModules = []; + } else if (options.yes) { + selectedModules = await this.getDefaultModules(installedModuleIds); + await prompts.log.info( + `Non-interactive mode (--yes): using default modules (installed + defaults): ${selectedModules.join(', ')}`, + ); + } else { + selectedModules = await this.selectAllModules(installedModuleIds); + } + + // Resolve custom sources from --custom-source flag + if (options.customSource) { + const customCodes = await this._resolveCustomSourcesCli(options.customSource); + for (const code of customCodes) { + if (!selectedModules.includes(code)) selectedModules.push(code); + } + } + + // Ensure core is in the modules list + if (!selectedModules.includes('core')) { + selectedModules.unshift('core'); + } + + // Get tool selection + const toolSelection = await this.promptToolSelection(confirmedDirectory, options); + + const moduleConfigs = await this.collectModuleConfigs(confirmedDirectory, selectedModules, options); + + return { + actionType: 'update', + directory: confirmedDirectory, + modules: selectedModules, + ides: toolSelection.ides, + skipIde: toolSelection.skipIde, + coreConfig: moduleConfigs.core || {}, + moduleConfigs: moduleConfigs, + skipPrompts: options.yes || false, + }; + } + } + + // This section is only for new installations (update returns early above) + const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory); + + // Unified module selection - all modules in one grouped multiselect + let selectedModules; + if (options.modules) { + // Use modules from command-line + selectedModules = options.modules + .split(',') + .map((m) => m.trim()) + .filter(Boolean); + await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`); + } else if (options.customSource) { + // Custom source without --modules: start with empty list (core added below) + selectedModules = []; + } else if (options.yes) { + // Use default modules when --yes flag is set + selectedModules = await this.getDefaultModules(installedModuleIds); + await prompts.log.info(`Using default modules (--yes flag): ${selectedModules.join(', ')}`); + } else { + selectedModules = await this.selectAllModules(installedModuleIds); + } + + // Resolve custom sources from --custom-source flag + if (options.customSource) { + const customCodes = await this._resolveCustomSourcesCli(options.customSource); + for (const code of customCodes) { + if (!selectedModules.includes(code)) selectedModules.push(code); + } + } + + // Ensure core is in the modules list + if (!selectedModules.includes('core')) { + selectedModules.unshift('core'); + } + let toolSelection = await this.promptToolSelection(confirmedDirectory, options); + const moduleConfigs = await this.collectModuleConfigs(confirmedDirectory, selectedModules, options); + + return { + actionType: 'install', + directory: confirmedDirectory, + modules: selectedModules, + ides: toolSelection.ides, + skipIde: toolSelection.skipIde, + coreConfig: moduleConfigs.core || {}, + moduleConfigs: moduleConfigs, + skipPrompts: options.yes || false, + }; + } + + /** + * Prompt for tool/IDE selection (called after module configuration) + * Uses a split prompt approach: + * 1. Recommended tools - standard multiselect for preferred tools + * 2. Additional tools - autocompleteMultiselect with search capability + * @param {string} projectDir - Project directory to check for existing IDEs + * @param {Object} options - Command-line options + * @returns {Object} Tool configuration + */ + async promptToolSelection(projectDir, options = {}) { + const { ExistingInstall } = require('./core/existing-install'); + const { Installer } = require('./core/installer'); + const installer = new Installer(); + const { bmadDir } = await installer.findBmadDir(projectDir || process.cwd()); + const existingInstall = await ExistingInstall.detect(bmadDir); + const configuredIdes = existingInstall.ides; + + // Get IDE manager to fetch available IDEs dynamically + const { IdeManager } = require('./ide/manager'); + const ideManager = new IdeManager(); + await ideManager.ensureInitialized(); // IMPORTANT: Must initialize before getting IDEs + + const preferredIdes = ideManager.getPreferredIdes(); + const otherIdes = ideManager.getOtherIdes(); + + // Determine which configured IDEs are in "preferred" vs "other" categories + const configuredPreferred = configuredIdes.filter((id) => preferredIdes.some((ide) => ide.value === id)); + const configuredOther = configuredIdes.filter((id) => otherIdes.some((ide) => ide.value === id)); + + // Warn about previously configured tools that are no longer available + const allKnownValues = new Set([...preferredIdes, ...otherIdes].map((ide) => ide.value)); + const unknownTools = configuredIdes.filter((id) => id && typeof id === 'string' && !allKnownValues.has(id)); + if (unknownTools.length > 0) { + await prompts.log.warn(`Previously configured tools are no longer available: ${unknownTools.join(', ')}`); + } + + // ───────────────────────────────────────────────────────────────────────────── + // UPGRADE PATH: If tools already configured, show all tools with configured at top + // ───────────────────────────────────────────────────────────────────────────── + if (configuredIdes.length > 0) { + const allTools = [...preferredIdes, ...otherIdes]; + + // Non-interactive: handle --tools and --yes flags before interactive prompt + if (options.tools) { + if (options.tools.toLowerCase() === 'none') { + await prompts.log.info('Skipping tool configuration (--tools none)'); + return { ides: [], skipIde: true }; + } + const selectedIdes = options.tools + .split(',') + .map((t) => t.trim()) + .filter(Boolean); + await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`); + await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); + return { ides: selectedIdes, skipIde: false }; + } + + if (options.yes) { + await prompts.log.info(`Non-interactive mode (--yes): keeping configured tools: ${configuredIdes.join(', ')}`); + await this.displaySelectedTools(configuredIdes, preferredIdes, allTools); + return { ides: configuredIdes, skipIde: false }; + } + + // Sort: configured tools first, then preferred, then others + const sortedTools = [ + ...allTools.filter((ide) => configuredIdes.includes(ide.value)), + ...allTools.filter((ide) => !configuredIdes.includes(ide.value)), + ]; + + const upgradeOptions = sortedTools.map((ide) => { + const isConfigured = configuredIdes.includes(ide.value); + const isPreferred = preferredIdes.some((p) => p.value === ide.value); + let label = ide.name; + if (isPreferred) label += ' ⭐'; + if (isConfigured) label += ' ✅'; + return { label, value: ide.value }; + }); + + // Sort initialValues to match display order + const sortedInitialValues = sortedTools.filter((ide) => configuredIdes.includes(ide.value)).map((ide) => ide.value); + + const upgradeSelected = await prompts.autocompleteMultiselect({ + message: 'Integrate with', + options: upgradeOptions, + initialValues: sortedInitialValues, + required: false, + maxItems: 8, + }); + + const selectedIdes = upgradeSelected || []; + + if (selectedIdes.length === 0) { + const confirmNoTools = await prompts.confirm({ + message: 'No tools selected. Continue without installing any tools?', + default: false, + }); + + if (!confirmNoTools) { + return this.promptToolSelection(projectDir, options); + } + + return { ides: [], skipIde: true }; + } + + // Display selected tools + await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); + + return { ides: selectedIdes, skipIde: false }; + } + + // ───────────────────────────────────────────────────────────────────────────── + // NEW INSTALL: Show all tools with search + // ───────────────────────────────────────────────────────────────────────────── + const allTools = [...preferredIdes, ...otherIdes]; + + const allToolOptions = allTools.map((ide) => { + const isPreferred = preferredIdes.some((p) => p.value === ide.value); + let label = ide.name; + if (isPreferred) label += ' ⭐'; + return { + label, + value: ide.value, + }; + }); + + let selectedIdes = []; + + // Check if tools are provided via command-line + if (options.tools) { + // Check for explicit "none" value to skip tool installation + if (options.tools.toLowerCase() === 'none') { + await prompts.log.info('Skipping tool configuration (--tools none)'); + return { ides: [], skipIde: true }; + } else { + selectedIdes = options.tools + .split(',') + .map((t) => t.trim()) + .filter(Boolean); + await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`); + await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); + return { ides: selectedIdes, skipIde: false }; + } + } else if (options.yes) { + // If --yes flag is set, skip tool prompt and use previously configured tools or empty + if (configuredIdes.length > 0) { + await prompts.log.info(`Using previously configured tools (--yes flag): ${configuredIdes.join(', ')}`); + await this.displaySelectedTools(configuredIdes, preferredIdes, allTools); + return { ides: configuredIdes, skipIde: false }; + } else { + await prompts.log.info('Skipping tool configuration (--yes flag, no previous tools)'); + return { ides: [], skipIde: true }; + } + } + + // Interactive mode + const interactiveSelectedIdes = await prompts.autocompleteMultiselect({ + message: 'Integrate with:', + options: allToolOptions, + initialValues: configuredIdes.length > 0 ? configuredIdes : undefined, + required: false, + maxItems: 8, + }); + + selectedIdes = interactiveSelectedIdes || []; + + // ───────────────────────────────────────────────────────────────────────────── + // STEP 3: Confirm if no tools selected + // ───────────────────────────────────────────────────────────────────────────── + if (selectedIdes.length === 0) { + const confirmNoTools = await prompts.confirm({ + message: 'No tools selected. Continue without installing any tools?', + default: false, + }); + + if (!confirmNoTools) { + // User wants to select tools - recurse + return this.promptToolSelection(projectDir, options); + } + + return { + ides: [], + skipIde: true, + }; + } + + // Display selected tools + await this.displaySelectedTools(selectedIdes, preferredIdes, allTools); + + return { + ides: selectedIdes, + skipIde: selectedIdes.length === 0, + }; + } + + /** + * Prompt for update configuration + * @returns {Object} Update configuration + */ + async promptUpdate() { + const backupFirst = await prompts.confirm({ + message: 'Create backup before updating?', + default: true, + }); + + const preserveCustomizations = await prompts.confirm({ + message: 'Preserve local customizations?', + default: true, + }); + + return { backupFirst, preserveCustomizations }; + } + + /** + * Confirm action + * @param {string} message - Confirmation message + * @param {boolean} defaultValue - Default value + * @returns {boolean} User confirmation + */ + async confirm(message, defaultValue = false) { + return await prompts.confirm({ + message, + default: defaultValue, + }); + } + + /** + * Get confirmed directory from user + * @returns {string} Confirmed directory path + */ + async getConfirmedDirectory() { + let confirmedDirectory = null; + while (!confirmedDirectory) { + const directoryAnswer = await this.promptForDirectory(); + await this.displayDirectoryInfo(directoryAnswer.directory); + + if (await this.confirmDirectory(directoryAnswer.directory)) { + confirmedDirectory = directoryAnswer.directory; + } + } + return confirmedDirectory; + } + + /** + * Get existing installation info and installed modules + * @param {string} directory - Installation directory + * @returns {Object} Object with existingInstall, installedModuleIds, and bmadDir + */ + async getExistingInstallation(directory) { + const { ExistingInstall } = require('./core/existing-install'); + const { Installer } = require('./core/installer'); + const installer = new Installer(); + const { bmadDir } = await installer.findBmadDir(directory); + const existingInstall = await ExistingInstall.detect(bmadDir); + const installedModuleIds = new Set(existingInstall.moduleIds); + + return { existingInstall, installedModuleIds, bmadDir }; + } + + /** + * Collect all module configurations (core + selected modules). + * All interactive prompting happens here in the UI layer. + * @param {string} directory - Installation directory + * @param {string[]} modules - Modules to configure (including 'core') + * @param {Object} options - Command-line options + * @returns {Object} Collected module configurations keyed by module name + */ + async collectModuleConfigs(directory, modules, options = {}) { + const { OfficialModules } = require('./modules/official-modules'); + const configCollector = new OfficialModules(); + + // Seed core config from CLI options if provided + if (options.userName || options.communicationLanguage || options.documentOutputLanguage || options.outputFolder) { + const coreConfig = {}; + if (options.userName) { + coreConfig.user_name = options.userName; + await prompts.log.info(`Using user name from command-line: ${options.userName}`); + } + if (options.communicationLanguage) { + coreConfig.communication_language = options.communicationLanguage; + await prompts.log.info(`Using communication language from command-line: ${options.communicationLanguage}`); + } + if (options.documentOutputLanguage) { + coreConfig.document_output_language = options.documentOutputLanguage; + await prompts.log.info(`Using document output language from command-line: ${options.documentOutputLanguage}`); + } + if (options.outputFolder) { + coreConfig.output_folder = options.outputFolder; + await prompts.log.info(`Using output folder from command-line: ${options.outputFolder}`); + } + + // Load existing config to merge with provided options + await configCollector.loadExistingConfig(directory); + const existingConfig = configCollector.collectedConfig.core || {}; + configCollector.collectedConfig.core = { ...existingConfig, ...coreConfig }; + + // If not all options are provided, collect the missing ones interactively (unless --yes flag) + if ( + !options.yes && + (!options.userName || !options.communicationLanguage || !options.documentOutputLanguage || !options.outputFolder) + ) { + await configCollector.collectModuleConfig('core', directory, false, true); + } + } else if (options.yes) { + // Use all defaults when --yes flag is set + await configCollector.loadExistingConfig(directory); + const existingConfig = configCollector.collectedConfig.core || {}; + + if (Object.keys(existingConfig).length === 0) { + let safeUsername; + try { + safeUsername = os.userInfo().username; + } catch { + safeUsername = process.env.USER || process.env.USERNAME || 'User'; + } + const defaultUsername = safeUsername.charAt(0).toUpperCase() + safeUsername.slice(1); + configCollector.collectedConfig.core = { + user_name: defaultUsername, + communication_language: 'English', + document_output_language: 'English', + output_folder: '_bmad-output', + }; + await prompts.log.info('Using default configuration (--yes flag)'); + } + } + + // Collect all module configs — core is skipped if already seeded above + await configCollector.collectAllConfigurations(modules, directory, { + skipPrompts: options.yes || false, + }); + + return configCollector.collectedConfig; + } + + /** + * Select all modules across three tiers: official, community, and custom URL. + * @param {Set} installedModuleIds - Currently installed module IDs + * @returns {Array} Selected module codes (excluding core) + */ + async selectAllModules(installedModuleIds = new Set()) { + // Phase 1: Official modules + const officialSelected = await this._selectOfficialModules(installedModuleIds); + + // Determine which installed modules are NOT official (community or custom). + // These must be preserved even if the user declines to browse community/custom. + const officialCodes = new Set(officialSelected); + const externalManager = new ExternalModuleManager(); + const registryModules = await externalManager.listAvailable(); + const officialRegistryCodes = new Set(['core', 'bmm', ...registryModules.map((m) => m.code)]); + const installedNonOfficial = [...installedModuleIds].filter((id) => !officialRegistryCodes.has(id)); + + // Phase 2: Community modules (category drill-down) + // Returns { codes, didBrowse } so we know if the user entered the flow + const communityResult = await this._browseCommunityModules(installedModuleIds); + + // Phase 3: Custom URL modules + const customSelected = await this._addCustomUrlModules(installedModuleIds); + + // Merge all selections + const allSelected = new Set([...officialSelected, ...communityResult.codes, ...customSelected]); + + // Auto-include installed non-official modules that the user didn't get + // a chance to manage (they declined to browse). If they did browse, + // trust their selections - they could have deselected intentionally. + if (!communityResult.didBrowse) { + for (const code of installedNonOfficial) { + allSelected.add(code); + } + } + + return [...allSelected]; + } + + /** + * Select official modules using autocompleteMultiselect. + * Extracted from the original selectAllModules - unchanged behavior. + * @param {Set} installedModuleIds - Currently installed module IDs + * @returns {Array} Selected official module codes + */ + async _selectOfficialModules(installedModuleIds = new Set()) { + // Built-in modules (core, bmm) come from local source, not the registry + const { OfficialModules } = require('./modules/official-modules'); + const builtInModules = (await new OfficialModules().listAvailable()).modules || []; + + // External modules come from the registry (with fallback) + const externalManager = new ExternalModuleManager(); + const registryModules = await externalManager.listAvailable(); + + const allOptions = []; + const initialValues = []; + const lockedValues = ['core']; + + const buildModuleEntry = async (code, name, description, isDefault) => { + const isInstalled = installedModuleIds.has(code); + const version = await getMarketplaceVersion(code); + const label = version ? `${name} (v${version})` : name; + return { + label, + value: code, + hint: description, + selected: isInstalled || isDefault, + }; + }; + + // Add built-in modules first (always available regardless of network) + const builtInCodes = new Set(); + for (const mod of builtInModules) { + const code = mod.id; + builtInCodes.add(code); + const entry = await buildModuleEntry(code, mod.name, mod.description, mod.defaultSelected); + allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint }); + if (entry.selected) { + initialValues.push(code); + } + } + + // Add external registry modules (skip built-in duplicates) + for (const mod of registryModules) { + if (mod.builtIn || builtInCodes.has(mod.code)) continue; + const entry = await buildModuleEntry(mod.code, mod.name, mod.description, mod.defaultSelected); + allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint }); + if (entry.selected) { + initialValues.push(mod.code); + } + } + + const selected = await prompts.autocompleteMultiselect({ + message: 'Select official modules to install:', + options: allOptions, + initialValues: initialValues.length > 0 ? initialValues : undefined, + lockedValues, + required: true, + maxItems: allOptions.length, + }); + + const result = selected ? [...selected] : []; + + if (result.length > 0) { + const moduleLines = result.map((moduleId) => { + const opt = allOptions.find((o) => o.value === moduleId); + return ` \u2022 ${opt?.label || moduleId}`; + }); + await prompts.log.message('Selected official modules:\n' + moduleLines.join('\n')); + } + + return result; + } + + /** + * Browse and select community modules using category drill-down. + * Featured/promoted modules appear at the top. + * @param {Set} installedModuleIds - Currently installed module IDs + * @returns {Object} { codes: string[], didBrowse: boolean } + */ + async _browseCommunityModules(installedModuleIds = new Set()) { + const browseCommunity = await prompts.confirm({ + message: 'Would you like to browse community modules?', + default: false, + }); + if (!browseCommunity) return { codes: [], didBrowse: false }; + + const { CommunityModuleManager } = require('./modules/community-manager'); + const communityMgr = new CommunityModuleManager(); + + const s = await prompts.spinner(); + s.start('Loading community module catalog...'); + + let categories, featured, allCommunity; + try { + [categories, featured, allCommunity] = await Promise.all([ + communityMgr.getCategoryList(), + communityMgr.listFeatured(), + communityMgr.listAll(), + ]); + s.stop(`Community catalog loaded (${allCommunity.length} modules)`); + } catch (error) { + s.error('Failed to load community catalog'); + await prompts.log.warn(` ${error.message}`); + return { codes: [], didBrowse: false }; + } + + if (allCommunity.length === 0) { + await prompts.log.info('No community modules are currently available.'); + return { codes: [], didBrowse: false }; + } + + const selectedCodes = new Set(); + let browsing = true; + + while (browsing) { + const categoryChoices = []; + + // Featured section at top + if (featured.length > 0) { + categoryChoices.push({ + value: '__featured__', + label: `\u2605 Featured (${featured.length} module${featured.length === 1 ? '' : 's'})`, + }); + } + + // Categories with module counts + for (const cat of categories) { + categoryChoices.push({ + value: cat.slug, + label: `${cat.name} (${cat.moduleCount} module${cat.moduleCount === 1 ? '' : 's'})`, + }); + } + + // Special actions at bottom + categoryChoices.push( + { value: '__all__', label: '\u25CE View all community modules' }, + { value: '__search__', label: '\u25CE Search by keyword' }, + { value: '__done__', label: '\u2713 Done browsing' }, + ); + + const selectedCount = selectedCodes.size; + const categoryChoice = await prompts.select({ + message: `Browse community modules${selectedCount > 0 ? ` (${selectedCount} selected)` : ''}:`, + choices: categoryChoices, + }); + + if (categoryChoice === '__done__') { + browsing = false; + continue; + } + + let modulesToShow; + switch (categoryChoice) { + case '__featured__': { + modulesToShow = featured; + + break; + } + case '__all__': { + modulesToShow = allCommunity; + + break; + } + case '__search__': { + const query = await prompts.text({ + message: 'Search community modules:', + placeholder: 'e.g., design, testing, game', + }); + if (!query || query.trim() === '') continue; + modulesToShow = await communityMgr.searchByKeyword(query.trim()); + if (modulesToShow.length === 0) { + await prompts.log.warn('No matching modules found.'); + continue; + } + + break; + } + default: { + modulesToShow = await communityMgr.listByCategory(categoryChoice); + } + } + + // Build options for autocompleteMultiselect + const trustBadge = (tier) => { + if (tier === 'bmad-certified') return '\u2713'; + if (tier === 'community-reviewed') return '\u25CB'; + return '\u26A0'; + }; + + const options = modulesToShow.map((mod) => { + const versionStr = mod.version ? ` (v${mod.version})` : ''; + const badge = trustBadge(mod.trustTier); + return { + label: `${mod.displayName}${versionStr} [${badge}]`, + value: mod.code, + hint: mod.description, + }; + }); + + // Pre-check modules that are already selected or installed + const initialValues = modulesToShow.filter((m) => selectedCodes.has(m.code) || installedModuleIds.has(m.code)).map((m) => m.code); + + const selected = await prompts.autocompleteMultiselect({ + message: 'Select community modules:', + options, + initialValues: initialValues.length > 0 ? initialValues : undefined, + required: false, + maxItems: Math.min(options.length, 10), + }); + + // Update accumulated selections: sync with what user selected in this view + const shownCodes = new Set(modulesToShow.map((m) => m.code)); + for (const code of shownCodes) { + if (selected && selected.includes(code)) { + selectedCodes.add(code); + } else { + selectedCodes.delete(code); + } + } + } + + if (selectedCodes.size > 0) { + const moduleLines = []; + for (const code of selectedCodes) { + const mod = await communityMgr.getModuleByCode(code); + moduleLines.push(` \u2022 ${mod?.displayName || code}`); + } + await prompts.log.message('Selected community modules:\n' + moduleLines.join('\n')); + } + + return { codes: [...selectedCodes], didBrowse: true }; + } + + /** + * Prompt user to install modules from custom sources (Git URLs or local paths). + * @param {Set} installedModuleIds - Currently installed module IDs + * @returns {Array} Selected custom module code strings + */ + async _addCustomUrlModules(installedModuleIds = new Set()) { + const addCustom = await prompts.confirm({ + message: 'Would you like to install from a custom source (Git URL or local path)?', + default: false, + }); + if (!addCustom) return []; + + const { CustomModuleManager } = require('./modules/custom-module-manager'); + const customMgr = new CustomModuleManager(); + const selectedModules = []; + + let addMore = true; + while (addMore) { + const sourceInput = await prompts.text({ + message: 'Git URL or local path:', + placeholder: 'https://github.com/owner/repo or /path/to/module', + validate: (input) => { + if (!input || input.trim() === '') return 'Source is required'; + const result = customMgr.parseSource(input.trim()); + return result.isValid ? undefined : result.error; + }, + }); + + const s = await prompts.spinner(); + s.start('Resolving source...'); + + let sourceResult; + try { + sourceResult = await customMgr.resolveSource(sourceInput.trim(), { skipInstall: true, silent: true }); + s.stop(sourceResult.parsed.type === 'local' ? 'Local source resolved' : 'Repository cloned'); + } catch (error) { + s.error('Failed to resolve source'); + await prompts.log.error(` ${error.message}`); + addMore = await prompts.confirm({ message: 'Try another source?', default: false }); + continue; + } + + if (sourceResult.parsed.type === 'local') { + await prompts.log.info('LOCAL MODULE: Pointing directly at local source (changes take effect on reinstall).'); + } else { + await prompts.log.warn( + 'UNVERIFIED MODULE: This module has not been reviewed by the BMad team.\n' + ' Only install modules from sources you trust.', + ); + } + + // Resolve plugins based on discovery mode vs direct mode + s.start('Analyzing plugin structure...'); + const allResolved = []; + const localPath = sourceResult.parsed.type === 'local' ? sourceResult.rootDir : null; + + if (sourceResult.mode === 'discovery') { + // Discovery mode: marketplace.json found, list available plugins + let plugins; + try { + plugins = await customMgr.discoverModules(sourceResult.marketplace, sourceResult.sourceUrl); + } catch (discoverError) { + s.error('Failed to discover modules'); + await prompts.log.error(` ${discoverError.message}`); + addMore = await prompts.confirm({ message: 'Try another source?', default: false }); + continue; + } + + const effectiveRepoPath = sourceResult.repoPath || sourceResult.rootDir; + for (const plugin of plugins) { + try { + const resolved = await customMgr.resolvePlugin(effectiveRepoPath, plugin.rawPlugin, sourceResult.sourceUrl, localPath); + if (resolved.length > 0) { + allResolved.push(...resolved); + } else { + // No skills array or empty - use plugin metadata as-is (legacy) + allResolved.push({ + code: plugin.code, + name: plugin.displayName || plugin.name, + version: plugin.version, + description: plugin.description, + strategy: 0, + pluginName: plugin.name, + skillPaths: [], + }); + } + } catch (resolveError) { + await prompts.log.warn(` Could not resolve ${plugin.name}: ${resolveError.message}`); + } + } + } else { + // Direct mode: no marketplace.json, scan directory for skills and resolve + const directPlugin = { + name: sourceResult.parsed.displayName || path.basename(sourceResult.rootDir), + source: '.', + skills: [], + }; + + // Scan for SKILL.md directories to populate skills array + try { + const entries = await fs.readdir(sourceResult.rootDir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const skillMd = path.join(sourceResult.rootDir, entry.name, 'SKILL.md'); + if (await fs.pathExists(skillMd)) { + directPlugin.skills.push(entry.name); + } + } + } + } catch (scanError) { + s.error('Failed to scan directory'); + await prompts.log.error(` ${scanError.message}`); + addMore = await prompts.confirm({ message: 'Try another source?', default: false }); + continue; + } + + if (directPlugin.skills.length > 0) { + try { + const resolved = await customMgr.resolvePlugin(sourceResult.rootDir, directPlugin, sourceResult.sourceUrl, localPath); + allResolved.push(...resolved); + } catch (resolveError) { + await prompts.log.warn(` Could not resolve: ${resolveError.message}`); + } + } + } + s.stop(`Found ${allResolved.length} installable module${allResolved.length === 1 ? '' : 's'}`); + + if (allResolved.length === 0) { + await prompts.log.warn('No installable modules found in this source.'); + addMore = await prompts.confirm({ message: 'Try another source?', default: false }); + continue; + } + + // Build multiselect choices + // Already-installed modules are pre-checked (update). New modules are unchecked (opt-in). + // Unchecking an installed module means "skip update" - removal is handled elsewhere. + const choices = allResolved.map((mod) => { + const versionStr = mod.version ? ` v${mod.version}` : ''; + const skillCount = mod.skillPaths ? mod.skillPaths.length : 0; + const skillStr = skillCount > 0 ? ` (${skillCount} skill${skillCount === 1 ? '' : 's'})` : ''; + const alreadyInstalled = installedModuleIds.has(mod.code); + const hint = alreadyInstalled ? 'update' : undefined; + + return { + name: `${mod.name}${versionStr}${skillStr}`, + value: mod.code, + hint, + checked: alreadyInstalled, + }; + }); + + // Show descriptions before the multiselect + for (const mod of allResolved) { + const versionStr = mod.version ? ` v${mod.version}` : ''; + await prompts.log.info(` ${mod.name}${versionStr}\n ${mod.description}`); + } + + const selected = await prompts.multiselect({ + message: 'Select modules to install:', + choices, + required: false, + }); + + if (selected && selected.length > 0) { + for (const code of selected) { + selectedModules.push(code); + } + } + + addMore = await prompts.confirm({ + message: 'Add another custom source?', + default: false, + }); + } + + if (selectedModules.length > 0) { + await prompts.log.message('Selected custom modules:\n' + selectedModules.map((c) => ` \u2022 ${c}`).join('\n')); + } + + return selectedModules; + } + + /** + * Resolve custom sources from --custom-source CLI flag (non-interactive). + * Auto-selects all discovered modules from each source. + * @param {string} sourcesArg - Comma-separated Git URLs or local paths + * @returns {Array} Module codes from all resolved sources + */ + async _resolveCustomSourcesCli(sourcesArg) { + const { CustomModuleManager } = require('./modules/custom-module-manager'); + const customMgr = new CustomModuleManager(); + const allCodes = []; + + const sources = sourcesArg + .split(',') + .map((s) => s.trim()) + .filter(Boolean); + + for (const source of sources) { + const s = await prompts.spinner(); + s.start(`Resolving ${source}...`); + + let sourceResult; + try { + sourceResult = await customMgr.resolveSource(source, { skipInstall: true, silent: true }); + s.stop(sourceResult.parsed.type === 'local' ? 'Local source resolved' : 'Repository cloned'); + } catch (error) { + s.error(`Failed to resolve ${source}`); + await prompts.log.error(` ${error.message}`); + continue; + } + + const s2 = await prompts.spinner(); + s2.start('Analyzing plugin structure...'); + const allResolved = []; + const localPath = sourceResult.parsed.type === 'local' ? sourceResult.rootDir : null; + + if (sourceResult.mode === 'discovery') { + try { + const plugins = await customMgr.discoverModules(sourceResult.marketplace, sourceResult.sourceUrl); + const effectiveRepoPath = sourceResult.repoPath || sourceResult.rootDir; + for (const plugin of plugins) { + try { + const resolved = await customMgr.resolvePlugin(effectiveRepoPath, plugin.rawPlugin, sourceResult.sourceUrl, localPath); + if (resolved.length > 0) { + allResolved.push(...resolved); + } + } catch { + // Skip unresolvable plugins + } + } + } catch (discoverError) { + s2.error('Failed to discover modules'); + await prompts.log.error(` ${discoverError.message}`); + continue; + } + } else { + // Direct mode: scan for SKILL.md directories + const directPlugin = { + name: sourceResult.parsed.displayName || path.basename(sourceResult.rootDir), + source: '.', + skills: [], + }; + try { + const entries = await fs.readdir(sourceResult.rootDir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const skillMd = path.join(sourceResult.rootDir, entry.name, 'SKILL.md'); + if (await fs.pathExists(skillMd)) { + directPlugin.skills.push(entry.name); + } + } + } + } catch { + // Skip unreadable directories + } + + if (directPlugin.skills.length > 0) { + try { + const resolved = await customMgr.resolvePlugin(sourceResult.rootDir, directPlugin, sourceResult.sourceUrl, localPath); + allResolved.push(...resolved); + } catch { + // Skip unresolvable + } + } + } + s2.stop(`Found ${allResolved.length} module${allResolved.length === 1 ? '' : 's'}`); + + for (const mod of allResolved) { + allCodes.push(mod.code); + const versionStr = mod.version ? ` v${mod.version}` : ''; + await prompts.log.info(` Custom module: ${mod.name}${versionStr}`); + } + } + + return allCodes; + } + + /** + * Get default modules for non-interactive mode + * @param {Set} installedModuleIds - Already installed module IDs + * @returns {Array} Default module codes + */ + async getDefaultModules(installedModuleIds = new Set()) { + // Built-in modules with default_selected come from local source + const { OfficialModules } = require('./modules/official-modules'); + const builtInModules = (await new OfficialModules().listAvailable()).modules || []; + + const defaultModules = []; + const seen = new Set(); + + for (const mod of builtInModules) { + if (mod.defaultSelected || installedModuleIds.has(mod.id)) { + defaultModules.push(mod.id); + seen.add(mod.id); + } + } + + // Add external registry defaults + const externalManager = new ExternalModuleManager(); + const registryModules = await externalManager.listAvailable(); + + for (const mod of registryModules) { + if (mod.builtIn || seen.has(mod.code)) continue; + if (mod.defaultSelected || installedModuleIds.has(mod.code)) { + defaultModules.push(mod.code); + } + } + + // If no defaults found, use 'bmm' as the fallback default + if (defaultModules.length === 0) { + defaultModules.push('bmm'); + } + + return defaultModules; + } + + /** + * Prompt for directory selection + * @returns {Object} Directory answer from prompt + */ + async promptForDirectory() { + // Use sync validation because @clack/prompts doesn't support async validate + const directory = await prompts.text({ + message: 'Installation directory:', + default: process.cwd(), + placeholder: process.cwd(), + validate: (input) => this.validateDirectorySync(input), + }); + + // Apply filter logic + let filteredDir = directory; + if (!filteredDir || filteredDir.trim() === '') { + filteredDir = process.cwd(); + } else { + filteredDir = this.expandUserPath(filteredDir); + } + + return { directory: filteredDir }; + } + + /** + * Display directory information + * @param {string} directory - The directory path + */ + async displayDirectoryInfo(directory) { + await prompts.log.info(`Resolved installation path: ${directory}`); + + const dirExists = await fs.pathExists(directory); + if (dirExists) { + // Show helpful context about the existing path + const stats = await fs.stat(directory); + if (stats.isDirectory()) { + const files = await fs.readdir(directory); + if (files.length > 0) { + // Check for any bmad installation (any folder with _config/manifest.yaml) + const { Installer } = require('./core/installer'); + const installer = new Installer(); + const bmadResult = await installer.findBmadDir(directory); + const hasBmadInstall = + (await fs.pathExists(bmadResult.bmadDir)) && (await fs.pathExists(path.join(bmadResult.bmadDir, '_config', 'manifest.yaml'))); + + const bmadNote = hasBmadInstall ? ` including existing BMAD installation (${path.basename(bmadResult.bmadDir)})` : ''; + await prompts.log.message(`Directory exists and contains ${files.length} item(s)${bmadNote}`); + } else { + await prompts.log.message('Directory exists and is empty'); + } + } + } + } + + /** + * Confirm directory selection + * @param {string} directory - The directory path + * @returns {boolean} Whether user confirmed + */ + async confirmDirectory(directory) { + const dirExists = await fs.pathExists(directory); + + if (dirExists) { + const proceed = await prompts.confirm({ + message: 'Install to this directory?', + default: true, + }); + + if (!proceed) { + await prompts.log.warn("Let's try again with a different path."); + } + + return proceed; + } else { + // Ask for confirmation to create the directory + const create = await prompts.confirm({ + message: `Create directory: ${directory}?`, + default: false, + }); + + if (!create) { + await prompts.log.warn("Let's try again with a different path."); + } + + return create; + } + } + + /** + * Validate directory path for installation (sync version for clack prompts) + * @param {string} input - User input path + * @returns {string|undefined} Error message or undefined if valid + */ + validateDirectorySync(input) { + // Allow empty input to use the default + if (!input || input.trim() === '') { + return; // Empty means use default, undefined = valid for clack + } + + let expandedPath; + try { + expandedPath = this.expandUserPath(input.trim()); + } catch (error) { + return error.message; + } + + // Check if the path exists + const pathExists = fs.pathExistsSync(expandedPath); + + if (!pathExists) { + // Find the first existing parent directory + const existingParent = this.findExistingParentSync(expandedPath); + + if (!existingParent) { + return 'Cannot create directory: no existing parent directory found'; + } + + // Check if the existing parent is writable + try { + fs.accessSync(existingParent, fs.constants.W_OK); + // Path doesn't exist but can be created - will prompt for confirmation later + return; + } catch { + // Provide a detailed error message explaining both issues + return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`; + } + } + + // If it exists, validate it's a directory and writable + const stat = fs.statSync(expandedPath); + if (!stat.isDirectory()) { + return `Path exists but is not a directory: ${expandedPath}`; + } + + // Check write permissions + try { + fs.accessSync(expandedPath, fs.constants.W_OK); + } catch { + return `Directory is not writable: ${expandedPath}`; + } + + return; + } + + /** + * Validate directory path for installation (async version) + * @param {string} input - User input path + * @returns {string|true} Error message or true if valid + */ + async validateDirectory(input) { + // Allow empty input to use the default + if (!input || input.trim() === '') { + return true; // Empty means use default + } + + let expandedPath; + try { + expandedPath = this.expandUserPath(input.trim()); + } catch (error) { + return error.message; + } + + // Check if the path exists + const pathExists = await fs.pathExists(expandedPath); + + if (!pathExists) { + // Find the first existing parent directory + const existingParent = await this.findExistingParent(expandedPath); + + if (!existingParent) { + return 'Cannot create directory: no existing parent directory found'; + } + + // Check if the existing parent is writable + try { + await fs.access(existingParent, fs.constants.W_OK); + // Path doesn't exist but can be created - will prompt for confirmation later + return true; + } catch { + // Provide a detailed error message explaining both issues + return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`; + } + } + + // If it exists, validate it's a directory and writable + const stat = await fs.stat(expandedPath); + if (!stat.isDirectory()) { + return `Path exists but is not a directory: ${expandedPath}`; + } + + // Check write permissions + try { + await fs.access(expandedPath, fs.constants.W_OK); + } catch { + return `Directory is not writable: ${expandedPath}`; + } + + return true; + } + + /** + * Find the first existing parent directory (sync version) + * @param {string} targetPath - The path to check + * @returns {string|null} The first existing parent directory, or null if none found + */ + findExistingParentSync(targetPath) { + let currentPath = path.resolve(targetPath); + + // Walk up the directory tree until we find an existing directory + while (currentPath !== path.dirname(currentPath)) { + // Stop at root + const parent = path.dirname(currentPath); + if (fs.pathExistsSync(parent)) { + return parent; + } + currentPath = parent; + } + + return null; // No existing parent found (shouldn't happen in practice) + } + + /** + * Find the first existing parent directory (async version) + * @param {string} targetPath - The path to check + * @returns {string|null} The first existing parent directory, or null if none found + */ + async findExistingParent(targetPath) { + let currentPath = path.resolve(targetPath); + + // Walk up the directory tree until we find an existing directory + while (currentPath !== path.dirname(currentPath)) { + // Stop at root + const parent = path.dirname(currentPath); + if (await fs.pathExists(parent)) { + return parent; + } + currentPath = parent; + } + + return null; // No existing parent found (shouldn't happen in practice) + } + + /** + * Expands the user-provided path: handles ~ and resolves to absolute. + * @param {string} inputPath - User input path. + * @returns {string} Absolute expanded path. + */ + expandUserPath(inputPath) { + if (typeof inputPath !== 'string') { + throw new TypeError('Path must be a string.'); + } + + let expanded = inputPath.trim(); + + // Handle tilde expansion + if (expanded.startsWith('~')) { + if (expanded === '~') { + expanded = os.homedir(); + } else if (expanded.startsWith('~' + path.sep)) { + const pathAfterHome = expanded.slice(2); // Remove ~/ or ~\ + expanded = path.join(os.homedir(), pathAfterHome); + } else { + const restOfPath = expanded.slice(1); + const separatorIndex = restOfPath.indexOf(path.sep); + const username = separatorIndex === -1 ? restOfPath : restOfPath.slice(0, separatorIndex); + if (username) { + throw new Error(`Path expansion for ~${username} is not supported. Please use an absolute path or ~${path.sep}`); + } + } + } + + // Resolve to the absolute path relative to the current working directory + return path.resolve(expanded); + } + + /** + * Get configured IDEs from existing installation + * @param {string} directory - Installation directory + * @returns {Array} List of configured IDEs + */ + async getConfiguredIdes(directory) { + const { ExistingInstall } = require('./core/existing-install'); + const { Installer } = require('./core/installer'); + const installer = new Installer(); + const { bmadDir } = await installer.findBmadDir(directory); + const existingInstall = await ExistingInstall.detect(bmadDir); + return existingInstall.ides; + } + + /** + * Display module versions with update availability + * @param {Array} modules - Array of module info objects with version info + * @param {Array} availableUpdates - Array of available updates + */ + async displayModuleVersions(modules, availableUpdates = []) { + // Group modules by source + const builtIn = modules.filter((m) => m.source === 'built-in'); + const external = modules.filter((m) => m.source === 'external'); + const community = modules.filter((m) => m.source === 'community'); + const custom = modules.filter((m) => m.source === 'custom'); + const unknown = modules.filter((m) => m.source === 'unknown'); + + const lines = []; + const formatGroup = (group, title) => { + if (group.length === 0) return; + lines.push(title); + for (const mod of group) { + const updateInfo = availableUpdates.find((u) => u.name === mod.name); + const versionDisplay = mod.version || 'unknown'; + if (updateInfo) { + lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2192 ${updateInfo.latestVersion} \u2191`); + } else { + lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2713`); + } + } + }; + + formatGroup(builtIn, 'Built-in Modules'); + formatGroup(external, 'External Modules (Official)'); + formatGroup(community, 'Community Modules'); + formatGroup(custom, 'Custom Modules'); + formatGroup(unknown, 'Other Modules'); + + await prompts.note(lines.join('\n'), 'Module Versions'); + } + + /** + * Prompt user to select which modules to update + * @param {Array} availableUpdates - Array of available updates + * @returns {Array} Selected module names to update + */ + async promptUpdateSelection(availableUpdates) { + if (availableUpdates.length === 0) { + return []; + } + + await prompts.log.info('Available Updates'); + + const choices = availableUpdates.map((update) => ({ + name: `${update.name} (v${update.installedVersion} \u2192 v${update.latestVersion})`, + value: update.name, + checked: true, // Default to selecting all updates + })); + + // Add "Update All" and "Cancel" options + const action = await prompts.select({ + message: 'How would you like to proceed?', + choices: [ + { name: 'Update all available modules', value: 'all' }, + { name: 'Select specific modules to update', value: 'select' }, + { name: 'Skip updates for now', value: 'skip' }, + ], + default: 'all', + }); + + if (action === 'all') { + return availableUpdates.map((u) => u.name); + } + + if (action === 'skip') { + return []; + } + + // Allow specific selection + const selected = await prompts.multiselect({ + message: 'Select modules to update (use arrow keys, space to toggle):', + choices: choices, + required: true, + }); + + return selected || []; + } + + /** + * Display status of all installed modules + * @param {Object} statusData - Status data with modules, installation info, and available updates + */ + async displayStatus(statusData) { + const { installation, modules, availableUpdates, bmadDir } = statusData; + + // Installation info + const infoLines = [ + `Version: ${installation.version || 'unknown'}`, + `Location: ${bmadDir}`, + `Installed: ${new Date(installation.installDate).toLocaleDateString()}`, + `Last Updated: ${installation.lastUpdated ? new Date(installation.lastUpdated).toLocaleDateString() : 'unknown'}`, + ]; + + await prompts.note(infoLines.join('\n'), 'BMAD Status'); + + // Module versions + await this.displayModuleVersions(modules, availableUpdates); + + // Update summary + if (availableUpdates.length > 0) { + await prompts.log.warn(`${availableUpdates.length} update(s) available`); + await prompts.log.message('Run \'bmad install\' and select "Quick Update" to update'); + } else { + await prompts.log.success('All modules are up to date'); + } + } + + /** + * Display list of selected tools after IDE selection + * @param {Array} selectedIdes - Array of selected IDE values + * @param {Array} preferredIdes - Array of preferred IDE objects + * @param {Array} allTools - Array of all tool objects + */ + async displaySelectedTools(selectedIdes, preferredIdes, allTools) { + if (selectedIdes.length === 0) return; + + const preferredValues = new Set(preferredIdes.map((ide) => ide.value)); + const toolLines = selectedIdes.map((ideValue) => { + const tool = allTools.find((t) => t.value === ideValue); + const name = tool?.name || ideValue; + const marker = preferredValues.has(ideValue) ? ' \u2B50' : ''; + return ` \u2022 ${name}${marker}`; + }); + await prompts.log.message('Selected tools:\n' + toolLines.join('\n')); + } +} + +module.exports = { UI }; diff --git a/tools/cli/lib/yaml-format.js b/tools/installer/yaml-format.js similarity index 100% rename from tools/cli/lib/yaml-format.js rename to tools/installer/yaml-format.js diff --git a/tools/javascript-conventions.md b/tools/javascript-conventions.md new file mode 100644 index 000000000..99ea39520 --- /dev/null +++ b/tools/javascript-conventions.md @@ -0,0 +1,5 @@ +# JavaScript Conventions + +## Function ordering + +Define functions top-to-bottom in call order: callers above callees. If `install()` calls `_initPaths()`, then `install` appears first and `_initPaths` appears after it. diff --git a/tools/lib/xml-utils.js b/tools/lib/xml-utils.js deleted file mode 100644 index 482373151..000000000 --- a/tools/lib/xml-utils.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Escape XML special characters in a string - * @param {string} text - The text to escape - * @returns {string} The escaped text - */ -function escapeXml(text) { - if (!text) return ''; - return text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", '''); -} - -module.exports = { - escapeXml, -}; diff --git a/tools/platform-codes.yaml b/tools/platform-codes.yaml index f643d7aa6..7227af0ce 100644 --- a/tools/platform-codes.yaml +++ b/tools/platform-codes.yaml @@ -127,6 +127,12 @@ platforms: category: ide description: "AI-powered IDE with cascade flows" + junie: + name: "Junie" + preferred: false + category: cli + description: "AI coding agent by JetBrains" + ona: name: "Ona" preferred: false diff --git a/tools/validate-file-refs.js b/tools/validate-file-refs.js index a3b91f2fb..75a802967 100644 --- a/tools/validate-file-refs.js +++ b/tools/validate-file-refs.js @@ -83,7 +83,7 @@ function escapeTableCell(str) { const INSTALL_ONLY_PATHS = ['_config/']; // Files that are generated at install time and don't exist in the source tree -const INSTALL_GENERATED_FILES = ['config.yaml']; +const INSTALL_GENERATED_FILES = ['config.yaml', 'config.user.yaml']; // Variables that indicate a path is not statically resolvable const UNRESOLVABLE_VARS = [ @@ -156,8 +156,15 @@ function mapInstalledToSource(refPath) { // Skip install-only paths (generated at install time, not in source) if (isInstallOnly(cleaned)) return null; - // core/, bmm/, and utility/ are directly under src/ - if (cleaned.startsWith('core/') || cleaned.startsWith('bmm/') || cleaned.startsWith('utility/')) { + // Map installed module names to their source directory names + // _bmad/core/ → src/core-skills/, _bmad/bmm/ → src/bmm-skills/ + if (cleaned.startsWith('core/')) { + return path.join(SRC_DIR, 'core-skills', cleaned.slice('core/'.length)); + } + if (cleaned.startsWith('bmm/')) { + return path.join(SRC_DIR, 'bmm-skills', cleaned.slice('bmm/'.length)); + } + if (cleaned.startsWith('utility/')) { return path.join(SRC_DIR, cleaned); } diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 9d7efd99e..64ea3e0d9 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -50,12 +50,6 @@ export default defineConfig({ defaultLocale: 'root', locales, - logo: { - light: './public/img/bmad-light.png', - dark: './public/img/bmad-dark.png', - alt: 'BMAD Method', - replacesTitle: true, - }, favicon: '/favicon.ico', // Social links @@ -98,33 +92,55 @@ export default defineConfig({ // Sidebar configuration (Diataxis structure) sidebar: [ - { label: 'Welcome', translations: { 'zh-CN': '欢迎', 'fr-FR': 'Bienvenue' }, slug: 'index' }, - { label: 'Roadmap', translations: { 'zh-CN': '路线图', 'fr-FR': 'Feuille de route' }, slug: 'roadmap' }, + { + label: 'Welcome', + translations: { 'vi-VN': 'Chào mừng', 'zh-CN': '欢迎', 'fr-FR': 'Bienvenue', 'cs-CZ': 'Vítejte' }, + slug: 'index', + }, + { + label: 'Roadmap', + translations: { 'vi-VN': 'Lộ trình', 'zh-CN': '路线图', 'fr-FR': 'Feuille de route', 'cs-CZ': 'Plán rozvoje' }, + slug: 'roadmap', + }, { label: 'Tutorials', - translations: { 'zh-CN': '教程', 'fr-FR': 'Tutoriels' }, + translations: { 'vi-VN': 'Hướng dẫn nhập môn', 'zh-CN': '教程', 'fr-FR': 'Tutoriels', 'cs-CZ': 'Tutoriály' }, collapsed: false, autogenerate: { directory: 'tutorials' }, }, { label: 'How-To Guides', - translations: { 'zh-CN': '操作指南', 'fr-FR': 'Guides pratiques' }, + translations: { 'vi-VN': 'Hướng dẫn tác vụ', 'zh-CN': '操作指南', 'fr-FR': 'Guides pratiques', 'cs-CZ': 'Praktické návody' }, collapsed: true, autogenerate: { directory: 'how-to' }, }, { label: 'Explanation', - translations: { 'zh-CN': '概念说明', 'fr-FR': 'Explications' }, + translations: { 'vi-VN': 'Giải thích', 'zh-CN': '概念说明', 'fr-FR': 'Explications', 'cs-CZ': 'Vysvětlení' }, collapsed: true, autogenerate: { directory: 'explanation' }, }, { label: 'Reference', - translations: { 'zh-CN': '参考', 'fr-FR': 'Référence' }, + translations: { 'vi-VN': 'Tham chiếu', 'zh-CN': '参考', 'fr-FR': 'Référence', 'cs-CZ': 'Reference' }, collapsed: true, autogenerate: { directory: 'reference' }, }, // TEA docs moved to standalone module site; keep BMM sidebar focused. + { + label: 'BMad Ecosystem', + collapsed: false, + items: [ + { label: 'BMad Builder', link: 'https://bmad-builder-docs.bmad-method.org/', attrs: { target: '_blank' } }, + { label: 'Creative Intelligence Suite', link: 'https://cis-docs.bmad-method.org/', attrs: { target: '_blank' } }, + { label: 'Game Dev Studio', link: 'https://game-dev-studio-docs.bmad-method.org/', attrs: { target: '_blank' } }, + { + label: 'Test Architect (TEA)', + link: 'https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/', + attrs: { target: '_blank' }, + }, + ], + }, ], // Credits in footer diff --git a/website/public/diagrams/checkpoint-preview-diagram-fr.webp b/website/public/diagrams/checkpoint-preview-diagram-fr.webp new file mode 100644 index 000000000..caa0ac09b Binary files /dev/null and b/website/public/diagrams/checkpoint-preview-diagram-fr.webp differ diff --git a/website/public/diagrams/checkpoint-preview-diagram.png b/website/public/diagrams/checkpoint-preview-diagram.png new file mode 100644 index 000000000..a7e67adda Binary files /dev/null and b/website/public/diagrams/checkpoint-preview-diagram.png differ diff --git a/website/public/workflow-map-diagram-fr.html b/website/public/workflow-map-diagram-fr.html index f7a30ac58..1fde3c038 100644 --- a/website/public/workflow-map-diagram-fr.html +++ b/website/public/workflow-map-diagram-fr.html @@ -93,9 +93,8 @@ .agent-icon.john { background: linear-gradient(135deg, #60a5fa, #3b82f6); } .agent-icon.sally { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #000; } .agent-icon.winston { background: linear-gradient(135deg, #a78bfa, #8b5cf6); } - .agent-icon.bob { background: linear-gradient(135deg, #34d399, #10b981); color: #000; } .agent-icon.amelia { background: linear-gradient(135deg, #fb7185, #ef4444); } - .agent-icon.barry { background: linear-gradient(135deg, #94a3b8, #64748b); } + .agent-name { font-size: 0.65rem; } .output { color: var(--success); font-family: monospace; font-size: 0.6rem; } .badge { font-size: 0.55rem; padding: 1px 4px; border-radius: 3px; } @@ -261,7 +260,7 @@ sprint-planning
-
B
Bob
+
A
Amelia
sprint-status.yaml →
@@ -270,7 +269,7 @@ create-story
-
B
Bob
+
A
Amelia
story-[slug].md →
@@ -308,7 +307,7 @@ par Epic
-
B
Bob
+
A
Amelia
leçons
@@ -326,7 +325,7 @@
-
B
Barry
+
A
Amelia
quick-dev
intention → spec technique → code fonctionnel
diff --git a/website/public/workflow-map-diagram.html b/website/public/workflow-map-diagram.html index 2c6aedc86..0a17cc2eb 100644 --- a/website/public/workflow-map-diagram.html +++ b/website/public/workflow-map-diagram.html @@ -93,9 +93,8 @@ .agent-icon.john { background: linear-gradient(135deg, #60a5fa, #3b82f6); } .agent-icon.sally { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #000; } .agent-icon.winston { background: linear-gradient(135deg, #a78bfa, #8b5cf6); } - .agent-icon.bob { background: linear-gradient(135deg, #34d399, #10b981); color: #000; } .agent-icon.amelia { background: linear-gradient(135deg, #fb7185, #ef4444); } - .agent-icon.barry { background: linear-gradient(135deg, #94a3b8, #64748b); } + .agent-name { font-size: 0.65rem; } .output { color: var(--success); font-family: monospace; font-size: 0.6rem; } .badge { font-size: 0.55rem; padding: 1px 4px; border-radius: 3px; } @@ -169,13 +168,24 @@
- create-product-brief + product-brief + or ↓
M
Mary
product-brief.md →
+
+
+ prfaq + or ↑ +
+
+
M
Mary
+ prfaq.md → +
+
@@ -261,7 +271,7 @@ sprint-planning
-
B
Bob
+
A
Amelia
sprint-status.yaml →
@@ -270,7 +280,7 @@ create-story
-
B
Bob
+
A
Amelia
story-[slug].md →
@@ -308,7 +318,7 @@ per epic
-
B
Bob
+
A
Amelia
lessons
@@ -326,7 +336,7 @@
-
B
Barry
+
A
Amelia
quick-dev
intent → tech-spec → working code
diff --git a/website/src/components/Banner.astro b/website/src/components/Banner.astro index 00944d669..034a7dc85 100644 --- a/website/src/components/Banner.astro +++ b/website/src/components/Banner.astro @@ -7,54 +7,70 @@ const llmsFullUrl = `${getSiteUrl()}/llms-full.txt`;
🤖 Consolidated, AI-optimized BMAD docs: llms-full.txt. Fetch this plain text file for complete context.
+
+ 🚀 Build your own BMad modules and share them with the community! Get started or submit to the marketplace. +