bmalph 2.2.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +162 -48
  2. package/dist/cli.js +14 -0
  3. package/dist/commands/doctor.d.ts +14 -2
  4. package/dist/commands/doctor.js +105 -41
  5. package/dist/commands/implement.d.ts +6 -0
  6. package/dist/commands/implement.js +82 -0
  7. package/dist/commands/init.d.ts +1 -0
  8. package/dist/commands/init.js +74 -7
  9. package/dist/commands/reset.d.ts +7 -0
  10. package/dist/commands/reset.js +81 -0
  11. package/dist/commands/status.js +86 -10
  12. package/dist/commands/upgrade.js +8 -5
  13. package/dist/installer.d.ts +15 -4
  14. package/dist/installer.js +190 -101
  15. package/dist/platform/aider.d.ts +2 -0
  16. package/dist/platform/aider.js +71 -0
  17. package/dist/platform/claude-code.d.ts +2 -0
  18. package/dist/platform/claude-code.js +87 -0
  19. package/dist/platform/codex.d.ts +2 -0
  20. package/dist/platform/codex.js +67 -0
  21. package/dist/platform/copilot.d.ts +2 -0
  22. package/dist/platform/copilot.js +71 -0
  23. package/dist/platform/cursor.d.ts +2 -0
  24. package/dist/platform/cursor.js +71 -0
  25. package/dist/platform/detect.d.ts +7 -0
  26. package/dist/platform/detect.js +23 -0
  27. package/dist/platform/index.d.ts +4 -0
  28. package/dist/platform/index.js +3 -0
  29. package/dist/platform/registry.d.ts +4 -0
  30. package/dist/platform/registry.js +27 -0
  31. package/dist/platform/resolve.d.ts +8 -0
  32. package/dist/platform/resolve.js +24 -0
  33. package/dist/platform/types.d.ts +41 -0
  34. package/dist/platform/types.js +7 -0
  35. package/dist/platform/windsurf.d.ts +2 -0
  36. package/dist/platform/windsurf.js +71 -0
  37. package/dist/reset.d.ts +18 -0
  38. package/dist/reset.js +181 -0
  39. package/dist/transition/artifact-scan.d.ts +27 -0
  40. package/dist/transition/artifact-scan.js +91 -0
  41. package/dist/transition/artifacts.d.ts +1 -0
  42. package/dist/transition/artifacts.js +2 -1
  43. package/dist/transition/context.js +34 -0
  44. package/dist/transition/fix-plan.d.ts +8 -2
  45. package/dist/transition/fix-plan.js +33 -7
  46. package/dist/transition/orchestration.d.ts +2 -2
  47. package/dist/transition/orchestration.js +120 -41
  48. package/dist/transition/preflight.d.ts +6 -0
  49. package/dist/transition/preflight.js +154 -0
  50. package/dist/transition/specs-changelog.js +4 -1
  51. package/dist/transition/specs-index.d.ts +1 -1
  52. package/dist/transition/specs-index.js +24 -1
  53. package/dist/transition/types.d.ts +23 -1
  54. package/dist/utils/config.d.ts +2 -0
  55. package/dist/utils/dryrun.d.ts +1 -1
  56. package/dist/utils/dryrun.js +22 -0
  57. package/dist/utils/validate.js +18 -2
  58. package/package.json +1 -1
  59. package/ralph/drivers/claude-code.sh +118 -0
  60. package/ralph/drivers/codex.sh +81 -0
  61. package/ralph/ralph_import.sh +11 -0
  62. package/ralph/ralph_loop.sh +52 -64
  63. package/ralph/templates/ralphrc.template +7 -0
  64. package/slash-commands/bmalph-doctor.md +16 -0
  65. package/slash-commands/bmalph-implement.md +18 -141
  66. package/slash-commands/bmalph-status.md +15 -0
  67. package/slash-commands/bmalph-upgrade.md +15 -0
package/README.md CHANGED
@@ -25,13 +25,32 @@ bmalph provides:
25
25
  - `bmalph init` — Install both systems
26
26
  - `bmalph upgrade` — Update to latest versions
27
27
  - `bmalph doctor` — Check installation health
28
- - `/bmalph-implement` — Transition from BMAD to Ralph
28
+ - `bmalph implement` — Transition from BMAD to Ralph
29
+
30
+ ## Supported Platforms
31
+
32
+ bmalph works with multiple AI coding assistants. Each platform gets BMAD planning (Phases 1-3). The Ralph autonomous loop (Phase 4) requires a CLI-based platform.
33
+
34
+ | Platform | ID | Tier | Instructions File | Commands |
35
+ | -------------- | ------------- | ----------------- | --------------------------------- | ----------------------------- |
36
+ | Claude Code | `claude-code` | full | `CLAUDE.md` | `.claude/commands/` directory |
37
+ | OpenAI Codex | `codex` | full | `AGENTS.md` | Inline in instructions file |
38
+ | Cursor | `cursor` | instructions-only | `.cursor/rules/bmad.mdc` | None |
39
+ | Windsurf | `windsurf` | instructions-only | `.windsurf/rules/bmad.md` | None |
40
+ | GitHub Copilot | `copilot` | instructions-only | `.github/copilot-instructions.md` | None |
41
+ | Aider | `aider` | instructions-only | `CONVENTIONS.md` | None |
42
+
43
+ **Tiers:**
44
+
45
+ - **full** — Phases 1-4. BMAD planning + Ralph autonomous implementation loop.
46
+ - **instructions-only** — Phases 1-3. BMAD planning only. Ralph is not available.
29
47
 
30
48
  ## Prerequisites
31
49
 
32
50
  - Node.js 20+
33
51
  - Bash (WSL or Git Bash on Windows)
34
- - Claude Code (`claude` in PATH) needed for Ralph loop
52
+ - A supported AI coding platform (see table above)
53
+ - For Ralph loop (Phase 4): Claude Code (`claude`) or Codex CLI (`codex`) in PATH
35
54
 
36
55
  ## Installation
37
56
 
@@ -44,9 +63,9 @@ npm install -g bmalph
44
63
  ```bash
45
64
  cd my-project
46
65
  bmalph init --name my-project
47
- # Use /bmalph slash command in Claude Code to navigate phases
48
- # ... work through BMAD phases 1-3 ...
49
- # Use /bmalph-implement to transition and start Ralph
66
+
67
+ # To target a specific platform, add --platform (e.g. codex, cursor, windsurf)
68
+ # Without --platform, bmalph auto-detects or prompts interactively
50
69
  ```
51
70
 
52
71
  ## Workflow
@@ -58,17 +77,27 @@ cd my-project
58
77
  bmalph init
59
78
  ```
60
79
 
80
+ **Platform resolution:** `--platform` flag > auto-detect from project markers > interactive prompt > default `claude-code`
81
+
61
82
  This installs:
62
83
 
63
84
  - `_bmad/` — BMAD agents and workflows
64
- - `.ralph/` — Ralph loop, libs, templates
65
- - `bmalph/` — State management (config.json)
66
- - Updates `CLAUDE.md` with BMAD workflow instructions
67
- - Installs slash commands in `.claude/commands/`
85
+ - `.ralph/` — Ralph loop, libs, templates (drivers for claude-code and codex only)
86
+ - `bmalph/` — State management (config.json, stores selected platform)
87
+ - Updates the platform's instructions file with BMAD workflow instructions (e.g. `CLAUDE.md`, `AGENTS.md`, `.cursor/rules/bmad.mdc`)
88
+ - Installs slash commands for supported platforms (Claude Code: `.claude/commands/` directory; Codex: inline in `AGENTS.md`; other platforms: commands not installed)
89
+
90
+ ### Migrating from standalone BMAD
91
+
92
+ If you already have BMAD installed (a `_bmad/` directory), `bmalph init` works as a migration path:
93
+
94
+ - `_bmad/` (framework files) will be replaced with the bmalph-managed version
95
+ - `_bmad-output/` (your planning artifacts: PRDs, architecture, stories) is not touched
96
+ - If you've customized framework files inside `_bmad/`, commit first so you can review changes with `git diff`
68
97
 
69
98
  ### Step 2: Plan with BMAD (Phases 1-3)
70
99
 
71
- Work interactively in Claude Code with BMAD agents. Use the `/bmalph` slash command to see your current phase, available commands, and advance phases.
100
+ Work interactively with BMAD agents in your AI coding assistant. On Claude Code, use the `/bmalph` slash command to see your current phase and available commands. On other platforms, ask the agent about BMAD phases or run `bmalph status` in terminal.
72
101
 
73
102
  | Phase | Agent | Commands |
74
103
  | ------------- | ---------------- | ------------------ |
@@ -124,7 +153,9 @@ Available in any phase for supporting tasks:
124
153
 
125
154
  ### Step 3: Implement with Ralph (Phase 4)
126
155
 
127
- Use the `/bmalph-implement` slash command in Claude Code.
156
+ > **Note:** Ralph is only available on **full** tier platforms (Claude Code, OpenAI Codex). Instructions-only platforms (Cursor, Windsurf, Copilot, Aider) support Phases 1-3 only.
157
+
158
+ Run `bmalph implement` from the terminal, or use the `/bmalph-implement` slash command in Claude Code.
128
159
 
129
160
  This transitions your BMAD artifacts into Ralph's format:
130
161
 
@@ -133,10 +164,14 @@ This transitions your BMAD artifacts into Ralph's format:
133
164
  3. Copies specs to `.ralph/specs/` with changelog tracking
134
165
  4. Instructs you to start the Ralph autonomous loop
135
166
 
136
- Then start Ralph:
167
+ Then start Ralph using the driver for your platform:
137
168
 
138
169
  ```bash
139
- bash .ralph/ralph_loop.sh
170
+ # Claude Code
171
+ bash .ralph/drivers/claude-code.sh
172
+
173
+ # OpenAI Codex
174
+ bash .ralph/drivers/codex.sh
140
175
  ```
141
176
 
142
177
  Ralph picks stories one by one, implements with TDD, and commits. The loop stops when all stories are done or the circuit breaker triggers.
@@ -146,12 +181,12 @@ Ralph picks stories one by one, implements with TDD, and commits. The loop stops
146
181
  bmalph supports iterative development cycles:
147
182
 
148
183
  ```
149
- BMAD (Epic 1) → /bmalph-implement → Ralph works on Epic 1
184
+ BMAD (Epic 1) → bmalph implement → Ralph works on Epic 1
150
185
 
151
- BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
186
+ BMAD (add Epic 2) → bmalph implement → Ralph sees changes + picks up Epic 2
152
187
  ```
153
188
 
154
- **Smart Merge**: When you run `/bmalph-implement` again after Ralph has made progress:
189
+ **Smart Merge**: When you run `bmalph implement` again after Ralph has made progress:
155
190
 
156
191
  - Completed stories (`[x]`) are preserved in the new fix_plan
157
192
  - New stories from BMAD are added as pending (`[ ]`)
@@ -167,6 +202,7 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
167
202
  | `bmalph doctor` | Check installation health |
168
203
  | `bmalph check-updates` | Check if bundled BMAD/Ralph versions are up to date |
169
204
  | `bmalph status` | Show current project status and phase |
205
+ | `bmalph implement` | Transition BMAD planning artifacts to Ralph format |
170
206
 
171
207
  ### Global options
172
208
 
@@ -181,10 +217,29 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
181
217
 
182
218
  ### init options
183
219
 
184
- | Flag | Description | Default |
185
- | -------------------------- | ------------------- | -------------- |
186
- | `-n, --name <name>` | Project name | directory name |
187
- | `-d, --description <desc>` | Project description | (prompted) |
220
+ | Flag | Description | Default |
221
+ | -------------------------- | ---------------------------------------------------------------------------------- | -------------- |
222
+ | `-n, --name <name>` | Project name | directory name |
223
+ | `-d, --description <desc>` | Project description | (prompted) |
224
+ | `--platform <id>` | Target platform (`claude-code`, `codex`, `cursor`, `windsurf`, `copilot`, `aider`) | auto-detect |
225
+
226
+ ### implement options
227
+
228
+ | Flag | Description |
229
+ | --------- | ------------------------------------- |
230
+ | `--force` | Override pre-flight validation errors |
231
+
232
+ ### check-updates options
233
+
234
+ | Flag | Description |
235
+ | -------- | -------------- |
236
+ | `--json` | Output as JSON |
237
+
238
+ ### status options
239
+
240
+ | Flag | Description |
241
+ | -------- | -------------- |
242
+ | `--json` | Output as JSON |
188
243
 
189
244
  ### upgrade options
190
245
 
@@ -195,7 +250,13 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
195
250
 
196
251
  ## Slash Commands
197
252
 
198
- bmalph installs 47 BMAD slash commands. Key commands:
253
+ bmalph installs 50 slash commands (45 BMAD + 5 bmalph). Command delivery varies by platform:
254
+
255
+ - **Claude Code** — installed as files in `.claude/commands/` (invoke with `/command-name`)
256
+ - **OpenAI Codex** — inlined in `AGENTS.md` (reference agents by name)
257
+ - **Cursor, Windsurf, Copilot, Aider** — not delivered as slash commands; use agents by name in chat
258
+
259
+ Key commands (Claude Code syntax):
199
260
 
200
261
  | Command | Description |
201
262
  | ----------------------- | ----------------------------------- |
@@ -218,7 +279,7 @@ For full list, run `/bmad-help` in Claude Code.
218
279
 
219
280
  ### Transition to Ralph
220
281
 
221
- Use `/bmalph-implement` to transition from BMAD planning to Ralph implementation.
282
+ Use `bmalph implement` (or `/bmalph-implement` in Claude Code) to transition from BMAD planning to Ralph implementation.
222
283
 
223
284
  ## Project Structure (after init)
224
285
 
@@ -226,44 +287,64 @@ Use `/bmalph-implement` to transition from BMAD planning to Ralph implementation
226
287
  project/
227
288
  ├── _bmad/ # BMAD agents, workflows, core
228
289
  │ ├── _config/ # Generated configuration
229
- │ │ └── config.yaml # Platform config
290
+ │ │ ├── config.yaml # Platform config
291
+ │ │ ├── task-manifest.csv # Combined task manifest
292
+ │ │ ├── workflow-manifest.csv # Combined workflow manifest
293
+ │ │ └── bmad-help.csv # Combined help manifest
230
294
  │ ├── core/
231
295
  │ │ ├── agents/ # Master agent
232
296
  │ │ ├── tasks/ # Workflow tasks
233
- │ │ └── workflows/ # Brainstorming, party-mode, etc.
297
+ │ │ ├── workflows/ # Brainstorming, party-mode, etc.
298
+ │ │ ├── module.yaml # Core module metadata
299
+ │ │ └── module-help.csv # Core module help entries
234
300
  │ └── bmm/
235
301
  │ ├── agents/ # Analyst, PM, Architect, Dev, QA, etc.
302
+ │ ├── data/ # Templates (project-context-template.md)
236
303
  │ ├── workflows/ # Phase 1-4 workflows
237
- └── teams/ # Agent team definitions
304
+ ├── teams/ # Agent team definitions
305
+ │ ├── module.yaml # BMM module metadata
306
+ │ └── module-help.csv # BMM module help entries
238
307
  ├── _bmad-output/ # BMAD planning artifacts (generated)
239
308
  │ ├── planning-artifacts/ # PRD, architecture, stories
240
309
  │ ├── implementation-artifacts/ # Sprint plans (optional)
241
310
  │ └── brainstorming/ # Brainstorm sessions (optional)
242
- ├── .ralph/ # Ralph autonomous loop
311
+ ├── .ralph/ # Ralph autonomous loop (drivers for claude-code and codex only)
243
312
  │ ├── ralph_loop.sh # Main loop script
244
313
  │ ├── ralph_import.sh # Import requirements into Ralph
245
314
  │ ├── ralph_monitor.sh # Monitor loop progress
246
315
  │ ├── .ralphrc # Ralph configuration
247
316
  │ ├── RALPH-REFERENCE.md # Ralph usage reference
248
- │ ├── lib/ # Circuit breaker, response analyzer
317
+ │ ├── drivers/ # Platform driver scripts
318
+ │ │ ├── claude-code.sh # Claude Code driver (uses `claude`)
319
+ │ │ └── codex.sh # OpenAI Codex driver (uses `codex exec`)
320
+ │ ├── lib/ # Shell libraries
321
+ │ ├── docs/generated/ # Generated documentation
249
322
  │ ├── specs/ # Copied from _bmad-output during transition
250
323
  │ ├── logs/ # Loop execution logs
251
324
  │ ├── PROMPT.md # Iteration prompt template
252
- │ ├── PROJECT_CONTEXT.md # Extracted project context (after /bmalph-implement)
253
- │ ├── SPECS_CHANGELOG.md # Spec diff since last run (after /bmalph-implement)
325
+ │ ├── PROJECT_CONTEXT.md # Extracted project context (after bmalph implement)
326
+ │ ├── SPECS_CHANGELOG.md # Spec diff since last run (after bmalph implement)
327
+ │ ├── SPECS_INDEX.md # Prioritized spec file index (after bmalph implement)
254
328
  │ ├── @AGENT.md # Agent build instructions
255
- │ └── @fix_plan.md # Generated task list (after /bmalph-implement)
329
+ │ └── @fix_plan.md # Generated task list (after bmalph implement)
256
330
  ├── bmalph/ # State management
257
- │ ├── config.json # Project config (name, description)
331
+ │ ├── config.json # Project config (name, description, platform)
258
332
  │ └── state/ # Phase tracking data
259
- ├── .claude/
260
- │ └── commands/ # Slash commands for Claude Code
261
- └── CLAUDE.md # Updated with BMAD instructions
333
+ ├── .claude/ # Claude Code specific
334
+ │ └── commands/ # Slash commands (claude-code only)
335
+ └── <instructions file> # Varies by platform (see Supported Platforms)
262
336
  ```
263
337
 
338
+ The instructions file and command directory depend on the configured platform. See the [Supported Platforms](#supported-platforms) table for details.
339
+
264
340
  ## How Ralph Works
265
341
 
266
- Ralph is a bash loop that spawns fresh Claude Code instances:
342
+ Ralph is a bash loop that spawns fresh AI coding sessions using a **platform driver** matching the configured platform:
343
+
344
+ - **Claude Code driver** — invokes `claude` with `--allowedTools` and session resume
345
+ - **Codex driver** — invokes `codex exec` with `--sandbox workspace-write`
346
+
347
+ Each iteration:
267
348
 
268
349
  1. Pick the next unchecked story from `@fix_plan.md`
269
350
  2. Implement with TDD (tests first, then code)
@@ -304,8 +385,8 @@ wsl --install
304
385
  If you get permission errors:
305
386
 
306
387
  ```bash
307
- # Unix/Mac: Make ralph_loop.sh executable
308
- chmod +x .ralph/ralph_loop.sh
388
+ # Unix/Mac: Make driver scripts executable
389
+ chmod +x .ralph/drivers/*.sh
309
390
 
310
391
  # Check file ownership
311
392
  ls -la .ralph/
@@ -313,12 +394,14 @@ ls -la .ralph/
313
394
 
314
395
  ### Common Issues
315
396
 
316
- | Scenario | Solution |
317
- | ---------------------------- | --------------------------------------------------------- |
318
- | Commands fail before init | Run `bmalph init` first |
319
- | Transition finds no stories | Create stories in Phase 3 with `/create-epics-stories` |
320
- | Ralph stops mid-loop | Circuit breaker detected stagnation. Check `.ralph/logs/` |
321
- | Doctor reports version drift | Run `bmalph upgrade` to update bundled assets |
397
+ | Scenario | Solution |
398
+ | ----------------------------- | -------------------------------------------------------------- |
399
+ | Commands fail before init | Run `bmalph init` first |
400
+ | Transition finds no stories | Create stories in Phase 3 with `/create-epics-stories` |
401
+ | Ralph stops mid-loop | Circuit breaker detected stagnation. Check `.ralph/logs/` |
402
+ | Doctor reports version drift | Run `bmalph upgrade` to update bundled assets |
403
+ | Wrong platform detected | Re-run `bmalph init --platform <id>` with the correct platform |
404
+ | Ralph unavailable on platform | Ralph requires a full tier platform (claude-code or codex) |
322
405
 
323
406
  ### Reset Installation
324
407
 
@@ -326,8 +409,16 @@ If something goes wrong, you can manually reset:
326
409
 
327
410
  ```bash
328
411
  # Remove bmalph directories (preserves your project code)
329
- rm -rf _bmad .ralph bmalph .claude/commands/
330
- # Note: manually remove the bmalph section from CLAUDE.md and .gitignore entries
412
+ rm -rf _bmad .ralph bmalph
413
+
414
+ # Also remove platform-specific files:
415
+ # Claude Code: rm -rf .claude/commands/ and remove bmalph section from CLAUDE.md
416
+ # Codex: remove bmalph sections from AGENTS.md
417
+ # Cursor: rm .cursor/rules/bmad.mdc
418
+ # Windsurf: rm .windsurf/rules/bmad.md
419
+ # Copilot: remove bmalph sections from .github/copilot-instructions.md
420
+ # Aider: remove bmalph sections from CONVENTIONS.md
421
+ # See the Supported Platforms table for your platform's files.
331
422
 
332
423
  # Reinitialize
333
424
  bmalph init
@@ -338,12 +429,17 @@ bmalph init
338
429
  ### Initialize a new project
339
430
 
340
431
  ```bash
341
- # Interactive mode (prompts for name/description)
432
+ # Interactive mode (prompts for name/description, auto-detects platform)
342
433
  bmalph init
343
434
 
344
435
  # Non-interactive mode
345
436
  bmalph init --name my-app --description "My awesome app"
346
437
 
438
+ # Specify platform explicitly
439
+ bmalph init --name my-app --platform codex
440
+ bmalph init --name my-app --platform cursor
441
+ bmalph init --name my-app --platform windsurf
442
+
347
443
  # Preview what would be created
348
444
  bmalph init --dry-run
349
445
  ```
@@ -370,6 +466,8 @@ bmalph upgrade --dry-run
370
466
 
371
467
  ### After init: Next steps
372
468
 
469
+ **Claude Code:**
470
+
373
471
  ```bash
374
472
  # 1. Open Claude Code in your project
375
473
  claude
@@ -383,10 +481,26 @@ claude
383
481
  # Phase 3: /architect → create architecture and stories
384
482
 
385
483
  # 4. Transition to Ralph
386
- # Use /bmalph-implement to generate @fix_plan.md
484
+ # Run: bmalph implement
387
485
 
388
486
  # 5. Start autonomous implementation
389
- bash .ralph/ralph_loop.sh
487
+ bash .ralph/drivers/claude-code.sh
488
+ ```
489
+
490
+ **Other platforms:**
491
+
492
+ ```bash
493
+ # 1. Open your project in your AI coding assistant
494
+
495
+ # 2. Ask the agent about BMAD phases to start planning
496
+ # Or check status from terminal: bmalph status
497
+
498
+ # 3. Reference BMAD agents by name (analyst, pm, architect)
499
+ # Follow phases: Analysis → Planning → Solutioning
500
+
501
+ # 4. For full tier platforms (Codex), transition to Ralph:
502
+ # Run: bmalph implement
503
+ bash .ralph/drivers/codex.sh
390
504
  ```
391
505
 
392
506
  ## Contributing
package/dist/cli.js CHANGED
@@ -6,6 +6,8 @@ import { upgradeCommand } from "./commands/upgrade.js";
6
6
  import { doctorCommand } from "./commands/doctor.js";
7
7
  import { checkUpdatesCommand } from "./commands/check-updates.js";
8
8
  import { statusCommand } from "./commands/status.js";
9
+ import { implementCommand } from "./commands/implement.js";
10
+ import { resetCommand } from "./commands/reset.js";
9
11
  import { setVerbose, setQuiet } from "./utils/logger.js";
10
12
  import { getPackageVersion } from "./installer.js";
11
13
  import { isEnoent } from "./utils/errors.js";
@@ -55,6 +57,7 @@ program
55
57
  .description("Initialize bmalph in the current project")
56
58
  .option("-n, --name <name>", "Project name")
57
59
  .option("-d, --description <desc>", "Project description")
60
+ .option("--platform <id>", "Target platform (claude-code, codex, cursor, windsurf, copilot, aider)")
58
61
  .option("--dry-run", "Preview changes without writing files")
59
62
  .action(async (opts) => initCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
60
63
  program
@@ -78,4 +81,15 @@ program
78
81
  .description("Show current project status and phase")
79
82
  .option("--json", "Output as JSON")
80
83
  .action(async (opts) => statusCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
84
+ program
85
+ .command("implement")
86
+ .description("Transition BMAD planning artifacts to Ralph implementation format")
87
+ .option("--force", "Override pre-flight validation errors")
88
+ .action(async (opts) => implementCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
89
+ program
90
+ .command("reset")
91
+ .description("Remove all bmalph files from the project")
92
+ .option("--dry-run", "Preview changes without removing files")
93
+ .option("--force", "Skip confirmation prompt")
94
+ .action(async (opts) => resetCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
81
95
  void program.parseAsync();
@@ -1,3 +1,4 @@
1
+ import type { Platform } from "../platform/types.js";
1
2
  /**
2
3
  * Result of a single doctor check.
3
4
  */
@@ -32,8 +33,19 @@ interface DoctorResult {
32
33
  }
33
34
  export declare function runDoctor(options: DoctorOptions): Promise<DoctorResult>;
34
35
  /**
35
- * Registry of all doctor checks in execution order.
36
- * Each check has a unique ID and a run function that takes a project directory.
36
+ * Build the full check registry for a given platform.
37
+ * Core checks + platform doctor checks + trailing checks.
38
+ */
39
+ export declare function buildCheckRegistry(platform: Platform): CheckDefinition[];
40
+ /**
41
+ * Static registry for backward compatibility with existing tests.
42
+ * Uses claude-code platform checks (slash-command + claude-md).
43
+ *
44
+ * Note: The check ids here ("slash-command", "claude-md") intentionally differ
45
+ * from the live buildCheckRegistry path which uses platform-provided ids
46
+ * ("instructions-file"). This is for test backward compatibility only.
47
+ *
48
+ * @deprecated Use `buildCheckRegistry(platform)` for platform-aware checks.
37
49
  */
38
50
  export declare const CHECK_REGISTRY: CheckDefinition[];
39
51
  export {};
@@ -9,6 +9,7 @@ import { checkUpstream, getSkipReason } from "../utils/github.js";
9
9
  import { isEnoent, formatError, withErrorHandling } from "../utils/errors.js";
10
10
  import { validateCircuitBreakerState, validateRalphSession, validateRalphApiStatus, } from "../utils/validate.js";
11
11
  import { SESSION_AGE_WARNING_MS, API_USAGE_WARNING_PERCENT, CONFIG_FILE, RALPH_STATUS_FILE, } from "../utils/constants.js";
12
+ import { resolveProjectPlatform } from "../platform/resolve.js";
12
13
  export async function doctorCommand(options) {
13
14
  await withErrorHandling(async () => {
14
15
  const { failed } = await runDoctor(options);
@@ -19,8 +20,12 @@ export async function doctorCommand(options) {
19
20
  }
20
21
  export async function runDoctor(options) {
21
22
  const projectDir = options.projectDir;
22
- // Run all checks from the registry
23
- const results = await Promise.all(CHECK_REGISTRY.map((check) => check.run(projectDir)));
23
+ // Resolve platform for this project
24
+ const platform = await resolveProjectPlatform(projectDir);
25
+ // Build the check list: core checks + platform-specific checks
26
+ const checks = buildCheckRegistry(platform);
27
+ // Run all checks
28
+ const results = await Promise.all(checks.map((check) => check.run(projectDir)));
24
29
  // Output
25
30
  const passed = results.filter((r) => r.passed).length;
26
31
  const failed = results.filter((r) => !r.passed).length;
@@ -59,10 +64,10 @@ export async function runDoctor(options) {
59
64
  }
60
65
  return { passed, failed };
61
66
  }
62
- async function checkBashAvailable() {
67
+ async function checkCommandAvailable(command) {
63
68
  const { execSync } = await import("child_process");
64
69
  try {
65
- const cmd = process.platform === "win32" ? "where bash" : "which bash";
70
+ const cmd = process.platform === "win32" ? `where ${command}` : `which ${command}`;
66
71
  execSync(cmd, { stdio: "ignore" });
67
72
  return true;
68
73
  }
@@ -71,7 +76,7 @@ async function checkBashAvailable() {
71
76
  }
72
77
  }
73
78
  // =============================================================================
74
- // Check functions - each conforms to CheckFunction signature
79
+ // Core check functions - platform-independent
75
80
  // =============================================================================
76
81
  async function checkNodeVersion(_projectDir) {
77
82
  const major = parseInt(process.versions.node.split(".")[0]);
@@ -83,18 +88,33 @@ async function checkNodeVersion(_projectDir) {
83
88
  };
84
89
  }
85
90
  async function checkBash(_projectDir) {
86
- const bashAvailable = await checkBashAvailable();
91
+ const available = await checkCommandAvailable("bash");
87
92
  return {
88
93
  label: "bash available",
89
- passed: bashAvailable,
90
- detail: bashAvailable ? undefined : "bash not found in PATH",
91
- hint: bashAvailable
94
+ passed: available,
95
+ detail: available ? undefined : "bash not found in PATH",
96
+ hint: available
92
97
  ? undefined
93
98
  : process.platform === "win32"
94
99
  ? "Install Git Bash or WSL: https://git-scm.com/downloads"
95
100
  : "Install bash via your package manager (apt, brew, etc.)",
96
101
  };
97
102
  }
103
+ async function checkJq(_projectDir) {
104
+ const available = await checkCommandAvailable("jq");
105
+ return {
106
+ label: "jq available",
107
+ passed: available,
108
+ detail: available ? undefined : "jq not found in PATH",
109
+ hint: available
110
+ ? undefined
111
+ : process.platform === "win32"
112
+ ? "Install jq: choco install jq (or: winget install jqlang.jq)"
113
+ : process.platform === "darwin"
114
+ ? "Install jq: brew install jq"
115
+ : "Install jq: sudo apt-get install jq",
116
+ };
117
+ }
98
118
  async function checkBmadDir(projectDir) {
99
119
  return checkDir(join(projectDir, "_bmad"), "_bmad/ directory present", "Run: bmalph init");
100
120
  }
@@ -104,9 +124,6 @@ async function checkRalphLoop(projectDir) {
104
124
  async function checkRalphLib(projectDir) {
105
125
  return checkDir(join(projectDir, ".ralph/lib"), ".ralph/lib/ directory present", "Run: bmalph upgrade");
106
126
  }
107
- async function checkSlashCommand(projectDir) {
108
- return checkFileExists(join(projectDir, ".claude/commands/bmalph.md"), ".claude/commands/bmalph.md present", "Run: bmalph init");
109
- }
110
127
  async function checkConfig(projectDir) {
111
128
  const label = "bmalph/config.json exists and valid";
112
129
  const hint = "Run: bmalph init";
@@ -135,12 +152,6 @@ async function checkDir(dirPath, label, hint) {
135
152
  return { label, passed: false, detail: `error: ${formatError(err)}`, hint };
136
153
  }
137
154
  }
138
- async function checkFileExists(filePath, label, hint) {
139
- if (await exists(filePath)) {
140
- return { label, passed: true };
141
- }
142
- return { label, passed: false, detail: "not found", hint };
143
- }
144
155
  async function checkFileHasContent(filePath, label, hint) {
145
156
  try {
146
157
  const content = await readFile(filePath, "utf-8");
@@ -153,23 +164,6 @@ async function checkFileHasContent(filePath, label, hint) {
153
164
  return { label, passed: false, detail: `error: ${formatError(err)}`, hint };
154
165
  }
155
166
  }
156
- async function checkClaudeMd(projectDir) {
157
- const label = "CLAUDE.md contains BMAD snippet";
158
- const hint = "Run: bmalph init";
159
- try {
160
- const content = await readFile(join(projectDir, "CLAUDE.md"), "utf-8");
161
- if (content.includes("BMAD-METHOD Integration")) {
162
- return { label, passed: true };
163
- }
164
- return { label, passed: false, detail: "missing BMAD-METHOD Integration section", hint };
165
- }
166
- catch (err) {
167
- if (isEnoent(err)) {
168
- return { label, passed: false, detail: "CLAUDE.md not found", hint };
169
- }
170
- return { label, passed: false, detail: `error: ${formatError(err)}`, hint };
171
- }
172
- }
173
167
  async function checkGitignore(projectDir) {
174
168
  const label = ".gitignore has required entries";
175
169
  const required = [".ralph/logs/", "_bmad-output/"];
@@ -412,21 +406,24 @@ async function checkUpstreamGitHubStatus(_projectDir) {
412
406
  }
413
407
  }
414
408
  // =============================================================================
415
- // Check Registry - defines all checks in execution order
409
+ // Check Registry - core checks + platform-specific checks
416
410
  // =============================================================================
417
411
  /**
418
- * Registry of all doctor checks in execution order.
419
- * Each check has a unique ID and a run function that takes a project directory.
412
+ * Core checks that apply to every platform.
420
413
  */
421
- export const CHECK_REGISTRY = [
414
+ const CORE_CHECKS = [
422
415
  { id: "node-version", run: checkNodeVersion },
423
416
  { id: "bash-available", run: checkBash },
417
+ { id: "jq-available", run: checkJq },
424
418
  { id: "config-valid", run: checkConfig },
425
419
  { id: "bmad-dir", run: checkBmadDir },
426
420
  { id: "ralph-loop", run: checkRalphLoop },
427
421
  { id: "ralph-lib", run: checkRalphLib },
428
- { id: "slash-command", run: checkSlashCommand },
429
- { id: "claude-md", run: checkClaudeMd },
422
+ ];
423
+ /**
424
+ * Checks that run after platform-specific checks.
425
+ */
426
+ const TRAILING_CHECKS = [
430
427
  { id: "gitignore", run: checkGitignore },
431
428
  { id: "version-marker", run: checkVersionMarker },
432
429
  { id: "upstream-versions", run: checkUpstreamVersions },
@@ -435,3 +432,70 @@ export const CHECK_REGISTRY = [
435
432
  { id: "api-calls", run: checkApiCalls },
436
433
  { id: "upstream-github", run: checkUpstreamGitHubStatus },
437
434
  ];
435
+ /**
436
+ * Build the full check registry for a given platform.
437
+ * Core checks + platform doctor checks + trailing checks.
438
+ */
439
+ export function buildCheckRegistry(platform) {
440
+ const platformChecks = platform.getDoctorChecks().map((pc) => ({
441
+ id: pc.id,
442
+ run: async (projectDir) => {
443
+ const result = await pc.check(projectDir);
444
+ return {
445
+ label: pc.label,
446
+ passed: result.passed,
447
+ detail: result.detail,
448
+ hint: result.hint,
449
+ };
450
+ },
451
+ }));
452
+ return [...CORE_CHECKS, ...platformChecks, ...TRAILING_CHECKS];
453
+ }
454
+ /**
455
+ * Static registry for backward compatibility with existing tests.
456
+ * Uses claude-code platform checks (slash-command + claude-md).
457
+ *
458
+ * Note: The check ids here ("slash-command", "claude-md") intentionally differ
459
+ * from the live buildCheckRegistry path which uses platform-provided ids
460
+ * ("instructions-file"). This is for test backward compatibility only.
461
+ *
462
+ * @deprecated Use `buildCheckRegistry(platform)` for platform-aware checks.
463
+ */
464
+ export const CHECK_REGISTRY = (() => {
465
+ // Inline claude-code platform checks to avoid async import at module level
466
+ const slashCommandCheck = {
467
+ id: "slash-command",
468
+ run: async (projectDir) => {
469
+ if (await exists(join(projectDir, ".claude/commands/bmalph.md"))) {
470
+ return { label: ".claude/commands/bmalph.md present", passed: true };
471
+ }
472
+ return {
473
+ label: ".claude/commands/bmalph.md present",
474
+ passed: false,
475
+ detail: "not found",
476
+ hint: "Run: bmalph init",
477
+ };
478
+ },
479
+ };
480
+ const claudeMdCheck = {
481
+ id: "claude-md",
482
+ run: async (projectDir) => {
483
+ const label = "CLAUDE.md contains BMAD snippet";
484
+ const hint = "Run: bmalph init";
485
+ try {
486
+ const content = await readFile(join(projectDir, "CLAUDE.md"), "utf-8");
487
+ if (content.includes("BMAD-METHOD Integration")) {
488
+ return { label, passed: true };
489
+ }
490
+ return { label, passed: false, detail: "missing BMAD-METHOD Integration section", hint };
491
+ }
492
+ catch (err) {
493
+ if (isEnoent(err)) {
494
+ return { label, passed: false, detail: "CLAUDE.md not found", hint };
495
+ }
496
+ return { label, passed: false, detail: `error: ${formatError(err)}`, hint };
497
+ }
498
+ },
499
+ };
500
+ return [...CORE_CHECKS, slashCommandCheck, claudeMdCheck, ...TRAILING_CHECKS];
501
+ })();
@@ -0,0 +1,6 @@
1
+ interface ImplementOptions {
2
+ force?: boolean;
3
+ projectDir: string;
4
+ }
5
+ export declare function implementCommand(options: ImplementOptions): Promise<void>;
6
+ export {};