bmad-method 6.10.1-next.47 → 6.10.1-next.48

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