bmalph 2.3.0 → 2.5.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.
- package/README.md +105 -38
- package/dist/cli.js +19 -0
- package/dist/commands/doctor.d.ts +0 -11
- package/dist/commands/doctor.js +22 -55
- package/dist/commands/implement.d.ts +6 -0
- package/dist/commands/implement.js +82 -0
- package/dist/commands/init.js +4 -2
- package/dist/commands/reset.d.ts +7 -0
- package/dist/commands/reset.js +81 -0
- package/dist/commands/status.js +100 -11
- package/dist/commands/watch.d.ts +6 -0
- package/dist/commands/watch.js +19 -0
- package/dist/installer.d.ts +0 -6
- package/dist/installer.js +0 -10
- package/dist/platform/claude-code.js +0 -1
- package/dist/reset.d.ts +18 -0
- package/dist/reset.js +181 -0
- package/dist/transition/artifact-scan.d.ts +27 -0
- package/dist/transition/artifact-scan.js +91 -0
- package/dist/transition/artifacts.d.ts +0 -1
- package/dist/transition/artifacts.js +0 -26
- package/dist/transition/context.js +34 -0
- package/dist/transition/fix-plan.d.ts +8 -2
- package/dist/transition/fix-plan.js +33 -7
- package/dist/transition/index.d.ts +1 -1
- package/dist/transition/index.js +1 -1
- package/dist/transition/orchestration.d.ts +2 -2
- package/dist/transition/orchestration.js +120 -41
- package/dist/transition/preflight.d.ts +6 -0
- package/dist/transition/preflight.js +154 -0
- package/dist/transition/specs-index.d.ts +1 -1
- package/dist/transition/specs-index.js +24 -1
- package/dist/transition/types.d.ts +23 -1
- package/dist/utils/dryrun.d.ts +1 -1
- package/dist/utils/dryrun.js +22 -0
- package/dist/utils/state.d.ts +0 -2
- package/dist/utils/validate.js +3 -2
- package/dist/watch/dashboard.d.ts +4 -0
- package/dist/watch/dashboard.js +60 -0
- package/dist/watch/file-watcher.d.ts +9 -0
- package/dist/watch/file-watcher.js +27 -0
- package/dist/watch/renderer.d.ts +16 -0
- package/dist/watch/renderer.js +241 -0
- package/dist/watch/state-reader.d.ts +9 -0
- package/dist/watch/state-reader.js +190 -0
- package/dist/watch/types.d.ts +55 -0
- package/dist/watch/types.js +1 -0
- package/package.json +9 -4
- package/ralph/lib/circuit_breaker.sh +86 -59
- package/ralph/lib/enable_core.sh +3 -6
- package/ralph/lib/response_analyzer.sh +5 -29
- package/ralph/lib/task_sources.sh +45 -11
- package/ralph/lib/wizard_utils.sh +9 -0
- package/ralph/ralph_import.sh +7 -2
- package/ralph/ralph_loop.sh +44 -34
- package/ralph/ralph_monitor.sh +4 -0
- package/slash-commands/bmalph-doctor.md +16 -0
- package/slash-commands/bmalph-implement.md +18 -141
- package/slash-commands/bmalph-status.md +15 -0
- package/slash-commands/bmalph-upgrade.md +15 -0
- package/slash-commands/bmalph-watch.md +20 -0
package/README.md
CHANGED
|
@@ -25,7 +25,11 @@ 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
|
-
-
|
|
28
|
+
- `bmalph implement` — Transition from BMAD to Ralph
|
|
29
|
+
- `bmalph check-updates` — Check for upstream updates
|
|
30
|
+
- `bmalph status` — Show project status and phase
|
|
31
|
+
- `bmalph reset` — Remove all bmalph files
|
|
32
|
+
- `bmalph watch` — Live Ralph loop dashboard
|
|
29
33
|
|
|
30
34
|
## Supported Platforms
|
|
31
35
|
|
|
@@ -155,7 +159,7 @@ Available in any phase for supporting tasks:
|
|
|
155
159
|
|
|
156
160
|
> **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
161
|
|
|
158
|
-
|
|
162
|
+
Run `bmalph implement` from the terminal, or use the `/bmalph-implement` slash command in Claude Code.
|
|
159
163
|
|
|
160
164
|
This transitions your BMAD artifacts into Ralph's format:
|
|
161
165
|
|
|
@@ -164,10 +168,14 @@ This transitions your BMAD artifacts into Ralph's format:
|
|
|
164
168
|
3. Copies specs to `.ralph/specs/` with changelog tracking
|
|
165
169
|
4. Instructs you to start the Ralph autonomous loop
|
|
166
170
|
|
|
167
|
-
Then start Ralph:
|
|
171
|
+
Then start Ralph using the driver for your platform:
|
|
168
172
|
|
|
169
173
|
```bash
|
|
170
|
-
|
|
174
|
+
# Claude Code
|
|
175
|
+
bash .ralph/drivers/claude-code.sh
|
|
176
|
+
|
|
177
|
+
# OpenAI Codex
|
|
178
|
+
bash .ralph/drivers/codex.sh
|
|
171
179
|
```
|
|
172
180
|
|
|
173
181
|
Ralph picks stories one by one, implements with TDD, and commits. The loop stops when all stories are done or the circuit breaker triggers.
|
|
@@ -177,12 +185,12 @@ Ralph picks stories one by one, implements with TDD, and commits. The loop stops
|
|
|
177
185
|
bmalph supports iterative development cycles:
|
|
178
186
|
|
|
179
187
|
```
|
|
180
|
-
BMAD (Epic 1) →
|
|
188
|
+
BMAD (Epic 1) → bmalph implement → Ralph works on Epic 1
|
|
181
189
|
↓
|
|
182
|
-
BMAD (add Epic 2) →
|
|
190
|
+
BMAD (add Epic 2) → bmalph implement → Ralph sees changes + picks up Epic 2
|
|
183
191
|
```
|
|
184
192
|
|
|
185
|
-
**Smart Merge**: When you run
|
|
193
|
+
**Smart Merge**: When you run `bmalph implement` again after Ralph has made progress:
|
|
186
194
|
|
|
187
195
|
- Completed stories (`[x]`) are preserved in the new fix_plan
|
|
188
196
|
- New stories from BMAD are added as pending (`[ ]`)
|
|
@@ -198,6 +206,9 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
|
|
|
198
206
|
| `bmalph doctor` | Check installation health |
|
|
199
207
|
| `bmalph check-updates` | Check if bundled BMAD/Ralph versions are up to date |
|
|
200
208
|
| `bmalph status` | Show current project status and phase |
|
|
209
|
+
| `bmalph implement` | Transition BMAD planning artifacts to Ralph format |
|
|
210
|
+
| `bmalph reset` | Remove all bmalph files from the project |
|
|
211
|
+
| `bmalph watch` | Live dashboard showing Ralph loop status |
|
|
201
212
|
|
|
202
213
|
### Global options
|
|
203
214
|
|
|
@@ -217,6 +228,31 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
|
|
|
217
228
|
| `-n, --name <name>` | Project name | directory name |
|
|
218
229
|
| `-d, --description <desc>` | Project description | (prompted) |
|
|
219
230
|
| `--platform <id>` | Target platform (`claude-code`, `codex`, `cursor`, `windsurf`, `copilot`, `aider`) | auto-detect |
|
|
231
|
+
| `--dry-run` | Preview changes without writing files | |
|
|
232
|
+
|
|
233
|
+
### implement options
|
|
234
|
+
|
|
235
|
+
| Flag | Description |
|
|
236
|
+
| --------- | ------------------------------------- |
|
|
237
|
+
| `--force` | Override pre-flight validation errors |
|
|
238
|
+
|
|
239
|
+
### check-updates options
|
|
240
|
+
|
|
241
|
+
| Flag | Description |
|
|
242
|
+
| -------- | -------------- |
|
|
243
|
+
| `--json` | Output as JSON |
|
|
244
|
+
|
|
245
|
+
### doctor options
|
|
246
|
+
|
|
247
|
+
| Flag | Description |
|
|
248
|
+
| -------- | -------------- |
|
|
249
|
+
| `--json` | Output as JSON |
|
|
250
|
+
|
|
251
|
+
### status options
|
|
252
|
+
|
|
253
|
+
| Flag | Description |
|
|
254
|
+
| -------- | -------------- |
|
|
255
|
+
| `--json` | Output as JSON |
|
|
220
256
|
|
|
221
257
|
### upgrade options
|
|
222
258
|
|
|
@@ -225,9 +261,22 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
|
|
|
225
261
|
| `--force` | Skip confirmation prompts |
|
|
226
262
|
| `--dry-run` | Preview changes |
|
|
227
263
|
|
|
264
|
+
### reset options
|
|
265
|
+
|
|
266
|
+
| Flag | Description |
|
|
267
|
+
| ----------- | ------------------------ |
|
|
268
|
+
| `--dry-run` | Preview changes |
|
|
269
|
+
| `--force` | Skip confirmation prompt |
|
|
270
|
+
|
|
271
|
+
### watch options
|
|
272
|
+
|
|
273
|
+
| Flag | Description |
|
|
274
|
+
| ----------------- | ------------------------------------------------ |
|
|
275
|
+
| `--interval <ms>` | Refresh interval in milliseconds (default: 2000) |
|
|
276
|
+
|
|
228
277
|
## Slash Commands
|
|
229
278
|
|
|
230
|
-
bmalph installs
|
|
279
|
+
bmalph installs 51 slash commands (45 BMAD + 6 bmalph). Command delivery varies by platform:
|
|
231
280
|
|
|
232
281
|
- **Claude Code** — installed as files in `.claude/commands/` (invoke with `/command-name`)
|
|
233
282
|
- **OpenAI Codex** — inlined in `AGENTS.md` (reference agents by name)
|
|
@@ -256,7 +305,7 @@ For full list, run `/bmad-help` in Claude Code.
|
|
|
256
305
|
|
|
257
306
|
### Transition to Ralph
|
|
258
307
|
|
|
259
|
-
Use `/bmalph-implement` to transition from BMAD planning to Ralph implementation.
|
|
308
|
+
Use `bmalph implement` (or `/bmalph-implement` in Claude Code) to transition from BMAD planning to Ralph implementation.
|
|
260
309
|
|
|
261
310
|
## Project Structure (after init)
|
|
262
311
|
|
|
@@ -264,15 +313,23 @@ Use `/bmalph-implement` to transition from BMAD planning to Ralph implementation
|
|
|
264
313
|
project/
|
|
265
314
|
├── _bmad/ # BMAD agents, workflows, core
|
|
266
315
|
│ ├── _config/ # Generated configuration
|
|
267
|
-
│ │
|
|
316
|
+
│ │ ├── config.yaml # Platform config
|
|
317
|
+
│ │ ├── task-manifest.csv # Combined task manifest
|
|
318
|
+
│ │ ├── workflow-manifest.csv # Combined workflow manifest
|
|
319
|
+
│ │ └── bmad-help.csv # Combined help manifest
|
|
268
320
|
│ ├── core/
|
|
269
321
|
│ │ ├── agents/ # Master agent
|
|
270
322
|
│ │ ├── tasks/ # Workflow tasks
|
|
271
|
-
│ │
|
|
323
|
+
│ │ ├── workflows/ # Brainstorming, party-mode, etc.
|
|
324
|
+
│ │ ├── module.yaml # Core module metadata
|
|
325
|
+
│ │ └── module-help.csv # Core module help entries
|
|
272
326
|
│ └── bmm/
|
|
273
327
|
│ ├── agents/ # Analyst, PM, Architect, Dev, QA, etc.
|
|
328
|
+
│ ├── data/ # Templates (project-context-template.md)
|
|
274
329
|
│ ├── workflows/ # Phase 1-4 workflows
|
|
275
|
-
│
|
|
330
|
+
│ ├── teams/ # Agent team definitions
|
|
331
|
+
│ ├── module.yaml # BMM module metadata
|
|
332
|
+
│ └── module-help.csv # BMM module help entries
|
|
276
333
|
├── _bmad-output/ # BMAD planning artifacts (generated)
|
|
277
334
|
│ ├── planning-artifacts/ # PRD, architecture, stories
|
|
278
335
|
│ ├── implementation-artifacts/ # Sprint plans (optional)
|
|
@@ -286,14 +343,16 @@ project/
|
|
|
286
343
|
│ ├── drivers/ # Platform driver scripts
|
|
287
344
|
│ │ ├── claude-code.sh # Claude Code driver (uses `claude`)
|
|
288
345
|
│ │ └── codex.sh # OpenAI Codex driver (uses `codex exec`)
|
|
289
|
-
│ ├── lib/ #
|
|
346
|
+
│ ├── lib/ # Shell libraries
|
|
347
|
+
│ ├── docs/generated/ # Generated documentation
|
|
290
348
|
│ ├── specs/ # Copied from _bmad-output during transition
|
|
291
349
|
│ ├── logs/ # Loop execution logs
|
|
292
350
|
│ ├── PROMPT.md # Iteration prompt template
|
|
293
|
-
│ ├── PROJECT_CONTEXT.md # Extracted project context (after
|
|
294
|
-
│ ├── SPECS_CHANGELOG.md # Spec diff since last run (after
|
|
351
|
+
│ ├── PROJECT_CONTEXT.md # Extracted project context (after bmalph implement)
|
|
352
|
+
│ ├── SPECS_CHANGELOG.md # Spec diff since last run (after bmalph implement)
|
|
353
|
+
│ ├── SPECS_INDEX.md # Prioritized spec file index (after bmalph implement)
|
|
295
354
|
│ ├── @AGENT.md # Agent build instructions
|
|
296
|
-
│ └── @fix_plan.md # Generated task list (after
|
|
355
|
+
│ └── @fix_plan.md # Generated task list (after bmalph implement)
|
|
297
356
|
├── bmalph/ # State management
|
|
298
357
|
│ ├── config.json # Project config (name, description, platform)
|
|
299
358
|
│ └── state/ # Phase tracking data
|
|
@@ -352,8 +411,8 @@ wsl --install
|
|
|
352
411
|
If you get permission errors:
|
|
353
412
|
|
|
354
413
|
```bash
|
|
355
|
-
# Unix/Mac: Make
|
|
356
|
-
chmod +x .ralph/
|
|
414
|
+
# Unix/Mac: Make driver scripts executable
|
|
415
|
+
chmod +x .ralph/drivers/*.sh
|
|
357
416
|
|
|
358
417
|
# Check file ownership
|
|
359
418
|
ls -la .ralph/
|
|
@@ -372,25 +431,33 @@ ls -la .ralph/
|
|
|
372
431
|
|
|
373
432
|
### Reset Installation
|
|
374
433
|
|
|
375
|
-
|
|
434
|
+
The simplest way to remove all bmalph files:
|
|
376
435
|
|
|
377
436
|
```bash
|
|
378
|
-
|
|
379
|
-
rm -rf _bmad .ralph bmalph
|
|
380
|
-
|
|
381
|
-
# Also remove platform-specific files:
|
|
382
|
-
# Claude Code: rm -rf .claude/commands/ and remove bmalph section from CLAUDE.md
|
|
383
|
-
# Codex: remove bmalph sections from AGENTS.md
|
|
384
|
-
# Cursor: rm .cursor/rules/bmad.mdc
|
|
385
|
-
# Windsurf: rm .windsurf/rules/bmad.md
|
|
386
|
-
# Copilot: remove bmalph sections from .github/copilot-instructions.md
|
|
387
|
-
# Aider: remove bmalph sections from CONVENTIONS.md
|
|
388
|
-
# See the Supported Platforms table for your platform's files.
|
|
389
|
-
|
|
390
|
-
# Reinitialize
|
|
391
|
-
bmalph init
|
|
437
|
+
bmalph reset
|
|
392
438
|
```
|
|
393
439
|
|
|
440
|
+
Use `--dry-run` to preview what will be removed, or `--force` to skip confirmation.
|
|
441
|
+
|
|
442
|
+
#### Manual removal
|
|
443
|
+
|
|
444
|
+
If the CLI is unavailable, remove these directories and files manually:
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
rm -rf _bmad/ .ralph/ bmalph/
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
Then remove the bmalph-managed sections from your instructions file. The file depends on your platform:
|
|
451
|
+
|
|
452
|
+
- **Claude Code** — remove `.claude/commands/` and bmalph section from `CLAUDE.md`
|
|
453
|
+
- **Codex** — remove bmalph sections from `AGENTS.md`
|
|
454
|
+
- **Cursor** — remove `.cursor/rules/bmad.mdc`
|
|
455
|
+
- **Windsurf** — remove `.windsurf/rules/bmad.md`
|
|
456
|
+
- **Copilot** — remove bmalph sections from `.github/copilot-instructions.md`
|
|
457
|
+
- **Aider** — remove bmalph sections from `CONVENTIONS.md`
|
|
458
|
+
|
|
459
|
+
See the [Supported Platforms](#supported-platforms) table for details. After manual removal, run `bmalph init` to reinitialize.
|
|
460
|
+
|
|
394
461
|
## Quick Examples
|
|
395
462
|
|
|
396
463
|
### Initialize a new project
|
|
@@ -448,10 +515,10 @@ claude
|
|
|
448
515
|
# Phase 3: /architect → create architecture and stories
|
|
449
516
|
|
|
450
517
|
# 4. Transition to Ralph
|
|
451
|
-
#
|
|
518
|
+
# Run: bmalph implement
|
|
452
519
|
|
|
453
520
|
# 5. Start autonomous implementation
|
|
454
|
-
bash .ralph/
|
|
521
|
+
bash .ralph/drivers/claude-code.sh
|
|
455
522
|
```
|
|
456
523
|
|
|
457
524
|
**Other platforms:**
|
|
@@ -465,9 +532,9 @@ bash .ralph/ralph_loop.sh
|
|
|
465
532
|
# 3. Reference BMAD agents by name (analyst, pm, architect)
|
|
466
533
|
# Follow phases: Analysis → Planning → Solutioning
|
|
467
534
|
|
|
468
|
-
# 4. For full tier platforms (Codex), transition
|
|
469
|
-
#
|
|
470
|
-
bash .ralph/
|
|
535
|
+
# 4. For full tier platforms (Codex), transition to Ralph:
|
|
536
|
+
# Run: bmalph implement
|
|
537
|
+
bash .ralph/drivers/codex.sh
|
|
471
538
|
```
|
|
472
539
|
|
|
473
540
|
## Contributing
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,9 @@ 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";
|
|
11
|
+
import { watchCommand } from "./commands/watch.js";
|
|
9
12
|
import { setVerbose, setQuiet } from "./utils/logger.js";
|
|
10
13
|
import { getPackageVersion } from "./installer.js";
|
|
11
14
|
import { isEnoent } from "./utils/errors.js";
|
|
@@ -79,4 +82,20 @@ program
|
|
|
79
82
|
.description("Show current project status and phase")
|
|
80
83
|
.option("--json", "Output as JSON")
|
|
81
84
|
.action(async (opts) => statusCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
|
|
85
|
+
program
|
|
86
|
+
.command("implement")
|
|
87
|
+
.description("Transition BMAD planning artifacts to Ralph implementation format")
|
|
88
|
+
.option("--force", "Override pre-flight validation errors")
|
|
89
|
+
.action(async (opts) => implementCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
|
|
90
|
+
program
|
|
91
|
+
.command("reset")
|
|
92
|
+
.description("Remove all bmalph files from the project")
|
|
93
|
+
.option("--dry-run", "Preview changes without removing files")
|
|
94
|
+
.option("--force", "Skip confirmation prompt")
|
|
95
|
+
.action(async (opts) => resetCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
|
|
96
|
+
program
|
|
97
|
+
.command("watch")
|
|
98
|
+
.description("Live dashboard showing Ralph loop status, circuit breaker, and activity")
|
|
99
|
+
.option("--interval <ms>", "Refresh interval in milliseconds (default: 2000)")
|
|
100
|
+
.action(async (opts) => watchCommand({ ...opts, projectDir: await resolveAndValidateProjectDir() }));
|
|
82
101
|
void program.parseAsync();
|
|
@@ -37,15 +37,4 @@ export declare function runDoctor(options: DoctorOptions): Promise<DoctorResult>
|
|
|
37
37
|
* Core checks + platform doctor checks + trailing checks.
|
|
38
38
|
*/
|
|
39
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.
|
|
49
|
-
*/
|
|
50
|
-
export declare const CHECK_REGISTRY: CheckDefinition[];
|
|
51
40
|
export {};
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { readFile, stat } from "fs/promises";
|
|
3
|
-
import { exists } from "../utils/file-system.js";
|
|
4
3
|
import { join } from "path";
|
|
5
4
|
import { readJsonFile } from "../utils/json.js";
|
|
6
5
|
import { readConfig } from "../utils/config.js";
|
|
@@ -64,10 +63,10 @@ export async function runDoctor(options) {
|
|
|
64
63
|
}
|
|
65
64
|
return { passed, failed };
|
|
66
65
|
}
|
|
67
|
-
async function
|
|
66
|
+
async function checkCommandAvailable(command) {
|
|
68
67
|
const { execSync } = await import("child_process");
|
|
69
68
|
try {
|
|
70
|
-
const cmd = process.platform === "win32" ?
|
|
69
|
+
const cmd = process.platform === "win32" ? `where ${command}` : `which ${command}`;
|
|
71
70
|
execSync(cmd, { stdio: "ignore" });
|
|
72
71
|
return true;
|
|
73
72
|
}
|
|
@@ -88,18 +87,33 @@ async function checkNodeVersion(_projectDir) {
|
|
|
88
87
|
};
|
|
89
88
|
}
|
|
90
89
|
async function checkBash(_projectDir) {
|
|
91
|
-
const
|
|
90
|
+
const available = await checkCommandAvailable("bash");
|
|
92
91
|
return {
|
|
93
92
|
label: "bash available",
|
|
94
|
-
passed:
|
|
95
|
-
detail:
|
|
96
|
-
hint:
|
|
93
|
+
passed: available,
|
|
94
|
+
detail: available ? undefined : "bash not found in PATH",
|
|
95
|
+
hint: available
|
|
97
96
|
? undefined
|
|
98
97
|
: process.platform === "win32"
|
|
99
98
|
? "Install Git Bash or WSL: https://git-scm.com/downloads"
|
|
100
99
|
: "Install bash via your package manager (apt, brew, etc.)",
|
|
101
100
|
};
|
|
102
101
|
}
|
|
102
|
+
async function checkJq(_projectDir) {
|
|
103
|
+
const available = await checkCommandAvailable("jq");
|
|
104
|
+
return {
|
|
105
|
+
label: "jq available",
|
|
106
|
+
passed: available,
|
|
107
|
+
detail: available ? undefined : "jq not found in PATH",
|
|
108
|
+
hint: available
|
|
109
|
+
? undefined
|
|
110
|
+
: process.platform === "win32"
|
|
111
|
+
? "Install jq: choco install jq (or: winget install jqlang.jq)"
|
|
112
|
+
: process.platform === "darwin"
|
|
113
|
+
? "Install jq: brew install jq"
|
|
114
|
+
: "Install jq: sudo apt-get install jq",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
103
117
|
async function checkBmadDir(projectDir) {
|
|
104
118
|
return checkDir(join(projectDir, "_bmad"), "_bmad/ directory present", "Run: bmalph init");
|
|
105
119
|
}
|
|
@@ -399,6 +413,7 @@ async function checkUpstreamGitHubStatus(_projectDir) {
|
|
|
399
413
|
const CORE_CHECKS = [
|
|
400
414
|
{ id: "node-version", run: checkNodeVersion },
|
|
401
415
|
{ id: "bash-available", run: checkBash },
|
|
416
|
+
{ id: "jq-available", run: checkJq },
|
|
402
417
|
{ id: "config-valid", run: checkConfig },
|
|
403
418
|
{ id: "bmad-dir", run: checkBmadDir },
|
|
404
419
|
{ id: "ralph-loop", run: checkRalphLoop },
|
|
@@ -435,51 +450,3 @@ export function buildCheckRegistry(platform) {
|
|
|
435
450
|
}));
|
|
436
451
|
return [...CORE_CHECKS, ...platformChecks, ...TRAILING_CHECKS];
|
|
437
452
|
}
|
|
438
|
-
/**
|
|
439
|
-
* Static registry for backward compatibility with existing tests.
|
|
440
|
-
* Uses claude-code platform checks (slash-command + claude-md).
|
|
441
|
-
*
|
|
442
|
-
* Note: The check ids here ("slash-command", "claude-md") intentionally differ
|
|
443
|
-
* from the live buildCheckRegistry path which uses platform-provided ids
|
|
444
|
-
* ("instructions-file"). This is for test backward compatibility only.
|
|
445
|
-
*
|
|
446
|
-
* @deprecated Use `buildCheckRegistry(platform)` for platform-aware checks.
|
|
447
|
-
*/
|
|
448
|
-
export const CHECK_REGISTRY = (() => {
|
|
449
|
-
// Inline claude-code platform checks to avoid async import at module level
|
|
450
|
-
const slashCommandCheck = {
|
|
451
|
-
id: "slash-command",
|
|
452
|
-
run: async (projectDir) => {
|
|
453
|
-
if (await exists(join(projectDir, ".claude/commands/bmalph.md"))) {
|
|
454
|
-
return { label: ".claude/commands/bmalph.md present", passed: true };
|
|
455
|
-
}
|
|
456
|
-
return {
|
|
457
|
-
label: ".claude/commands/bmalph.md present",
|
|
458
|
-
passed: false,
|
|
459
|
-
detail: "not found",
|
|
460
|
-
hint: "Run: bmalph init",
|
|
461
|
-
};
|
|
462
|
-
},
|
|
463
|
-
};
|
|
464
|
-
const claudeMdCheck = {
|
|
465
|
-
id: "claude-md",
|
|
466
|
-
run: async (projectDir) => {
|
|
467
|
-
const label = "CLAUDE.md contains BMAD snippet";
|
|
468
|
-
const hint = "Run: bmalph init";
|
|
469
|
-
try {
|
|
470
|
-
const content = await readFile(join(projectDir, "CLAUDE.md"), "utf-8");
|
|
471
|
-
if (content.includes("BMAD-METHOD Integration")) {
|
|
472
|
-
return { label, passed: true };
|
|
473
|
-
}
|
|
474
|
-
return { label, passed: false, detail: "missing BMAD-METHOD Integration section", hint };
|
|
475
|
-
}
|
|
476
|
-
catch (err) {
|
|
477
|
-
if (isEnoent(err)) {
|
|
478
|
-
return { label, passed: false, detail: "CLAUDE.md not found", hint };
|
|
479
|
-
}
|
|
480
|
-
return { label, passed: false, detail: `error: ${formatError(err)}`, hint };
|
|
481
|
-
}
|
|
482
|
-
},
|
|
483
|
-
};
|
|
484
|
-
return [...CORE_CHECKS, slashCommandCheck, claudeMdCheck, ...TRAILING_CHECKS];
|
|
485
|
-
})();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { access } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { runTransition } from "../transition/orchestration.js";
|
|
5
|
+
import { withErrorHandling } from "../utils/errors.js";
|
|
6
|
+
import { resolveProjectPlatform } from "../platform/resolve.js";
|
|
7
|
+
export async function implementCommand(options) {
|
|
8
|
+
await withErrorHandling(() => runImplement(options));
|
|
9
|
+
}
|
|
10
|
+
async function runImplement(options) {
|
|
11
|
+
const { projectDir, force } = options;
|
|
12
|
+
// Re-run protection: warn if implement was already run
|
|
13
|
+
try {
|
|
14
|
+
await access(join(projectDir, ".ralph/@fix_plan.md"));
|
|
15
|
+
if (!force) {
|
|
16
|
+
console.log(chalk.yellow("Warning: bmalph implement has already been run."));
|
|
17
|
+
console.log("Re-running will overwrite PROMPT.md, PROJECT_CONTEXT.md, @AGENT.md, and SPECS_INDEX.md.");
|
|
18
|
+
console.log("Fix plan progress will be preserved.\n");
|
|
19
|
+
console.log(`Use ${chalk.bold("--force")} to proceed anyway.`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// fix_plan doesn't exist — first run, proceed
|
|
26
|
+
}
|
|
27
|
+
const platform = await resolveProjectPlatform(projectDir);
|
|
28
|
+
const result = await runTransition(projectDir, { force });
|
|
29
|
+
// Print preflight issues with severity icons
|
|
30
|
+
if (result.preflightIssues && result.preflightIssues.length > 0) {
|
|
31
|
+
console.log(chalk.bold("\nPre-flight checks\n"));
|
|
32
|
+
for (const issue of result.preflightIssues) {
|
|
33
|
+
console.log(` ${severityIcon(issue)} ${issue.message}`);
|
|
34
|
+
if (issue.suggestion) {
|
|
35
|
+
console.log(chalk.dim(` ${issue.suggestion}`));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
console.log("");
|
|
39
|
+
}
|
|
40
|
+
// Print warnings
|
|
41
|
+
if (result.warnings.length > 0) {
|
|
42
|
+
for (const warning of result.warnings) {
|
|
43
|
+
console.log(chalk.yellow(` ! ${warning}`));
|
|
44
|
+
}
|
|
45
|
+
console.log("");
|
|
46
|
+
}
|
|
47
|
+
// Generated files summary
|
|
48
|
+
if (result.generatedFiles.length > 0) {
|
|
49
|
+
console.log(chalk.bold("\nGenerated files\n"));
|
|
50
|
+
for (const file of result.generatedFiles) {
|
|
51
|
+
const icon = file.action === "created" ? chalk.green("+") : chalk.cyan("~");
|
|
52
|
+
console.log(` ${icon} ${file.path}`);
|
|
53
|
+
}
|
|
54
|
+
console.log("");
|
|
55
|
+
}
|
|
56
|
+
// Summary
|
|
57
|
+
const preserved = result.fixPlanPreserved ? chalk.dim(" (progress preserved)") : "";
|
|
58
|
+
console.log(chalk.green(`Transition complete: ${result.storiesCount} stories`) + preserved);
|
|
59
|
+
if (result.warnings.length > 0) {
|
|
60
|
+
console.log(chalk.yellow(` ${result.warnings.length} warning(s)`));
|
|
61
|
+
}
|
|
62
|
+
// Driver instructions
|
|
63
|
+
console.log("");
|
|
64
|
+
if (platform.tier === "full") {
|
|
65
|
+
console.log(`Start the Ralph loop:\n`);
|
|
66
|
+
console.log(` bash .ralph/drivers/${platform.id}.sh`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
console.log(`Ralph requires a full-tier platform (claude-code or codex). ` +
|
|
70
|
+
`Current platform: ${platform.displayName}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function severityIcon(issue) {
|
|
74
|
+
switch (issue.severity) {
|
|
75
|
+
case "error":
|
|
76
|
+
return chalk.red("\u2717");
|
|
77
|
+
case "warning":
|
|
78
|
+
return chalk.yellow("!");
|
|
79
|
+
case "info":
|
|
80
|
+
return chalk.dim("i");
|
|
81
|
+
}
|
|
82
|
+
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
3
|
import { writeConfig } from "../utils/config.js";
|
|
4
|
-
import { installProject, mergeInstructionsFile, isInitialized,
|
|
4
|
+
import { installProject, mergeInstructionsFile, isInitialized, previewInstall, getBundledVersions, } from "../installer.js";
|
|
5
5
|
import { formatDryRunSummary } from "../utils/dryrun.js";
|
|
6
6
|
import { validateProjectName } from "../utils/validate.js";
|
|
7
7
|
import { withErrorHandling } from "../utils/errors.js";
|
|
8
|
+
import { exists } from "../utils/file-system.js";
|
|
9
|
+
import { join } from "path";
|
|
8
10
|
import { isPlatformId, getPlatform } from "../platform/registry.js";
|
|
9
11
|
import { detectPlatform } from "../platform/detect.js";
|
|
10
12
|
export async function initCommand(options) {
|
|
@@ -62,7 +64,7 @@ async function runInit(options) {
|
|
|
62
64
|
console.log("Use 'bmalph upgrade' to update bundled assets to the latest version.");
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
|
-
if (await
|
|
67
|
+
if (await exists(join(projectDir, "_bmad"))) {
|
|
66
68
|
console.log(chalk.cyan("Existing BMAD installation detected."));
|
|
67
69
|
console.log("Framework files in _bmad/ will be replaced with the managed version.");
|
|
68
70
|
console.log("Planning artifacts in _bmad-output/ will not be modified.\n");
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import { isInitialized } from "../installer.js";
|
|
4
|
+
import { buildResetPlan, executeResetPlan, planToDryRunActions } from "../reset.js";
|
|
5
|
+
import { formatDryRunSummary } from "../utils/dryrun.js";
|
|
6
|
+
import { withErrorHandling } from "../utils/errors.js";
|
|
7
|
+
import { resolveProjectPlatform } from "../platform/resolve.js";
|
|
8
|
+
export async function resetCommand(options) {
|
|
9
|
+
await withErrorHandling(() => runReset(options));
|
|
10
|
+
}
|
|
11
|
+
async function runReset(options) {
|
|
12
|
+
const projectDir = options.projectDir;
|
|
13
|
+
if (!(await isInitialized(projectDir))) {
|
|
14
|
+
console.log(chalk.red("bmalph is not initialized. Nothing to reset."));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const platform = await resolveProjectPlatform(projectDir);
|
|
18
|
+
const plan = await buildResetPlan(projectDir, platform);
|
|
19
|
+
// Preview
|
|
20
|
+
const actions = planToDryRunActions(plan);
|
|
21
|
+
if (actions.length === 0) {
|
|
22
|
+
console.log(chalk.dim("Nothing to reset."));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Dry-run mode
|
|
26
|
+
if (options.dryRun) {
|
|
27
|
+
console.log(formatDryRunSummary(actions));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Show preview before confirmation
|
|
31
|
+
for (const action of actions) {
|
|
32
|
+
if (action.type === "delete") {
|
|
33
|
+
console.log(` ${chalk.red("delete")} ${action.path}`);
|
|
34
|
+
}
|
|
35
|
+
else if (action.type === "modify") {
|
|
36
|
+
console.log(` ${chalk.yellow("modify")} ${action.path}`);
|
|
37
|
+
}
|
|
38
|
+
else if (action.type === "warn") {
|
|
39
|
+
console.log(` ${chalk.yellow("warn")} ${action.path}${action.reason ? ` (${action.reason})` : ""}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Confirm unless --force or non-interactive
|
|
43
|
+
if (!options.force) {
|
|
44
|
+
if (!process.stdin.isTTY) {
|
|
45
|
+
throw new Error("Non-interactive mode requires --force flag for reset");
|
|
46
|
+
}
|
|
47
|
+
const { confirm } = await inquirer.prompt([
|
|
48
|
+
{
|
|
49
|
+
type: "confirm",
|
|
50
|
+
name: "confirm",
|
|
51
|
+
message: "This will remove all bmalph files from the project. Continue?",
|
|
52
|
+
default: false,
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
if (!confirm) {
|
|
56
|
+
console.log("Aborted.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Execute
|
|
61
|
+
console.log("\nResetting...");
|
|
62
|
+
await executeResetPlan(projectDir, plan);
|
|
63
|
+
// Summary
|
|
64
|
+
console.log(chalk.green("\nReset complete."));
|
|
65
|
+
if (plan.directories.length > 0) {
|
|
66
|
+
console.log(chalk.dim("\nRemoved:"));
|
|
67
|
+
for (const dir of plan.directories) {
|
|
68
|
+
console.log(` ${dir}/`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (plan.commandFiles.length > 0) {
|
|
72
|
+
console.log(chalk.dim("\nRemoved commands:"));
|
|
73
|
+
for (const file of plan.commandFiles) {
|
|
74
|
+
console.log(` ${file}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Show warnings
|
|
78
|
+
for (const warning of plan.warnings) {
|
|
79
|
+
console.log(chalk.yellow(`\nNote: ${warning.path} ${warning.message}`));
|
|
80
|
+
}
|
|
81
|
+
}
|