bmalph 2.7.4 → 2.7.6
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 +87 -34
- package/dist/commands/doctor-checks.js +5 -4
- package/dist/commands/doctor-checks.js.map +1 -1
- package/dist/commands/doctor-runtime-checks.js +104 -86
- package/dist/commands/doctor-runtime-checks.js.map +1 -1
- package/dist/commands/run.js +4 -0
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/status.js +12 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/installer/bmad-assets.js +182 -0
- package/dist/installer/bmad-assets.js.map +1 -0
- package/dist/installer/commands.js +324 -0
- package/dist/installer/commands.js.map +1 -0
- package/dist/installer/install.js +42 -0
- package/dist/installer/install.js.map +1 -0
- package/dist/installer/metadata.js +56 -0
- package/dist/installer/metadata.js.map +1 -0
- package/dist/installer/project-files.js +169 -0
- package/dist/installer/project-files.js.map +1 -0
- package/dist/installer/ralph-assets.js +91 -0
- package/dist/installer/ralph-assets.js.map +1 -0
- package/dist/installer/template-files.js +168 -0
- package/dist/installer/template-files.js.map +1 -0
- package/dist/installer/types.js +2 -0
- package/dist/installer/types.js.map +1 -0
- package/dist/installer.js +5 -790
- package/dist/installer.js.map +1 -1
- package/dist/platform/cursor-runtime-checks.js +81 -0
- package/dist/platform/cursor-runtime-checks.js.map +1 -0
- package/dist/platform/cursor.js +4 -3
- package/dist/platform/cursor.js.map +1 -1
- package/dist/platform/detect.js +28 -5
- package/dist/platform/detect.js.map +1 -1
- package/dist/platform/instructions-snippet.js +18 -0
- package/dist/platform/instructions-snippet.js.map +1 -1
- package/dist/platform/resolve.js +23 -5
- package/dist/platform/resolve.js.map +1 -1
- package/dist/run/ralph-process.js +84 -15
- package/dist/run/ralph-process.js.map +1 -1
- package/dist/transition/artifact-loading.js +91 -0
- package/dist/transition/artifact-loading.js.map +1 -0
- package/dist/transition/artifact-scan.js +15 -3
- package/dist/transition/artifact-scan.js.map +1 -1
- package/dist/transition/context-output.js +85 -0
- package/dist/transition/context-output.js.map +1 -0
- package/dist/transition/fix-plan-sync.js +119 -0
- package/dist/transition/fix-plan-sync.js.map +1 -0
- package/dist/transition/orchestration.js +25 -362
- package/dist/transition/orchestration.js.map +1 -1
- package/dist/transition/specs-sync.js +78 -2
- package/dist/transition/specs-sync.js.map +1 -1
- package/dist/utils/ralph-runtime-state.js +222 -0
- package/dist/utils/ralph-runtime-state.js.map +1 -0
- package/dist/utils/state.js +17 -16
- package/dist/utils/state.js.map +1 -1
- package/dist/utils/validate.js +16 -0
- package/dist/utils/validate.js.map +1 -1
- package/dist/watch/renderer.js +48 -6
- package/dist/watch/renderer.js.map +1 -1
- package/dist/watch/state-reader.js +79 -44
- package/dist/watch/state-reader.js.map +1 -1
- package/package.json +1 -1
- package/ralph/RALPH-REFERENCE.md +60 -16
- package/ralph/drivers/claude-code.sh +25 -0
- package/ralph/drivers/codex.sh +11 -0
- package/ralph/drivers/copilot.sh +11 -0
- package/ralph/drivers/cursor.sh +58 -29
- package/ralph/lib/circuit_breaker.sh +3 -3
- package/ralph/lib/date_utils.sh +28 -9
- package/ralph/lib/response_analyzer.sh +220 -17
- package/ralph/ralph_loop.sh +464 -121
- package/ralph/templates/PROMPT.md +5 -0
- package/ralph/templates/ralphrc.template +14 -4
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://github.com/LarsCowe/bmalph/actions/workflows/ci.yml)
|
|
8
8
|
[](https://codecov.io/gh/LarsCowe/bmalph)
|
|
9
9
|
|
|
10
|
-
[BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) planning + [Ralph](https://github.com/snarktank/ralph) autonomous implementation,
|
|
10
|
+
[BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) planning + [Ralph](https://github.com/snarktank/ralph) autonomous implementation, wired through platform-specific instructions, skills, and command indexes.
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
13
|
<img src="docs/bmalph-diagram-light.svg" alt="bmalph workflow diagram" width="800" />
|
|
@@ -70,7 +70,8 @@ cd my-project
|
|
|
70
70
|
bmalph init --name my-project
|
|
71
71
|
|
|
72
72
|
# To target a specific platform, add --platform (e.g. codex, cursor, windsurf)
|
|
73
|
-
# Without --platform, bmalph auto-detects
|
|
73
|
+
# Without --platform, bmalph auto-detects strong project markers and
|
|
74
|
+
# prompts interactively when detection is ambiguous or missing
|
|
74
75
|
```
|
|
75
76
|
|
|
76
77
|
## Workflow
|
|
@@ -84,13 +85,15 @@ bmalph init
|
|
|
84
85
|
|
|
85
86
|
**Platform resolution:** `--platform` flag > auto-detect from project markers > interactive prompt > default `claude-code`
|
|
86
87
|
|
|
88
|
+
Strong markers such as `.cursor/`, `.claude/`, `.windsurf/`, `.github/copilot-instructions.md`, and `.aider.conf.yml` are auto-detected directly. Root-only `AGENTS.md` and `CLAUDE.md` are treated as weak hints and may still trigger the interactive platform prompt.
|
|
89
|
+
|
|
87
90
|
This installs:
|
|
88
91
|
|
|
89
92
|
- `_bmad/` — BMAD agents and workflows
|
|
90
93
|
- `.ralph/` — Ralph loop, libs, templates (drivers for claude-code, codex, copilot, and cursor)
|
|
91
94
|
- `bmalph/` — State management (config.json, stores selected platform)
|
|
92
95
|
- Updates the platform's instructions file with BMAD workflow instructions (e.g. `CLAUDE.md`, `AGENTS.md`, `.cursor/rules/bmad.mdc`)
|
|
93
|
-
-
|
|
96
|
+
- Delivers BMAD commands using the platform's native mechanism (Claude Code: `.claude/commands/`; Codex: `.agents/skills/`; Cursor, Windsurf, Copilot, and Aider: `_bmad/COMMANDS.md`)
|
|
94
97
|
|
|
95
98
|
### Migrating from standalone BMAD
|
|
96
99
|
|
|
@@ -102,7 +105,12 @@ If you already have BMAD installed (a `_bmad/` directory), `bmalph init` works a
|
|
|
102
105
|
|
|
103
106
|
### Step 2: Plan with BMAD (Phases 1-3)
|
|
104
107
|
|
|
105
|
-
Work interactively with BMAD agents in your AI coding assistant.
|
|
108
|
+
Work interactively with BMAD agents in your AI coding assistant.
|
|
109
|
+
|
|
110
|
+
- **Claude Code** — use `/bmalph` to see your current phase and available commands.
|
|
111
|
+
- **OpenAI Codex** — use Codex Skills such as `$analyst` and `$create-prd`.
|
|
112
|
+
- **Cursor** — Read `_bmad/COMMANDS.md` and ask Cursor to run the BMAD master agent.
|
|
113
|
+
- **Windsurf, Copilot, Aider** — use `_bmad/COMMANDS.md` as the command reference and ask the assistant to follow the named BMAD workflow.
|
|
106
114
|
|
|
107
115
|
| Phase | Agent | Commands |
|
|
108
116
|
| ------------- | ---------------- | ------------------ |
|
|
@@ -110,7 +118,7 @@ Work interactively with BMAD agents in your AI coding assistant. On Claude Code,
|
|
|
110
118
|
| 2 Planning | PM / UX Designer | CP, VP, EP, CU |
|
|
111
119
|
| 3 Solutioning | Architect / PM | CA, CE, IR |
|
|
112
120
|
|
|
113
|
-
Validation commands (
|
|
121
|
+
Validation commands (`validate-brief`, `validate-prd`, `validate-ux`, `validate-architecture`, `validate-epics-stories`) run the same workflow in Validate mode. In Claude Code, invoke them as slash commands; on other platforms use the equivalent entry from `_bmad/COMMANDS.md` or Codex Skills.
|
|
114
122
|
|
|
115
123
|
**Phase 1 — Analysis**
|
|
116
124
|
|
|
@@ -152,7 +160,7 @@ Available in any phase for supporting tasks:
|
|
|
152
160
|
- `AR` Adversarial Review — critical content review for QA
|
|
153
161
|
- `US` Update Standards — update tech-writer documentation standards
|
|
154
162
|
- `EC` Explain Concept — create technical explanations with examples
|
|
155
|
-
-
|
|
163
|
+
- `_bmad/COMMANDS.md` — generated command reference for platforms without native slash commands
|
|
156
164
|
|
|
157
165
|
> **Note:** `EP` means Edit PRD in the bmm workflow (Phase 2) and Editorial Review — Prose in the core module. `PM` is Party Mode in core. The bmm meanings are the primary workflow codes.
|
|
158
166
|
|
|
@@ -284,13 +292,14 @@ BMAD (add Epic 2) → bmalph implement → Ralph sees changes + picks up Epic 2
|
|
|
284
292
|
| ----------------- | ------------------------------------------------ |
|
|
285
293
|
| `--interval <ms>` | Refresh interval in milliseconds (default: 2000) |
|
|
286
294
|
|
|
287
|
-
##
|
|
295
|
+
## Command Delivery
|
|
288
296
|
|
|
289
|
-
bmalph
|
|
297
|
+
bmalph bundles 51 BMAD and bmalph command definitions. Delivery varies by platform:
|
|
290
298
|
|
|
291
299
|
- **Claude Code** — installed as files in `.claude/commands/` (invoke with `/command-name`)
|
|
292
300
|
- **OpenAI Codex** — delivered as Codex Skills in `.agents/skills/` (invoke with `$command-name`)
|
|
293
|
-
- **Cursor
|
|
301
|
+
- **Cursor** — discoverable via `_bmad/COMMANDS.md`; ask Cursor to run the BMAD master agent
|
|
302
|
+
- **Windsurf, Copilot, Aider** — discoverable via `_bmad/COMMANDS.md` reference index
|
|
294
303
|
|
|
295
304
|
Key commands (Claude Code syntax):
|
|
296
305
|
|
|
@@ -311,7 +320,11 @@ Key commands (Claude Code syntax):
|
|
|
311
320
|
| `/create-epics-stories` | Create epics and stories |
|
|
312
321
|
| `/bmad-help` | List all BMAD commands |
|
|
313
322
|
|
|
314
|
-
For full list
|
|
323
|
+
For the full list:
|
|
324
|
+
|
|
325
|
+
- Claude Code: run `/bmad-help`
|
|
326
|
+
- OpenAI Codex: inspect `.agents/skills/`
|
|
327
|
+
- Cursor, Windsurf, Copilot, Aider: open `_bmad/COMMANDS.md`
|
|
315
328
|
|
|
316
329
|
### Transition to Ralph
|
|
317
330
|
|
|
@@ -322,8 +335,9 @@ Use `bmalph implement` (or `/bmalph-implement` in Claude Code) to transition fro
|
|
|
322
335
|
```
|
|
323
336
|
project/
|
|
324
337
|
├── _bmad/ # BMAD agents, workflows, core
|
|
325
|
-
│ ├──
|
|
326
|
-
│
|
|
338
|
+
│ ├── config.yaml # Generated platform/project config
|
|
339
|
+
│ ├── COMMANDS.md # Generated command reference index
|
|
340
|
+
│ ├── _config/ # Generated manifests
|
|
327
341
|
│ │ ├── task-manifest.csv # Combined task manifest
|
|
328
342
|
│ │ ├── workflow-manifest.csv # Combined workflow manifest
|
|
329
343
|
│ │ └── bmad-help.csv # Combined help manifest
|
|
@@ -380,10 +394,10 @@ The instructions file and command directory depend on the configured platform. S
|
|
|
380
394
|
|
|
381
395
|
Ralph is a bash loop that spawns fresh AI coding sessions using a **platform driver** matching the configured platform:
|
|
382
396
|
|
|
383
|
-
- **Claude Code driver** — invokes `claude` with `--allowedTools
|
|
384
|
-
- **Codex driver** — invokes `codex exec
|
|
397
|
+
- **Claude Code driver** — invokes `claude` with `--output-format json`, `--permission-mode auto`, `--allowedTools`, and explicit `--resume <session_id>`
|
|
398
|
+
- **Codex driver** — invokes `codex exec --json --sandbox workspace-write` with explicit `--resume <session_id>`
|
|
385
399
|
- **Copilot driver** _(experimental)_ — invokes `copilot --autopilot --yolo` with plain-text output
|
|
386
|
-
- **Cursor driver** _(experimental)_ — invokes `cursor-agent --
|
|
400
|
+
- **Cursor driver** _(experimental)_ — invokes `cursor-agent -p --force --output-format json`, persists `session_id` for `--resume`, and switches to `stream-json` only for live output
|
|
387
401
|
|
|
388
402
|
Each iteration:
|
|
389
403
|
|
|
@@ -398,6 +412,12 @@ Safety mechanisms:
|
|
|
398
412
|
- **Response analyzer** — detects stuck or repeating outputs
|
|
399
413
|
- **Completion** — loop exits when all `@fix_plan.md` items are checked off
|
|
400
414
|
|
|
415
|
+
Cursor-specific runtime checks:
|
|
416
|
+
|
|
417
|
+
- `bmalph doctor` validates `command -v jq` in the bash environment Ralph uses
|
|
418
|
+
- `bmalph doctor` validates `command -v cursor-agent` and `cursor-agent status`
|
|
419
|
+
- `bmalph run --driver cursor` runs the same bash-scoped preflight before the loop starts
|
|
420
|
+
|
|
401
421
|
Run `bmalph run` to start the loop with a live dashboard, or `bmalph run --no-dashboard` for headless mode. Press `Ctrl+C` to stop the loop at any time.
|
|
402
422
|
|
|
403
423
|
## Troubleshooting
|
|
@@ -427,30 +447,48 @@ wsl --install
|
|
|
427
447
|
If you get permission errors:
|
|
428
448
|
|
|
429
449
|
```bash
|
|
430
|
-
#
|
|
431
|
-
|
|
450
|
+
# Claude Code only: broaden the tool allowlist in the managed config
|
|
451
|
+
# .ralph/.ralphrc
|
|
452
|
+
ALLOWED_TOOLS="Write,Read,Edit,MultiEdit,Glob,Grep,Task,TodoWrite,WebFetch,WebSearch,NotebookEdit,Bash"
|
|
453
|
+
|
|
454
|
+
# Keep interactive approval workflows out of unattended Claude loops
|
|
455
|
+
CLAUDE_PERMISSION_MODE="auto"
|
|
432
456
|
|
|
433
|
-
#
|
|
434
|
-
|
|
457
|
+
# Keep the loop unattended by continuing after detected denials
|
|
458
|
+
PERMISSION_DENIAL_MODE="continue"
|
|
459
|
+
|
|
460
|
+
# Reset stale session state and restart
|
|
461
|
+
bash .ralph/ralph_loop.sh --reset-session
|
|
462
|
+
bmalph run
|
|
435
463
|
```
|
|
436
464
|
|
|
465
|
+
Notes:
|
|
466
|
+
|
|
467
|
+
- `ALLOWED_TOOLS` only applies to the Claude Code driver and controls normal tool access.
|
|
468
|
+
- `CLAUDE_PERMISSION_MODE="auto"` prevents interactive approval modes like plan approval from blocking unattended Claude loops.
|
|
469
|
+
- Codex, Cursor, and Copilot use their native sandbox/approval settings instead.
|
|
470
|
+
- Fresh installs default to unattended mode and discourage in-loop user questions via `.ralph/PROMPT.md`.
|
|
471
|
+
|
|
437
472
|
### Common Issues
|
|
438
473
|
|
|
439
|
-
| Scenario | Solution
|
|
440
|
-
| ----------------------------- |
|
|
441
|
-
| Commands fail before init | Run `bmalph init` first
|
|
442
|
-
| Transition finds no stories | Create stories in Phase 3 with `/create-epics-stories`
|
|
443
|
-
| Ralph stops mid-loop | Circuit breaker detected stagnation. Check `.ralph/logs/`
|
|
444
|
-
| Doctor reports version drift | Run `bmalph upgrade` to update bundled assets
|
|
445
|
-
| Wrong platform detected | Re-run `bmalph init --platform <id>` with the correct platform
|
|
446
|
-
| Ralph unavailable on platform | Ralph requires a full tier platform (claude-code, codex, copilot, or cursor)
|
|
474
|
+
| Scenario | Solution |
|
|
475
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
476
|
+
| Commands fail before init | Run `bmalph init` first |
|
|
477
|
+
| Transition finds no stories | Create stories in Phase 3 with `/create-epics-stories`, the matching Codex Skill, or the `_bmad/COMMANDS.md` entry |
|
|
478
|
+
| Ralph stops mid-loop | Circuit breaker detected stagnation. Check `.ralph/logs/` |
|
|
479
|
+
| Doctor reports version drift | Run `bmalph upgrade` to update bundled assets |
|
|
480
|
+
| Wrong platform detected | Re-run `bmalph init --platform <id>` with the correct platform |
|
|
481
|
+
| Ralph unavailable on platform | Ralph requires a full tier platform (claude-code, codex, copilot, or cursor) |
|
|
447
482
|
|
|
448
483
|
### Windows: Cursor Driver
|
|
449
484
|
|
|
450
485
|
`bmalph run --driver cursor` is experimental on Windows and is designed for Git Bash.
|
|
451
486
|
|
|
452
487
|
- `bmalph` prefers a working Git Bash install instead of Windows `bash.exe` shims.
|
|
453
|
-
- The
|
|
488
|
+
- The official binary is `cursor-agent`. The driver also accepts `cursor-agent.cmd`, `agent`, `agent.cmd`, and `%LOCALAPPDATA%\\cursor-agent\\*.cmd` as compatibility fallbacks.
|
|
489
|
+
- The main Ralph loop uses `cursor-agent -p --force --output-format json` and stores Cursor's `session_id` for `--resume` on the next loop.
|
|
490
|
+
- Live display switches to `stream-json`; background execution stays on JSON mode for reliable parsing.
|
|
491
|
+
- Cursor preflight is bash-scoped: `command -v jq`, `command -v cursor-agent`, and `cursor-agent status` must all succeed in the same shell Ralph uses.
|
|
454
492
|
- On Windows, the driver sends Cursor a short bootstrap prompt that tells it to read the Ralph files from `.ralph/` instead of trying to inline the full prompt on the command line.
|
|
455
493
|
|
|
456
494
|
### Reset Installation
|
|
@@ -545,18 +583,33 @@ claude
|
|
|
545
583
|
bmalph run
|
|
546
584
|
```
|
|
547
585
|
|
|
548
|
-
**
|
|
586
|
+
**OpenAI Codex:**
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
# 1. Open your project in your AI coding assistant
|
|
590
|
+
|
|
591
|
+
# 2. Use Codex Skills such as $analyst, $create-prd, and $architect
|
|
592
|
+
# See .agents/skills/ and _bmad/COMMANDS.md for the full catalog
|
|
593
|
+
|
|
594
|
+
# 3. Follow phases: Analysis -> Planning -> Solutioning
|
|
595
|
+
|
|
596
|
+
# 4. Transition to Ralph
|
|
597
|
+
# Run: bmalph implement
|
|
598
|
+
# Then: bmalph run
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
**Cursor, Copilot, Windsurf, Aider:**
|
|
549
602
|
|
|
550
603
|
```bash
|
|
551
604
|
# 1. Open your project in your AI coding assistant
|
|
552
605
|
|
|
553
|
-
# 2.
|
|
554
|
-
#
|
|
606
|
+
# 2. Read _bmad/COMMANDS.md for the available BMAD agents and workflows
|
|
607
|
+
# On Cursor specifically: ask Cursor to run the BMAD master agent
|
|
555
608
|
|
|
556
|
-
# 3.
|
|
557
|
-
#
|
|
609
|
+
# 3. Follow phases: Analysis -> Planning -> Solutioning
|
|
610
|
+
# Or check progress from terminal: bmalph status
|
|
558
611
|
|
|
559
|
-
# 4. For full tier platforms (
|
|
612
|
+
# 4. For full tier platforms (Cursor and Copilot), transition to Ralph:
|
|
560
613
|
# Run: bmalph implement
|
|
561
614
|
# Then: bmalph run
|
|
562
615
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, stat } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { resolveBashCommand } from "../run/ralph-process.js";
|
|
3
|
+
import { resolveBashCommand, runBashCommand } from "../run/ralph-process.js";
|
|
4
4
|
import { readJsonFile } from "../utils/json.js";
|
|
5
5
|
import { isEnoent, formatError } from "../utils/errors.js";
|
|
6
6
|
import { CONFIG_FILE } from "../utils/constants.js";
|
|
@@ -43,12 +43,13 @@ export async function checkBash(_projectDir) {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
export async function checkJq(
|
|
47
|
-
const
|
|
46
|
+
export async function checkJq(projectDir) {
|
|
47
|
+
const result = await runBashCommand("command -v jq", { cwd: projectDir });
|
|
48
|
+
const available = result.exitCode === 0;
|
|
48
49
|
return {
|
|
49
50
|
label: "jq available",
|
|
50
51
|
passed: available,
|
|
51
|
-
detail: available ? undefined : "jq not found in PATH",
|
|
52
|
+
detail: available ? undefined : "jq not found in bash PATH",
|
|
52
53
|
hint: available
|
|
53
54
|
? undefined
|
|
54
55
|
: process.platform === "win32"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-checks.js","sourceRoot":"","sources":["../../src/commands/doctor-checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor-checks.js","sourceRoot":"","sources":["../../src/commands/doctor-checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,OAAe;IACzD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7D,YAAY,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;IAC7D,OAAO;QACL,KAAK,EAAE,oBAAoB;QAC3B,MAAM,EAAE,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QACnF,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,4DAA4D;KAC7F,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,WAAmB;IACjD,IAAI,CAAC;QACH,MAAM,kBAAkB,EAAE,CAAC;QAC3B,OAAO;YACL,KAAK,EAAE,gBAAgB;YACvB,MAAM,EAAE,IAAI;SACb,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EAAE,gBAAgB;YACvB,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC;YACxB,IAAI,EACF,OAAO,CAAC,QAAQ,KAAK,OAAO;gBAC1B,CAAC,CAAC,sFAAsF;gBACxF,CAAC,CAAC,yDAAyD;SAChE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,UAAkB;IAC9C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC;IACxC,OAAO;QACL,KAAK,EAAE,cAAc;QACrB,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,2BAA2B;QAC3D,IAAI,EAAE,SAAS;YACb,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;gBAC5B,CAAC,CAAC,6DAA6D;gBAC/D,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ;oBAC7B,CAAC,CAAC,6BAA6B;oBAC/B,CAAC,CAAC,qCAAqC;KAC9C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAkB;IACnD,OAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,0BAA0B,EAAE,kBAAkB,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAkB;IACrD,OAAO,mBAAmB,CACxB,IAAI,CAAC,UAAU,EAAE,sBAAsB,CAAC,EACxC,uCAAuC,EACvC,qBAAqB,CACtB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB;IACpD,OAAO,QAAQ,CACb,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAC9B,+BAA+B,EAC/B,qBAAqB,CACtB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB;IAClD,MAAM,KAAK,GAAG,qCAAqC,CAAC;IACpD,MAAM,IAAI,GAAG,kBAAkB,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,YAAY,CAAU,IAAI,CAAC,CAAC;QAC/C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;QAClE,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAe,EACf,KAAa,EACb,IAAa;IAEb,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAC7D,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAChB,KAAa,EACb,IAAa;IAEb,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAC7D,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC"}
|
|
@@ -1,83 +1,53 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { getBundledVersions } from "../installer.js";
|
|
4
2
|
import { checkUpstream, getSkipReason } from "../utils/github.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { SESSION_AGE_WARNING_MS, API_USAGE_WARNING_PERCENT
|
|
3
|
+
import { formatError } from "../utils/errors.js";
|
|
4
|
+
import { readRalphCircuitBreaker, readRalphRuntimeSession, readRalphRuntimeStatus, } from "../utils/ralph-runtime-state.js";
|
|
5
|
+
import { SESSION_AGE_WARNING_MS, API_USAGE_WARNING_PERCENT } from "../utils/constants.js";
|
|
8
6
|
export async function checkCircuitBreaker(projectDir) {
|
|
9
7
|
const label = "circuit breaker";
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (state.state === "CLOSED") {
|
|
16
|
-
const detail = `CLOSED (${state.consecutive_no_progress} loops without progress)`;
|
|
17
|
-
return { label, passed: true, detail };
|
|
18
|
-
}
|
|
19
|
-
if (state.state === "HALF_OPEN") {
|
|
20
|
-
return { label, passed: true, detail: `HALF_OPEN - monitoring` };
|
|
21
|
-
}
|
|
22
|
-
const detail = `OPEN - ${state.reason ?? "stagnation detected"}`;
|
|
8
|
+
const result = await readRalphCircuitBreaker(projectDir);
|
|
9
|
+
if (result.kind === "missing") {
|
|
10
|
+
return { label, passed: true, detail: "not running" };
|
|
11
|
+
}
|
|
12
|
+
if (result.kind === "invalid") {
|
|
23
13
|
return {
|
|
24
14
|
label,
|
|
25
15
|
passed: false,
|
|
26
|
-
detail,
|
|
27
|
-
hint: "
|
|
16
|
+
detail: "corrupt state file",
|
|
17
|
+
hint: "Delete .ralph/.circuit_breaker_state and restart Ralph",
|
|
28
18
|
};
|
|
29
19
|
}
|
|
30
|
-
|
|
31
|
-
if (isEnoent(err)) {
|
|
32
|
-
return { label, passed: true, detail: "not running" };
|
|
33
|
-
}
|
|
20
|
+
if (result.kind === "unreadable") {
|
|
34
21
|
return {
|
|
35
22
|
label,
|
|
36
23
|
passed: false,
|
|
37
|
-
detail: "
|
|
38
|
-
hint: "
|
|
24
|
+
detail: "unreadable state file",
|
|
25
|
+
hint: "Check file permissions or locks on .ralph/.circuit_breaker_state and restart Ralph",
|
|
39
26
|
};
|
|
40
27
|
}
|
|
28
|
+
const state = result.value;
|
|
29
|
+
if (state.state === "CLOSED") {
|
|
30
|
+
const detail = `CLOSED (${state.consecutiveNoProgress} loops without progress)`;
|
|
31
|
+
return { label, passed: true, detail };
|
|
32
|
+
}
|
|
33
|
+
if (state.state === "HALF_OPEN") {
|
|
34
|
+
return { label, passed: true, detail: "HALF_OPEN - monitoring" };
|
|
35
|
+
}
|
|
36
|
+
const detail = `OPEN - ${state.reason ?? "stagnation detected"}`;
|
|
37
|
+
return {
|
|
38
|
+
label,
|
|
39
|
+
passed: false,
|
|
40
|
+
detail,
|
|
41
|
+
hint: "Ralph detected stagnation. Review logs with: bmalph status",
|
|
42
|
+
};
|
|
41
43
|
}
|
|
42
44
|
export async function checkRalphSession(projectDir) {
|
|
43
45
|
const label = "Ralph session";
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const parsed = JSON.parse(content);
|
|
48
|
-
const session = validateRalphSession(parsed);
|
|
49
|
-
if (!session.session_id || session.session_id === "") {
|
|
50
|
-
return { label, passed: true, detail: "no active session" };
|
|
51
|
-
}
|
|
52
|
-
const createdAt = new Date(session.created_at);
|
|
53
|
-
const now = new Date();
|
|
54
|
-
const ageMs = now.getTime() - createdAt.getTime();
|
|
55
|
-
if (ageMs < 0) {
|
|
56
|
-
return {
|
|
57
|
-
label,
|
|
58
|
-
passed: false,
|
|
59
|
-
detail: "invalid timestamp (future)",
|
|
60
|
-
hint: "Delete .ralph/.ralph_session to reset",
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
const ageHours = Math.floor(ageMs / (1000 * 60 * 60));
|
|
64
|
-
const ageMinutes = Math.floor((ageMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
65
|
-
const ageStr = ageHours > 0 ? `${ageHours}h${ageMinutes}m` : `${ageMinutes}m`;
|
|
66
|
-
const maxAgeHours = Math.floor(SESSION_AGE_WARNING_MS / (1000 * 60 * 60));
|
|
67
|
-
if (ageMs >= SESSION_AGE_WARNING_MS) {
|
|
68
|
-
return {
|
|
69
|
-
label,
|
|
70
|
-
passed: false,
|
|
71
|
-
detail: `${ageStr} old (max ${maxAgeHours}h)`,
|
|
72
|
-
hint: "Session is stale. Start a fresh Ralph session",
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
return { label, passed: true, detail: ageStr };
|
|
46
|
+
const result = await readRalphRuntimeSession(projectDir);
|
|
47
|
+
if (result.kind === "missing") {
|
|
48
|
+
return { label, passed: true, detail: "no active session" };
|
|
76
49
|
}
|
|
77
|
-
|
|
78
|
-
if (isEnoent(err)) {
|
|
79
|
-
return { label, passed: true, detail: "no active session" };
|
|
80
|
-
}
|
|
50
|
+
if (result.kind === "invalid") {
|
|
81
51
|
return {
|
|
82
52
|
label,
|
|
83
53
|
passed: false,
|
|
@@ -85,34 +55,59 @@ export async function checkRalphSession(projectDir) {
|
|
|
85
55
|
hint: "Delete .ralph/.ralph_session to reset",
|
|
86
56
|
};
|
|
87
57
|
}
|
|
58
|
+
if (result.kind === "unreadable") {
|
|
59
|
+
return {
|
|
60
|
+
label,
|
|
61
|
+
passed: false,
|
|
62
|
+
detail: "unreadable session file",
|
|
63
|
+
hint: "Check file permissions or locks on .ralph/.ralph_session and retry",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const session = result.value;
|
|
67
|
+
if (session.kind === "inactive") {
|
|
68
|
+
return { label, passed: true, detail: "no active session" };
|
|
69
|
+
}
|
|
70
|
+
const createdAt = new Date(session.created_at);
|
|
71
|
+
const createdAtMs = createdAt.getTime();
|
|
72
|
+
if (Number.isNaN(createdAtMs)) {
|
|
73
|
+
return {
|
|
74
|
+
label,
|
|
75
|
+
passed: false,
|
|
76
|
+
detail: "invalid timestamp",
|
|
77
|
+
hint: "Delete .ralph/.ralph_session to reset",
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const now = new Date();
|
|
81
|
+
const ageMs = now.getTime() - createdAtMs;
|
|
82
|
+
if (ageMs < 0) {
|
|
83
|
+
return {
|
|
84
|
+
label,
|
|
85
|
+
passed: false,
|
|
86
|
+
detail: "invalid timestamp (future)",
|
|
87
|
+
hint: "Delete .ralph/.ralph_session to reset",
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const ageHours = Math.floor(ageMs / (1000 * 60 * 60));
|
|
91
|
+
const ageMinutes = Math.floor((ageMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
92
|
+
const ageStr = ageHours > 0 ? `${ageHours}h${ageMinutes}m` : `${ageMinutes}m`;
|
|
93
|
+
const maxAgeHours = Math.floor(SESSION_AGE_WARNING_MS / (1000 * 60 * 60));
|
|
94
|
+
if (ageMs >= SESSION_AGE_WARNING_MS) {
|
|
95
|
+
return {
|
|
96
|
+
label,
|
|
97
|
+
passed: false,
|
|
98
|
+
detail: `${ageStr} old (max ${maxAgeHours}h)`,
|
|
99
|
+
hint: "Session is stale. Start a fresh Ralph session",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return { label, passed: true, detail: ageStr };
|
|
88
103
|
}
|
|
89
104
|
export async function checkApiCalls(projectDir) {
|
|
90
105
|
const label = "API calls this hour";
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const parsed = JSON.parse(content);
|
|
95
|
-
const status = validateRalphApiStatus(parsed);
|
|
96
|
-
const calls = status.calls_made_this_hour;
|
|
97
|
-
const max = status.max_calls_per_hour;
|
|
98
|
-
if (max <= 0) {
|
|
99
|
-
return { label, passed: true, detail: `${calls}/unlimited` };
|
|
100
|
-
}
|
|
101
|
-
const percentage = (calls / max) * 100;
|
|
102
|
-
if (percentage >= API_USAGE_WARNING_PERCENT) {
|
|
103
|
-
return {
|
|
104
|
-
label,
|
|
105
|
-
passed: false,
|
|
106
|
-
detail: `${calls}/${max} (approaching limit)`,
|
|
107
|
-
hint: "Wait for rate limit reset or increase API quota",
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
return { label, passed: true, detail: `${calls}/${max}` };
|
|
106
|
+
const result = await readRalphRuntimeStatus(projectDir);
|
|
107
|
+
if (result.kind === "missing") {
|
|
108
|
+
return { label, passed: true, detail: "not running" };
|
|
111
109
|
}
|
|
112
|
-
|
|
113
|
-
if (isEnoent(err)) {
|
|
114
|
-
return { label, passed: true, detail: "not running" };
|
|
115
|
-
}
|
|
110
|
+
if (result.kind === "invalid") {
|
|
116
111
|
return {
|
|
117
112
|
label,
|
|
118
113
|
passed: false,
|
|
@@ -120,6 +115,29 @@ export async function checkApiCalls(projectDir) {
|
|
|
120
115
|
hint: "Delete .ralph/status.json to reset",
|
|
121
116
|
};
|
|
122
117
|
}
|
|
118
|
+
if (result.kind === "unreadable") {
|
|
119
|
+
return {
|
|
120
|
+
label,
|
|
121
|
+
passed: false,
|
|
122
|
+
detail: "unreadable status file",
|
|
123
|
+
hint: "Check file permissions or locks on .ralph/status.json and retry",
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const calls = result.value.callsMadeThisHour;
|
|
127
|
+
const max = result.value.maxCallsPerHour;
|
|
128
|
+
if (max <= 0) {
|
|
129
|
+
return { label, passed: true, detail: `${calls}/unlimited` };
|
|
130
|
+
}
|
|
131
|
+
const percentage = (calls / max) * 100;
|
|
132
|
+
if (percentage >= API_USAGE_WARNING_PERCENT) {
|
|
133
|
+
return {
|
|
134
|
+
label,
|
|
135
|
+
passed: false,
|
|
136
|
+
detail: `${calls}/${max} (approaching limit)`,
|
|
137
|
+
hint: "Wait for rate limit reset or increase API quota",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return { label, passed: true, detail: `${calls}/${max}` };
|
|
123
141
|
}
|
|
124
142
|
export async function checkUpstreamGitHubStatus(_projectDir) {
|
|
125
143
|
const label = "upstream status";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-runtime-checks.js","sourceRoot":"","sources":["../../src/commands/doctor-runtime-checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"doctor-runtime-checks.js","sourceRoot":"","sources":["../../src/commands/doctor-runtime-checks.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/run.js
CHANGED
|
@@ -2,6 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { readConfig } from "../utils/config.js";
|
|
3
3
|
import { withErrorHandling } from "../utils/errors.js";
|
|
4
4
|
import { isPlatformId, getPlatform, getFullTierPlatformNames } from "../platform/registry.js";
|
|
5
|
+
import { validateCursorRuntime } from "../platform/cursor-runtime-checks.js";
|
|
5
6
|
import { validateBashAvailable, validateRalphLoop, spawnRalphLoop } from "../run/ralph-process.js";
|
|
6
7
|
import { startRunDashboard } from "../run/run-dashboard.js";
|
|
7
8
|
import { parseInterval } from "../utils/validate.js";
|
|
@@ -24,6 +25,9 @@ async function executeRun(options) {
|
|
|
24
25
|
}
|
|
25
26
|
const interval = parseInterval(options.interval);
|
|
26
27
|
await Promise.all([validateBashAvailable(), validateRalphLoop(projectDir)]);
|
|
28
|
+
if (platform.id === "cursor") {
|
|
29
|
+
await validateCursorRuntime(projectDir);
|
|
30
|
+
}
|
|
27
31
|
const ralph = spawnRalphLoop(projectDir, platform.id, {
|
|
28
32
|
inheritStdio: !dashboard,
|
|
29
33
|
});
|
package/dist/commands/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAUrD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAA0B;IACzD,MAAM,iBAAiB,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAA0B;IAClD,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE1C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClE,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,wCAAwC,wBAAwB,EAAE,KAAK;YACrE,YAAY,QAAQ,CAAC,WAAW,EAAE,CACrC,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,QAAQ,CAAC,WAAW,0BAA0B,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEjD,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,qBAAqB,EAAE,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/status.js
CHANGED
|
@@ -7,6 +7,9 @@ import { ARTIFACT_DEFINITIONS } from "../utils/artifact-definitions.js";
|
|
|
7
7
|
import { resolveProjectPlatform } from "../platform/resolve.js";
|
|
8
8
|
import { getFullTierPlatformNames } from "../platform/registry.js";
|
|
9
9
|
import { scanProjectArtifacts } from "../transition/artifact-scan.js";
|
|
10
|
+
function getCursorNextAction() {
|
|
11
|
+
return "Read _bmad/COMMANDS.md and ask Cursor to run the BMAD master agent";
|
|
12
|
+
}
|
|
10
13
|
export async function statusCommand(options) {
|
|
11
14
|
await withErrorHandling(() => runStatus(options));
|
|
12
15
|
}
|
|
@@ -27,12 +30,14 @@ export async function runStatus(options) {
|
|
|
27
30
|
if (storedPhase === 4) {
|
|
28
31
|
ralphStatus = await readRalphStatus(projectDir);
|
|
29
32
|
}
|
|
33
|
+
// Resolve platform for next action hints
|
|
34
|
+
const platform = await resolveProjectPlatform(projectDir);
|
|
30
35
|
// Scan artifacts for phases 1-3 to detect actual progress
|
|
31
36
|
let artifactScan = null;
|
|
32
37
|
let phase = storedPhase;
|
|
33
38
|
let phaseDetected = false;
|
|
34
39
|
if (phase < 4) {
|
|
35
|
-
artifactScan = await scanProjectArtifacts(projectDir);
|
|
40
|
+
artifactScan = await scanProjectArtifacts(projectDir, platform.id);
|
|
36
41
|
if (artifactScan && artifactScan.detectedPhase > phase) {
|
|
37
42
|
phase = artifactScan.detectedPhase;
|
|
38
43
|
phaseDetected = true;
|
|
@@ -40,8 +45,6 @@ export async function runStatus(options) {
|
|
|
40
45
|
}
|
|
41
46
|
const phaseName = getPhaseLabel(phase);
|
|
42
47
|
const phaseInfo = getPhaseInfo(phase);
|
|
43
|
-
// Resolve platform for next action hints
|
|
44
|
-
const platform = await resolveProjectPlatform(projectDir);
|
|
45
48
|
// Determine next action — use artifact-based suggestion when available
|
|
46
49
|
const nextAction = artifactScan && phaseDetected
|
|
47
50
|
? artifactScan.nextAction
|
|
@@ -147,8 +150,14 @@ function getNextAction(phase, status, ralphStatus, platform) {
|
|
|
147
150
|
}
|
|
148
151
|
switch (phase) {
|
|
149
152
|
case 1:
|
|
153
|
+
if (platform.id === "cursor") {
|
|
154
|
+
return getCursorNextAction();
|
|
155
|
+
}
|
|
150
156
|
return "Run /analyst to start analysis";
|
|
151
157
|
case 2:
|
|
158
|
+
if (platform.id === "cursor") {
|
|
159
|
+
return getCursorNextAction();
|
|
160
|
+
}
|
|
152
161
|
return "Run /pm to create PRD";
|
|
153
162
|
case 3:
|
|
154
163
|
return "Run: bmalph implement";
|