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.
Files changed (73) hide show
  1. package/README.md +87 -34
  2. package/dist/commands/doctor-checks.js +5 -4
  3. package/dist/commands/doctor-checks.js.map +1 -1
  4. package/dist/commands/doctor-runtime-checks.js +104 -86
  5. package/dist/commands/doctor-runtime-checks.js.map +1 -1
  6. package/dist/commands/run.js +4 -0
  7. package/dist/commands/run.js.map +1 -1
  8. package/dist/commands/status.js +12 -3
  9. package/dist/commands/status.js.map +1 -1
  10. package/dist/installer/bmad-assets.js +182 -0
  11. package/dist/installer/bmad-assets.js.map +1 -0
  12. package/dist/installer/commands.js +324 -0
  13. package/dist/installer/commands.js.map +1 -0
  14. package/dist/installer/install.js +42 -0
  15. package/dist/installer/install.js.map +1 -0
  16. package/dist/installer/metadata.js +56 -0
  17. package/dist/installer/metadata.js.map +1 -0
  18. package/dist/installer/project-files.js +169 -0
  19. package/dist/installer/project-files.js.map +1 -0
  20. package/dist/installer/ralph-assets.js +91 -0
  21. package/dist/installer/ralph-assets.js.map +1 -0
  22. package/dist/installer/template-files.js +168 -0
  23. package/dist/installer/template-files.js.map +1 -0
  24. package/dist/installer/types.js +2 -0
  25. package/dist/installer/types.js.map +1 -0
  26. package/dist/installer.js +5 -790
  27. package/dist/installer.js.map +1 -1
  28. package/dist/platform/cursor-runtime-checks.js +81 -0
  29. package/dist/platform/cursor-runtime-checks.js.map +1 -0
  30. package/dist/platform/cursor.js +4 -3
  31. package/dist/platform/cursor.js.map +1 -1
  32. package/dist/platform/detect.js +28 -5
  33. package/dist/platform/detect.js.map +1 -1
  34. package/dist/platform/instructions-snippet.js +18 -0
  35. package/dist/platform/instructions-snippet.js.map +1 -1
  36. package/dist/platform/resolve.js +23 -5
  37. package/dist/platform/resolve.js.map +1 -1
  38. package/dist/run/ralph-process.js +84 -15
  39. package/dist/run/ralph-process.js.map +1 -1
  40. package/dist/transition/artifact-loading.js +91 -0
  41. package/dist/transition/artifact-loading.js.map +1 -0
  42. package/dist/transition/artifact-scan.js +15 -3
  43. package/dist/transition/artifact-scan.js.map +1 -1
  44. package/dist/transition/context-output.js +85 -0
  45. package/dist/transition/context-output.js.map +1 -0
  46. package/dist/transition/fix-plan-sync.js +119 -0
  47. package/dist/transition/fix-plan-sync.js.map +1 -0
  48. package/dist/transition/orchestration.js +25 -362
  49. package/dist/transition/orchestration.js.map +1 -1
  50. package/dist/transition/specs-sync.js +78 -2
  51. package/dist/transition/specs-sync.js.map +1 -1
  52. package/dist/utils/ralph-runtime-state.js +222 -0
  53. package/dist/utils/ralph-runtime-state.js.map +1 -0
  54. package/dist/utils/state.js +17 -16
  55. package/dist/utils/state.js.map +1 -1
  56. package/dist/utils/validate.js +16 -0
  57. package/dist/utils/validate.js.map +1 -1
  58. package/dist/watch/renderer.js +48 -6
  59. package/dist/watch/renderer.js.map +1 -1
  60. package/dist/watch/state-reader.js +79 -44
  61. package/dist/watch/state-reader.js.map +1 -1
  62. package/package.json +1 -1
  63. package/ralph/RALPH-REFERENCE.md +60 -16
  64. package/ralph/drivers/claude-code.sh +25 -0
  65. package/ralph/drivers/codex.sh +11 -0
  66. package/ralph/drivers/copilot.sh +11 -0
  67. package/ralph/drivers/cursor.sh +58 -29
  68. package/ralph/lib/circuit_breaker.sh +3 -3
  69. package/ralph/lib/date_utils.sh +28 -9
  70. package/ralph/lib/response_analyzer.sh +220 -17
  71. package/ralph/ralph_loop.sh +464 -121
  72. package/ralph/templates/PROMPT.md +5 -0
  73. package/ralph/templates/ralphrc.template +14 -4
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![CI](https://github.com/LarsCowe/bmalph/actions/workflows/ci.yml/badge.svg)](https://github.com/LarsCowe/bmalph/actions/workflows/ci.yml)
8
8
  [![codecov](https://codecov.io/gh/LarsCowe/bmalph/branch/main/graph/badge.svg)](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, glued by slash commands.
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 or prompts interactively
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
- - Installs slash commands for supported platforms (Claude Code: `.claude/commands/` directory; Codex: `.agents/skills/`; other platforms: `_bmad/COMMANDS.md` reference index)
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. On Claude Code, use the `/bmalph` slash command to see your current phase and available commands. On other platforms, ask the agent about BMAD phases or run `bmalph status` in terminal.
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 (`/validate-brief`, `/validate-prd`, `/validate-ux`, `/validate-architecture`, `/validate-epics-stories`) run the same workflow in Validate mode.
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
- - `/bmad-help` — list all available commands
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
- ## Slash Commands
295
+ ## Command Delivery
288
296
 
289
- bmalph installs 51 slash commands (45 BMAD + 6 bmalph). Command delivery varies by platform:
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, Windsurf, Copilot, Aider** — discoverable via `_bmad/COMMANDS.md` reference index
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, run `/bmad-help` in Claude Code.
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
- │ ├── _config/ # Generated configuration
326
- ├── config.yaml # Platform config
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` and session resume
384
- - **Codex driver** — invokes `codex exec` with `--sandbox workspace-write`
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 --print --force` (or compatible `agent` installs) with NDJSON streaming
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
- # Unix/Mac: Make driver scripts executable
431
- chmod +x .ralph/drivers/*.sh
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
- # Check file ownership
434
- ls -la .ralph/
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 Cursor driver detects `cursor-agent`, `cursor-agent.cmd`, `agent`, `agent.cmd`, and `%LOCALAPPDATA%\\cursor-agent\\agent.cmd`.
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
- **Other platforms:**
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. Ask the agent about BMAD phases to start planning
554
- # Or check status from terminal: bmalph status
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. Reference BMAD agents by name (analyst, pm, architect)
557
- # Follow phases: Analysis Planning Solutioning
609
+ # 3. Follow phases: Analysis -> Planning -> Solutioning
610
+ # Or check progress from terminal: bmalph status
558
611
 
559
- # 4. For full tier platforms (Codex, Copilot, Cursor), transition to Ralph:
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(_projectDir) {
47
- const available = await checkCommandAvailable("jq");
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":"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"}
1
+ {"version":3,"file":"doctor-checks.js","sourceRoot":"","sources":["../../src/commands/doctor-checks.ts"],"names":[],"mappings":"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"}
@@ -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 { isEnoent, formatError } from "../utils/errors.js";
6
- import { validateCircuitBreakerState, validateRalphSession, validateRalphApiStatus, } from "../utils/validate.js";
7
- import { SESSION_AGE_WARNING_MS, API_USAGE_WARNING_PERCENT, RALPH_STATUS_FILE, } from "../utils/constants.js";
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 statePath = join(projectDir, ".ralph/.circuit_breaker_state");
11
- try {
12
- const content = await readFile(statePath, "utf-8");
13
- const parsed = JSON.parse(content);
14
- const state = validateCircuitBreakerState(parsed);
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: "Ralph detected stagnation. Review logs with: bmalph status",
16
+ detail: "corrupt state file",
17
+ hint: "Delete .ralph/.circuit_breaker_state and restart Ralph",
28
18
  };
29
19
  }
30
- catch (err) {
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: "corrupt state file",
38
- hint: "Delete .ralph/.circuit_breaker_state and restart Ralph",
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 sessionPath = join(projectDir, ".ralph/.ralph_session");
45
- try {
46
- const content = await readFile(sessionPath, "utf-8");
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
- catch (err) {
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 statusPath = join(projectDir, RALPH_STATUS_FILE);
92
- try {
93
- const content = await readFile(statusPath, "utf-8");
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
- catch (err) {
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":"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"}
1
+ {"version":3,"file":"doctor-runtime-checks.js","sourceRoot":"","sources":["../../src/commands/doctor-runtime-checks.ts"],"names":[],"mappings":"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"}
@@ -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
  });
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -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";