bmalph 2.3.0 → 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.
- package/README.md +56 -23
- package/dist/cli.js +13 -0
- package/dist/commands/doctor.js +22 -6
- package/dist/commands/implement.d.ts +6 -0
- package/dist/commands/implement.js +82 -0
- package/dist/commands/reset.d.ts +7 -0
- package/dist/commands/reset.js +81 -0
- package/dist/commands/status.js +86 -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 +1 -0
- package/dist/transition/artifacts.js +1 -0
- 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/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/validate.js +2 -2
- package/package.json +1 -1
- package/ralph/ralph_loop.sh +15 -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/README.md
CHANGED
|
@@ -25,7 +25,7 @@ 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
29
|
|
|
30
30
|
## Supported Platforms
|
|
31
31
|
|
|
@@ -155,7 +155,7 @@ Available in any phase for supporting tasks:
|
|
|
155
155
|
|
|
156
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
157
|
|
|
158
|
-
|
|
158
|
+
Run `bmalph implement` from the terminal, or use the `/bmalph-implement` slash command in Claude Code.
|
|
159
159
|
|
|
160
160
|
This transitions your BMAD artifacts into Ralph's format:
|
|
161
161
|
|
|
@@ -164,10 +164,14 @@ This transitions your BMAD artifacts into Ralph's format:
|
|
|
164
164
|
3. Copies specs to `.ralph/specs/` with changelog tracking
|
|
165
165
|
4. Instructs you to start the Ralph autonomous loop
|
|
166
166
|
|
|
167
|
-
Then start Ralph:
|
|
167
|
+
Then start Ralph using the driver for your platform:
|
|
168
168
|
|
|
169
169
|
```bash
|
|
170
|
-
|
|
170
|
+
# Claude Code
|
|
171
|
+
bash .ralph/drivers/claude-code.sh
|
|
172
|
+
|
|
173
|
+
# OpenAI Codex
|
|
174
|
+
bash .ralph/drivers/codex.sh
|
|
171
175
|
```
|
|
172
176
|
|
|
173
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.
|
|
@@ -177,12 +181,12 @@ Ralph picks stories one by one, implements with TDD, and commits. The loop stops
|
|
|
177
181
|
bmalph supports iterative development cycles:
|
|
178
182
|
|
|
179
183
|
```
|
|
180
|
-
BMAD (Epic 1) →
|
|
184
|
+
BMAD (Epic 1) → bmalph implement → Ralph works on Epic 1
|
|
181
185
|
↓
|
|
182
|
-
BMAD (add Epic 2) →
|
|
186
|
+
BMAD (add Epic 2) → bmalph implement → Ralph sees changes + picks up Epic 2
|
|
183
187
|
```
|
|
184
188
|
|
|
185
|
-
**Smart Merge**: When you run
|
|
189
|
+
**Smart Merge**: When you run `bmalph implement` again after Ralph has made progress:
|
|
186
190
|
|
|
187
191
|
- Completed stories (`[x]`) are preserved in the new fix_plan
|
|
188
192
|
- New stories from BMAD are added as pending (`[ ]`)
|
|
@@ -198,6 +202,7 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
|
|
|
198
202
|
| `bmalph doctor` | Check installation health |
|
|
199
203
|
| `bmalph check-updates` | Check if bundled BMAD/Ralph versions are up to date |
|
|
200
204
|
| `bmalph status` | Show current project status and phase |
|
|
205
|
+
| `bmalph implement` | Transition BMAD planning artifacts to Ralph format |
|
|
201
206
|
|
|
202
207
|
### Global options
|
|
203
208
|
|
|
@@ -218,6 +223,24 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
|
|
|
218
223
|
| `-d, --description <desc>` | Project description | (prompted) |
|
|
219
224
|
| `--platform <id>` | Target platform (`claude-code`, `codex`, `cursor`, `windsurf`, `copilot`, `aider`) | auto-detect |
|
|
220
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 |
|
|
243
|
+
|
|
221
244
|
### upgrade options
|
|
222
245
|
|
|
223
246
|
| Flag | Description |
|
|
@@ -227,7 +250,7 @@ BMAD (add Epic 2) → /bmalph-implement → Ralph sees changes + picks up Epic 2
|
|
|
227
250
|
|
|
228
251
|
## Slash Commands
|
|
229
252
|
|
|
230
|
-
bmalph installs
|
|
253
|
+
bmalph installs 50 slash commands (45 BMAD + 5 bmalph). Command delivery varies by platform:
|
|
231
254
|
|
|
232
255
|
- **Claude Code** — installed as files in `.claude/commands/` (invoke with `/command-name`)
|
|
233
256
|
- **OpenAI Codex** — inlined in `AGENTS.md` (reference agents by name)
|
|
@@ -256,7 +279,7 @@ For full list, run `/bmad-help` in Claude Code.
|
|
|
256
279
|
|
|
257
280
|
### Transition to Ralph
|
|
258
281
|
|
|
259
|
-
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.
|
|
260
283
|
|
|
261
284
|
## Project Structure (after init)
|
|
262
285
|
|
|
@@ -264,15 +287,23 @@ Use `/bmalph-implement` to transition from BMAD planning to Ralph implementation
|
|
|
264
287
|
project/
|
|
265
288
|
├── _bmad/ # BMAD agents, workflows, core
|
|
266
289
|
│ ├── _config/ # Generated configuration
|
|
267
|
-
│ │
|
|
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
|
|
268
294
|
│ ├── core/
|
|
269
295
|
│ │ ├── agents/ # Master agent
|
|
270
296
|
│ │ ├── tasks/ # Workflow tasks
|
|
271
|
-
│ │
|
|
297
|
+
│ │ ├── workflows/ # Brainstorming, party-mode, etc.
|
|
298
|
+
│ │ ├── module.yaml # Core module metadata
|
|
299
|
+
│ │ └── module-help.csv # Core module help entries
|
|
272
300
|
│ └── bmm/
|
|
273
301
|
│ ├── agents/ # Analyst, PM, Architect, Dev, QA, etc.
|
|
302
|
+
│ ├── data/ # Templates (project-context-template.md)
|
|
274
303
|
│ ├── workflows/ # Phase 1-4 workflows
|
|
275
|
-
│
|
|
304
|
+
│ ├── teams/ # Agent team definitions
|
|
305
|
+
│ ├── module.yaml # BMM module metadata
|
|
306
|
+
│ └── module-help.csv # BMM module help entries
|
|
276
307
|
├── _bmad-output/ # BMAD planning artifacts (generated)
|
|
277
308
|
│ ├── planning-artifacts/ # PRD, architecture, stories
|
|
278
309
|
│ ├── implementation-artifacts/ # Sprint plans (optional)
|
|
@@ -286,14 +317,16 @@ project/
|
|
|
286
317
|
│ ├── drivers/ # Platform driver scripts
|
|
287
318
|
│ │ ├── claude-code.sh # Claude Code driver (uses `claude`)
|
|
288
319
|
│ │ └── codex.sh # OpenAI Codex driver (uses `codex exec`)
|
|
289
|
-
│ ├── lib/ #
|
|
320
|
+
│ ├── lib/ # Shell libraries
|
|
321
|
+
│ ├── docs/generated/ # Generated documentation
|
|
290
322
|
│ ├── specs/ # Copied from _bmad-output during transition
|
|
291
323
|
│ ├── logs/ # Loop execution logs
|
|
292
324
|
│ ├── PROMPT.md # Iteration prompt template
|
|
293
|
-
│ ├── PROJECT_CONTEXT.md # Extracted project context (after
|
|
294
|
-
│ ├── SPECS_CHANGELOG.md # Spec diff since last run (after
|
|
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)
|
|
295
328
|
│ ├── @AGENT.md # Agent build instructions
|
|
296
|
-
│ └── @fix_plan.md # Generated task list (after
|
|
329
|
+
│ └── @fix_plan.md # Generated task list (after bmalph implement)
|
|
297
330
|
├── bmalph/ # State management
|
|
298
331
|
│ ├── config.json # Project config (name, description, platform)
|
|
299
332
|
│ └── state/ # Phase tracking data
|
|
@@ -352,8 +385,8 @@ wsl --install
|
|
|
352
385
|
If you get permission errors:
|
|
353
386
|
|
|
354
387
|
```bash
|
|
355
|
-
# Unix/Mac: Make
|
|
356
|
-
chmod +x .ralph/
|
|
388
|
+
# Unix/Mac: Make driver scripts executable
|
|
389
|
+
chmod +x .ralph/drivers/*.sh
|
|
357
390
|
|
|
358
391
|
# Check file ownership
|
|
359
392
|
ls -la .ralph/
|
|
@@ -448,10 +481,10 @@ claude
|
|
|
448
481
|
# Phase 3: /architect → create architecture and stories
|
|
449
482
|
|
|
450
483
|
# 4. Transition to Ralph
|
|
451
|
-
#
|
|
484
|
+
# Run: bmalph implement
|
|
452
485
|
|
|
453
486
|
# 5. Start autonomous implementation
|
|
454
|
-
bash .ralph/
|
|
487
|
+
bash .ralph/drivers/claude-code.sh
|
|
455
488
|
```
|
|
456
489
|
|
|
457
490
|
**Other platforms:**
|
|
@@ -465,9 +498,9 @@ bash .ralph/ralph_loop.sh
|
|
|
465
498
|
# 3. Reference BMAD agents by name (analyst, pm, architect)
|
|
466
499
|
# Follow phases: Analysis → Planning → Solutioning
|
|
467
500
|
|
|
468
|
-
# 4. For full tier platforms (Codex), transition
|
|
469
|
-
#
|
|
470
|
-
bash .ralph/
|
|
501
|
+
# 4. For full tier platforms (Codex), transition to Ralph:
|
|
502
|
+
# Run: bmalph implement
|
|
503
|
+
bash .ralph/drivers/codex.sh
|
|
471
504
|
```
|
|
472
505
|
|
|
473
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";
|
|
@@ -79,4 +81,15 @@ program
|
|
|
79
81
|
.description("Show current project status and phase")
|
|
80
82
|
.option("--json", "Output as JSON")
|
|
81
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() }));
|
|
82
95
|
void program.parseAsync();
|
package/dist/commands/doctor.js
CHANGED
|
@@ -64,10 +64,10 @@ export async function runDoctor(options) {
|
|
|
64
64
|
}
|
|
65
65
|
return { passed, failed };
|
|
66
66
|
}
|
|
67
|
-
async function
|
|
67
|
+
async function checkCommandAvailable(command) {
|
|
68
68
|
const { execSync } = await import("child_process");
|
|
69
69
|
try {
|
|
70
|
-
const cmd = process.platform === "win32" ?
|
|
70
|
+
const cmd = process.platform === "win32" ? `where ${command}` : `which ${command}`;
|
|
71
71
|
execSync(cmd, { stdio: "ignore" });
|
|
72
72
|
return true;
|
|
73
73
|
}
|
|
@@ -88,18 +88,33 @@ async function checkNodeVersion(_projectDir) {
|
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
async function checkBash(_projectDir) {
|
|
91
|
-
const
|
|
91
|
+
const available = await checkCommandAvailable("bash");
|
|
92
92
|
return {
|
|
93
93
|
label: "bash available",
|
|
94
|
-
passed:
|
|
95
|
-
detail:
|
|
96
|
-
hint:
|
|
94
|
+
passed: available,
|
|
95
|
+
detail: available ? undefined : "bash not found in PATH",
|
|
96
|
+
hint: available
|
|
97
97
|
? undefined
|
|
98
98
|
: process.platform === "win32"
|
|
99
99
|
? "Install Git Bash or WSL: https://git-scm.com/downloads"
|
|
100
100
|
: "Install bash via your package manager (apt, brew, etc.)",
|
|
101
101
|
};
|
|
102
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
|
+
}
|
|
103
118
|
async function checkBmadDir(projectDir) {
|
|
104
119
|
return checkDir(join(projectDir, "_bmad"), "_bmad/ directory present", "Run: bmalph init");
|
|
105
120
|
}
|
|
@@ -399,6 +414,7 @@ async function checkUpstreamGitHubStatus(_projectDir) {
|
|
|
399
414
|
const CORE_CHECKS = [
|
|
400
415
|
{ id: "node-version", run: checkNodeVersion },
|
|
401
416
|
{ id: "bash-available", run: checkBash },
|
|
417
|
+
{ id: "jq-available", run: checkJq },
|
|
402
418
|
{ id: "config-valid", run: checkConfig },
|
|
403
419
|
{ id: "bmad-dir", run: checkBmadDir },
|
|
404
420
|
{ id: "ralph-loop", run: checkRalphLoop },
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
}
|
package/dist/commands/status.js
CHANGED
|
@@ -2,6 +2,8 @@ import chalk from "chalk";
|
|
|
2
2
|
import { readConfig } from "../utils/config.js";
|
|
3
3
|
import { readState, readRalphStatus, getPhaseLabel, getPhaseInfo } from "../utils/state.js";
|
|
4
4
|
import { withErrorHandling } from "../utils/errors.js";
|
|
5
|
+
import { resolveProjectPlatform } from "../platform/resolve.js";
|
|
6
|
+
import { scanProjectArtifacts } from "../transition/artifact-scan.js";
|
|
5
7
|
export async function statusCommand(options) {
|
|
6
8
|
await withErrorHandling(() => runStatus(options));
|
|
7
9
|
}
|
|
@@ -15,17 +17,32 @@ export async function runStatus(options) {
|
|
|
15
17
|
}
|
|
16
18
|
// Read current state
|
|
17
19
|
const state = await readState(projectDir);
|
|
18
|
-
const
|
|
20
|
+
const storedPhase = state?.currentPhase ?? 1;
|
|
19
21
|
const status = state?.status ?? "planning";
|
|
20
|
-
const phaseName = getPhaseLabel(phase);
|
|
21
|
-
const phaseInfo = getPhaseInfo(phase);
|
|
22
22
|
// Read Ralph status if in implementation phase
|
|
23
23
|
let ralphStatus = null;
|
|
24
|
-
if (
|
|
24
|
+
if (storedPhase === 4) {
|
|
25
25
|
ralphStatus = await readRalphStatus(projectDir);
|
|
26
26
|
}
|
|
27
|
-
//
|
|
28
|
-
|
|
27
|
+
// Scan artifacts for phases 1-3 to detect actual progress
|
|
28
|
+
let artifactScan = null;
|
|
29
|
+
let phase = storedPhase;
|
|
30
|
+
let phaseDetected = false;
|
|
31
|
+
if (phase < 4) {
|
|
32
|
+
artifactScan = await scanProjectArtifacts(projectDir);
|
|
33
|
+
if (artifactScan && artifactScan.detectedPhase > phase) {
|
|
34
|
+
phase = artifactScan.detectedPhase;
|
|
35
|
+
phaseDetected = true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const phaseName = getPhaseLabel(phase);
|
|
39
|
+
const phaseInfo = getPhaseInfo(phase);
|
|
40
|
+
// Resolve platform for next action hints
|
|
41
|
+
const platform = await resolveProjectPlatform(projectDir);
|
|
42
|
+
// Determine next action — use artifact-based suggestion when available
|
|
43
|
+
const nextAction = artifactScan && phaseDetected
|
|
44
|
+
? artifactScan.nextAction
|
|
45
|
+
: getNextAction(phase, status, ralphStatus, platform);
|
|
29
46
|
if (options.json) {
|
|
30
47
|
const output = {
|
|
31
48
|
phase,
|
|
@@ -40,6 +57,14 @@ export async function runStatus(options) {
|
|
|
40
57
|
tasksTotal: ralphStatus.tasksTotal,
|
|
41
58
|
};
|
|
42
59
|
}
|
|
60
|
+
if (artifactScan) {
|
|
61
|
+
output.artifacts = {
|
|
62
|
+
directory: artifactScan.directory,
|
|
63
|
+
found: artifactScan.found,
|
|
64
|
+
detectedPhase: artifactScan.detectedPhase,
|
|
65
|
+
missing: artifactScan.missing,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
43
68
|
if (nextAction) {
|
|
44
69
|
output.nextAction = nextAction;
|
|
45
70
|
}
|
|
@@ -48,9 +73,18 @@ export async function runStatus(options) {
|
|
|
48
73
|
}
|
|
49
74
|
// Human-readable output
|
|
50
75
|
console.log(chalk.bold("bmalph status\n"));
|
|
51
|
-
|
|
76
|
+
const phaseLabel = phaseDetected
|
|
77
|
+
? `${phase} - ${phaseName} (detected from artifacts)`
|
|
78
|
+
: `${phase} - ${phaseName}`;
|
|
79
|
+
console.log(` ${chalk.cyan("Phase:")} ${phaseLabel}`);
|
|
52
80
|
console.log(` ${chalk.cyan("Agent:")} ${phaseInfo.agent}`);
|
|
53
81
|
console.log(` ${chalk.cyan("Status:")} ${formatStatus(status)}`);
|
|
82
|
+
// Show artifact checklist for phases 1-3
|
|
83
|
+
if (artifactScan) {
|
|
84
|
+
console.log("");
|
|
85
|
+
console.log(chalk.bold(` Artifacts (${artifactScan.directory})`));
|
|
86
|
+
printArtifactChecklist(artifactScan);
|
|
87
|
+
}
|
|
54
88
|
if (phase === 4 && ralphStatus) {
|
|
55
89
|
console.log("");
|
|
56
90
|
console.log(chalk.bold(" Ralph Loop"));
|
|
@@ -68,6 +102,45 @@ export async function runStatus(options) {
|
|
|
68
102
|
console.log(` ${chalk.cyan("Next:")} ${nextAction}`);
|
|
69
103
|
}
|
|
70
104
|
}
|
|
105
|
+
const ARTIFACT_DEFINITIONS = [
|
|
106
|
+
{ phase: 1, name: "Product Brief", required: false },
|
|
107
|
+
{ phase: 1, name: "Market Research", required: false },
|
|
108
|
+
{ phase: 1, name: "Domain Research", required: false },
|
|
109
|
+
{ phase: 1, name: "Technical Research", required: false },
|
|
110
|
+
{ phase: 2, name: "PRD", required: true },
|
|
111
|
+
{ phase: 2, name: "UX Design", required: false },
|
|
112
|
+
{ phase: 3, name: "Architecture", required: true },
|
|
113
|
+
{ phase: 3, name: "Epics & Stories", required: true },
|
|
114
|
+
{ phase: 3, name: "Readiness Report", required: true },
|
|
115
|
+
];
|
|
116
|
+
const PHASE_LABELS = {
|
|
117
|
+
1: "Phase 1 - Analysis",
|
|
118
|
+
2: "Phase 2 - Planning",
|
|
119
|
+
3: "Phase 3 - Solutioning",
|
|
120
|
+
};
|
|
121
|
+
function printArtifactChecklist(scan) {
|
|
122
|
+
const foundByName = new Map();
|
|
123
|
+
for (const artifacts of [scan.phases[1], scan.phases[2], scan.phases[3]]) {
|
|
124
|
+
for (const artifact of artifacts) {
|
|
125
|
+
foundByName.set(artifact.name, artifact);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
let currentPhase = 0;
|
|
129
|
+
for (const def of ARTIFACT_DEFINITIONS) {
|
|
130
|
+
if (def.phase !== currentPhase) {
|
|
131
|
+
currentPhase = def.phase;
|
|
132
|
+
console.log(` ${PHASE_LABELS[currentPhase]}`);
|
|
133
|
+
}
|
|
134
|
+
const found = foundByName.get(def.name);
|
|
135
|
+
if (found) {
|
|
136
|
+
console.log(` ${chalk.green("*")} ${def.name} (${found.filename})`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const suffix = def.required ? " (required)" : "";
|
|
140
|
+
console.log(` ${chalk.dim("-")} ${def.name}${suffix}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
71
144
|
function formatStatus(status) {
|
|
72
145
|
switch (status) {
|
|
73
146
|
case "planning":
|
|
@@ -94,7 +167,7 @@ function formatRalphStatus(status) {
|
|
|
94
167
|
return status;
|
|
95
168
|
}
|
|
96
169
|
}
|
|
97
|
-
function getNextAction(phase, status, ralphStatus) {
|
|
170
|
+
function getNextAction(phase, status, ralphStatus, platform) {
|
|
98
171
|
if (status === "completed") {
|
|
99
172
|
return null;
|
|
100
173
|
}
|
|
@@ -104,10 +177,13 @@ function getNextAction(phase, status, ralphStatus) {
|
|
|
104
177
|
case 2:
|
|
105
178
|
return "Run /pm to create PRD";
|
|
106
179
|
case 3:
|
|
107
|
-
return "Run
|
|
180
|
+
return "Run: bmalph implement";
|
|
108
181
|
case 4:
|
|
109
182
|
if (!ralphStatus || ralphStatus.status === "not_started") {
|
|
110
|
-
|
|
183
|
+
if (platform.tier === "full") {
|
|
184
|
+
return `Start Ralph loop with: bash .ralph/drivers/${platform.id}.sh`;
|
|
185
|
+
}
|
|
186
|
+
return "Ralph requires a full-tier platform (Claude Code or Codex)";
|
|
111
187
|
}
|
|
112
188
|
if (ralphStatus.status === "blocked") {
|
|
113
189
|
return "Review Ralph logs: bmalph doctor";
|
|
@@ -36,7 +36,6 @@ Use \`/bmalph\` to navigate phases. Use \`/bmad-help\` to discover all commands.
|
|
|
36
36
|
| \`/bmalph-implement\` | Transition planning artifacts → prepare Ralph loop |
|
|
37
37
|
| \`/bmalph-upgrade\` | Update bundled assets to match current bmalph version |
|
|
38
38
|
| \`/bmalph-doctor\` | Check project health and report issues |
|
|
39
|
-
| \`/bmalph-reset\` | Reset state (soft or hard reset with confirmation) |
|
|
40
39
|
|
|
41
40
|
### Available Agents
|
|
42
41
|
|
package/dist/reset.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Platform } from "./platform/types.js";
|
|
2
|
+
import type { DryRunAction } from "./utils/dryrun.js";
|
|
3
|
+
export interface ResetPlan {
|
|
4
|
+
directories: string[];
|
|
5
|
+
commandFiles: string[];
|
|
6
|
+
instructionsCleanup: {
|
|
7
|
+
path: string;
|
|
8
|
+
sectionsToRemove: string[];
|
|
9
|
+
} | null;
|
|
10
|
+
gitignoreLines: string[];
|
|
11
|
+
warnings: Array<{
|
|
12
|
+
path: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildResetPlan(projectDir: string, platform: Platform): Promise<ResetPlan>;
|
|
17
|
+
export declare function executeResetPlan(projectDir: string, plan: ResetPlan): Promise<void>;
|
|
18
|
+
export declare function planToDryRunActions(plan: ResetPlan): DryRunAction[];
|