bmalph 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +111 -30
  2. package/bundled-versions.json +1 -2
  3. package/dist/cli.js +3 -2
  4. package/dist/commands/check-updates.js +5 -27
  5. package/dist/commands/doctor.d.ts +14 -2
  6. package/dist/commands/doctor.js +99 -56
  7. package/dist/commands/init.d.ts +1 -0
  8. package/dist/commands/init.js +75 -9
  9. package/dist/commands/upgrade.js +8 -5
  10. package/dist/installer.d.ts +16 -5
  11. package/dist/installer.js +245 -128
  12. package/dist/platform/aider.d.ts +2 -0
  13. package/dist/platform/aider.js +71 -0
  14. package/dist/platform/claude-code.d.ts +2 -0
  15. package/dist/platform/claude-code.js +88 -0
  16. package/dist/platform/codex.d.ts +2 -0
  17. package/dist/platform/codex.js +67 -0
  18. package/dist/platform/copilot.d.ts +2 -0
  19. package/dist/platform/copilot.js +71 -0
  20. package/dist/platform/cursor.d.ts +2 -0
  21. package/dist/platform/cursor.js +71 -0
  22. package/dist/platform/detect.d.ts +7 -0
  23. package/dist/platform/detect.js +23 -0
  24. package/dist/platform/index.d.ts +4 -0
  25. package/dist/platform/index.js +3 -0
  26. package/dist/platform/registry.d.ts +4 -0
  27. package/dist/platform/registry.js +27 -0
  28. package/dist/platform/resolve.d.ts +8 -0
  29. package/dist/platform/resolve.js +24 -0
  30. package/dist/platform/types.d.ts +41 -0
  31. package/dist/platform/types.js +7 -0
  32. package/dist/platform/windsurf.d.ts +2 -0
  33. package/dist/platform/windsurf.js +71 -0
  34. package/dist/transition/artifacts.js +1 -1
  35. package/dist/transition/fix-plan.d.ts +1 -1
  36. package/dist/transition/fix-plan.js +3 -2
  37. package/dist/transition/orchestration.js +1 -1
  38. package/dist/transition/specs-changelog.js +4 -1
  39. package/dist/transition/specs-index.js +2 -3
  40. package/dist/utils/config.d.ts +2 -1
  41. package/dist/utils/errors.js +3 -0
  42. package/dist/utils/github.d.ts +0 -1
  43. package/dist/utils/github.js +1 -18
  44. package/dist/utils/json.js +2 -2
  45. package/dist/utils/state.js +7 -1
  46. package/dist/utils/validate.d.ts +1 -0
  47. package/dist/utils/validate.js +35 -4
  48. package/package.json +4 -4
  49. package/ralph/drivers/claude-code.sh +118 -0
  50. package/ralph/drivers/codex.sh +81 -0
  51. package/ralph/ralph_import.sh +11 -0
  52. package/ralph/ralph_loop.sh +37 -64
  53. package/ralph/templates/ralphrc.template +7 -0
@@ -0,0 +1,88 @@
1
+ import { readFile } from "fs/promises";
2
+ import { join } from "path";
3
+ import { exists } from "../utils/file-system.js";
4
+ import { isEnoent, formatError } from "../utils/errors.js";
5
+ export const claudeCodePlatform = {
6
+ id: "claude-code",
7
+ displayName: "Claude Code",
8
+ tier: "full",
9
+ instructionsFile: "CLAUDE.md",
10
+ commandDelivery: { kind: "directory", dir: ".claude/commands" },
11
+ instructionsSectionMarker: "## BMAD-METHOD Integration",
12
+ generateInstructionsSnippet: () => `
13
+ ## BMAD-METHOD Integration
14
+
15
+ Use \`/bmalph\` to navigate phases. Use \`/bmad-help\` to discover all commands. Use \`/bmalph-status\` for a quick overview.
16
+
17
+ ### Phases
18
+
19
+ | Phase | Focus | Key Commands |
20
+ |-------|-------|-------------|
21
+ | 1. Analysis | Understand the problem | \`/create-brief\`, \`/brainstorm-project\`, \`/market-research\` |
22
+ | 2. Planning | Define the solution | \`/create-prd\`, \`/create-ux\` |
23
+ | 3. Solutioning | Design the architecture | \`/create-architecture\`, \`/create-epics-stories\`, \`/implementation-readiness\` |
24
+ | 4. Implementation | Build it | \`/sprint-planning\`, \`/create-story\`, then \`/bmalph-implement\` for Ralph |
25
+
26
+ ### Workflow
27
+
28
+ 1. Work through Phases 1-3 using BMAD agents and workflows (interactive, command-driven)
29
+ 2. Run \`/bmalph-implement\` to transition planning artifacts into Ralph format, then start Ralph
30
+
31
+ ### Management Commands
32
+
33
+ | Command | Description |
34
+ |---------|-------------|
35
+ | \`/bmalph-status\` | Show current phase, Ralph progress, version info |
36
+ | \`/bmalph-implement\` | Transition planning artifacts → prepare Ralph loop |
37
+ | \`/bmalph-upgrade\` | Update bundled assets to match current bmalph version |
38
+ | \`/bmalph-doctor\` | Check project health and report issues |
39
+ | \`/bmalph-reset\` | Reset state (soft or hard reset with confirmation) |
40
+
41
+ ### Available Agents
42
+
43
+ | Command | Agent | Role |
44
+ |---------|-------|------|
45
+ | \`/analyst\` | Analyst | Research, briefs, discovery |
46
+ | \`/architect\` | Architect | Technical design, architecture |
47
+ | \`/pm\` | Product Manager | PRDs, epics, stories |
48
+ | \`/sm\` | Scrum Master | Sprint planning, status, coordination |
49
+ | \`/dev\` | Developer | Implementation, coding |
50
+ | \`/ux-designer\` | UX Designer | User experience, wireframes |
51
+ | \`/qa\` | QA Engineer | Test automation, quality assurance |
52
+ `,
53
+ getDoctorChecks: () => [
54
+ {
55
+ id: "slash-command",
56
+ label: ".claude/commands/bmalph.md present",
57
+ check: async (projectDir) => {
58
+ if (await exists(join(projectDir, ".claude/commands/bmalph.md"))) {
59
+ return { passed: true };
60
+ }
61
+ return { passed: false, detail: "not found", hint: "Run: bmalph init" };
62
+ },
63
+ },
64
+ {
65
+ id: "instructions-file",
66
+ label: "CLAUDE.md contains BMAD snippet",
67
+ check: async (projectDir) => {
68
+ try {
69
+ const content = await readFile(join(projectDir, "CLAUDE.md"), "utf-8");
70
+ if (content.includes("BMAD-METHOD Integration")) {
71
+ return { passed: true };
72
+ }
73
+ return {
74
+ passed: false,
75
+ detail: "missing BMAD-METHOD Integration section",
76
+ hint: "Run: bmalph init",
77
+ };
78
+ }
79
+ catch (err) {
80
+ if (isEnoent(err)) {
81
+ return { passed: false, detail: "CLAUDE.md not found", hint: "Run: bmalph init" };
82
+ }
83
+ return { passed: false, detail: formatError(err), hint: "Check file permissions" };
84
+ }
85
+ },
86
+ },
87
+ ],
88
+ };
@@ -0,0 +1,2 @@
1
+ import type { Platform } from "./types.js";
2
+ export declare const codexPlatform: Platform;
@@ -0,0 +1,67 @@
1
+ import { readFile } from "fs/promises";
2
+ import { join } from "path";
3
+ import { isEnoent, formatError } from "../utils/errors.js";
4
+ export const codexPlatform = {
5
+ id: "codex",
6
+ displayName: "OpenAI Codex",
7
+ tier: "full",
8
+ instructionsFile: "AGENTS.md",
9
+ commandDelivery: { kind: "inline" },
10
+ instructionsSectionMarker: "## BMAD-METHOD Integration",
11
+ generateInstructionsSnippet: () => `
12
+ ## BMAD-METHOD Integration
13
+
14
+ Run the BMAD master agent to navigate phases. Ask for help to discover all available agents and workflows.
15
+
16
+ ### Phases
17
+
18
+ | Phase | Focus | Key Agents |
19
+ |-------|-------|-----------|
20
+ | 1. Analysis | Understand the problem | Analyst agent |
21
+ | 2. Planning | Define the solution | Product Manager agent |
22
+ | 3. Solutioning | Design the architecture | Architect agent |
23
+ | 4. Implementation | Build it | Developer agent, then Ralph autonomous loop |
24
+
25
+ ### Workflow
26
+
27
+ 1. Work through Phases 1-3 using BMAD agents and workflows
28
+ 2. Use the bmalph-implement transition to prepare Ralph format, then start Ralph
29
+
30
+ ### Available Agents
31
+
32
+ | Agent | Role |
33
+ |-------|------|
34
+ | Analyst | Research, briefs, discovery |
35
+ | Architect | Technical design, architecture |
36
+ | Product Manager | PRDs, epics, stories |
37
+ | Scrum Master | Sprint planning, status, coordination |
38
+ | Developer | Implementation, coding |
39
+ | UX Designer | User experience, wireframes |
40
+ | QA Engineer | Test automation, quality assurance |
41
+ `,
42
+ getDoctorChecks: () => [
43
+ {
44
+ id: "instructions-file",
45
+ label: "AGENTS.md contains BMAD snippet",
46
+ check: async (projectDir) => {
47
+ try {
48
+ const content = await readFile(join(projectDir, "AGENTS.md"), "utf-8");
49
+ if (content.includes("BMAD-METHOD Integration")) {
50
+ return { passed: true };
51
+ }
52
+ return {
53
+ passed: false,
54
+ detail: "missing BMAD-METHOD Integration section",
55
+ hint: "Run: bmalph init",
56
+ };
57
+ }
58
+ catch (err) {
59
+ if (isEnoent(err)) {
60
+ return { passed: false, detail: "AGENTS.md not found", hint: "Run: bmalph init" };
61
+ }
62
+ return { passed: false, detail: formatError(err), hint: "Check file permissions" };
63
+ }
64
+ },
65
+ },
66
+ ],
67
+ };
@@ -0,0 +1,2 @@
1
+ import type { Platform } from "./types.js";
2
+ export declare const copilotPlatform: Platform;
@@ -0,0 +1,71 @@
1
+ import { readFile } from "fs/promises";
2
+ import { join } from "path";
3
+ import { isEnoent, formatError } from "../utils/errors.js";
4
+ export const copilotPlatform = {
5
+ id: "copilot",
6
+ displayName: "GitHub Copilot",
7
+ tier: "instructions-only",
8
+ instructionsFile: ".github/copilot-instructions.md",
9
+ commandDelivery: { kind: "none" },
10
+ instructionsSectionMarker: "## BMAD-METHOD Integration",
11
+ generateInstructionsSnippet: () => `
12
+ ## BMAD-METHOD Integration
13
+
14
+ Ask the BMAD master agent to navigate phases. Ask for help to discover all available agents and workflows.
15
+
16
+ ### Phases
17
+
18
+ | Phase | Focus | Key Agents |
19
+ |-------|-------|-----------|
20
+ | 1. Analysis | Understand the problem | Analyst agent |
21
+ | 2. Planning | Define the solution | Product Manager agent |
22
+ | 3. Solutioning | Design the architecture | Architect agent |
23
+
24
+ ### Workflow
25
+
26
+ Work through Phases 1-3 using BMAD agents and workflows interactively.
27
+
28
+ > **Note:** Ralph (Phase 4 — autonomous implementation) is not supported on this platform.
29
+
30
+ ### Available Agents
31
+
32
+ | Agent | Role |
33
+ |-------|------|
34
+ | Analyst | Research, briefs, discovery |
35
+ | Architect | Technical design, architecture |
36
+ | Product Manager | PRDs, epics, stories |
37
+ | Scrum Master | Sprint planning, status, coordination |
38
+ | Developer | Implementation, coding |
39
+ | UX Designer | User experience, wireframes |
40
+ | QA Engineer | Test automation, quality assurance |
41
+ `,
42
+ getDoctorChecks: () => [
43
+ {
44
+ id: "instructions-file",
45
+ label: ".github/copilot-instructions.md contains BMAD snippet",
46
+ check: async (projectDir) => {
47
+ try {
48
+ const content = await readFile(join(projectDir, ".github/copilot-instructions.md"), "utf-8");
49
+ if (content.includes("BMAD-METHOD Integration")) {
50
+ return { passed: true };
51
+ }
52
+ return {
53
+ passed: false,
54
+ detail: "missing BMAD-METHOD Integration section",
55
+ hint: "Run: bmalph init",
56
+ };
57
+ }
58
+ catch (err) {
59
+ if (isEnoent(err)) {
60
+ return {
61
+ passed: false,
62
+ detail: ".github/copilot-instructions.md not found",
63
+ hint: "Run: bmalph init",
64
+ };
65
+ }
66
+ return { passed: false, detail: formatError(err), hint: "Check file permissions" };
67
+ }
68
+ },
69
+ },
70
+ ],
71
+ };
@@ -0,0 +1,2 @@
1
+ import type { Platform } from "./types.js";
2
+ export declare const cursorPlatform: Platform;
@@ -0,0 +1,71 @@
1
+ import { readFile } from "fs/promises";
2
+ import { join } from "path";
3
+ import { isEnoent, formatError } from "../utils/errors.js";
4
+ export const cursorPlatform = {
5
+ id: "cursor",
6
+ displayName: "Cursor",
7
+ tier: "instructions-only",
8
+ instructionsFile: ".cursor/rules/bmad.mdc",
9
+ commandDelivery: { kind: "none" },
10
+ instructionsSectionMarker: "## BMAD-METHOD Integration",
11
+ generateInstructionsSnippet: () => `
12
+ ## BMAD-METHOD Integration
13
+
14
+ Ask the BMAD master agent to navigate phases. Ask for help to discover all available agents and workflows.
15
+
16
+ ### Phases
17
+
18
+ | Phase | Focus | Key Agents |
19
+ |-------|-------|-----------|
20
+ | 1. Analysis | Understand the problem | Analyst agent |
21
+ | 2. Planning | Define the solution | Product Manager agent |
22
+ | 3. Solutioning | Design the architecture | Architect agent |
23
+
24
+ ### Workflow
25
+
26
+ Work through Phases 1-3 using BMAD agents and workflows interactively.
27
+
28
+ > **Note:** Ralph (Phase 4 — autonomous implementation) is not supported on this platform.
29
+
30
+ ### Available Agents
31
+
32
+ | Agent | Role |
33
+ |-------|------|
34
+ | Analyst | Research, briefs, discovery |
35
+ | Architect | Technical design, architecture |
36
+ | Product Manager | PRDs, epics, stories |
37
+ | Scrum Master | Sprint planning, status, coordination |
38
+ | Developer | Implementation, coding |
39
+ | UX Designer | User experience, wireframes |
40
+ | QA Engineer | Test automation, quality assurance |
41
+ `,
42
+ getDoctorChecks: () => [
43
+ {
44
+ id: "instructions-file",
45
+ label: ".cursor/rules/bmad.mdc contains BMAD snippet",
46
+ check: async (projectDir) => {
47
+ try {
48
+ const content = await readFile(join(projectDir, ".cursor/rules/bmad.mdc"), "utf-8");
49
+ if (content.includes("BMAD-METHOD Integration")) {
50
+ return { passed: true };
51
+ }
52
+ return {
53
+ passed: false,
54
+ detail: "missing BMAD-METHOD Integration section",
55
+ hint: "Run: bmalph init",
56
+ };
57
+ }
58
+ catch (err) {
59
+ if (isEnoent(err)) {
60
+ return {
61
+ passed: false,
62
+ detail: ".cursor/rules/bmad.mdc not found",
63
+ hint: "Run: bmalph init",
64
+ };
65
+ }
66
+ return { passed: false, detail: formatError(err), hint: "Check file permissions" };
67
+ }
68
+ },
69
+ },
70
+ ],
71
+ };
@@ -0,0 +1,7 @@
1
+ import type { PlatformId } from "./types.js";
2
+ interface DetectionResult {
3
+ detected: PlatformId | null;
4
+ candidates: PlatformId[];
5
+ }
6
+ export declare function detectPlatform(projectDir: string): Promise<DetectionResult>;
7
+ export {};
@@ -0,0 +1,23 @@
1
+ import { exists } from "../utils/file-system.js";
2
+ import { join } from "path";
3
+ const DETECTION_MARKERS = [
4
+ { platform: "claude-code", markers: [".claude"] },
5
+ { platform: "codex", markers: ["AGENTS.md"] },
6
+ { platform: "cursor", markers: [".cursor"] },
7
+ { platform: "windsurf", markers: [".windsurf"] },
8
+ { platform: "copilot", markers: [".github/copilot-instructions.md"] },
9
+ { platform: "aider", markers: [".aider.conf.yml"] },
10
+ ];
11
+ export async function detectPlatform(projectDir) {
12
+ const candidates = [];
13
+ for (const { platform, markers } of DETECTION_MARKERS) {
14
+ for (const marker of markers) {
15
+ if (await exists(join(projectDir, marker))) {
16
+ candidates.push(platform);
17
+ break;
18
+ }
19
+ }
20
+ }
21
+ const detected = candidates.length === 1 ? (candidates[0] ?? null) : null;
22
+ return { detected, candidates };
23
+ }
@@ -0,0 +1,4 @@
1
+ export type { Platform, PlatformId, PlatformTier, CommandDelivery, PlatformDoctorCheck, } from "./types.js";
2
+ export { getPlatform, getAllPlatforms, isPlatformId } from "./registry.js";
3
+ export { resolveProjectPlatform } from "./resolve.js";
4
+ export { detectPlatform } from "./detect.js";
@@ -0,0 +1,3 @@
1
+ export { getPlatform, getAllPlatforms, isPlatformId } from "./registry.js";
2
+ export { resolveProjectPlatform } from "./resolve.js";
3
+ export { detectPlatform } from "./detect.js";
@@ -0,0 +1,4 @@
1
+ import type { Platform, PlatformId } from "./types.js";
2
+ export declare function getPlatform(id: PlatformId): Platform;
3
+ export declare function getAllPlatforms(): Platform[];
4
+ export declare function isPlatformId(value: string): value is PlatformId;
@@ -0,0 +1,27 @@
1
+ import { claudeCodePlatform } from "./claude-code.js";
2
+ import { codexPlatform } from "./codex.js";
3
+ import { cursorPlatform } from "./cursor.js";
4
+ import { windsurfPlatform } from "./windsurf.js";
5
+ import { copilotPlatform } from "./copilot.js";
6
+ import { aiderPlatform } from "./aider.js";
7
+ const PLATFORMS = new Map([
8
+ ["claude-code", claudeCodePlatform],
9
+ ["codex", codexPlatform],
10
+ ["cursor", cursorPlatform],
11
+ ["windsurf", windsurfPlatform],
12
+ ["copilot", copilotPlatform],
13
+ ["aider", aiderPlatform],
14
+ ]);
15
+ export function getPlatform(id) {
16
+ const platform = PLATFORMS.get(id);
17
+ if (!platform) {
18
+ throw new Error(`Unknown platform: ${id}`);
19
+ }
20
+ return platform;
21
+ }
22
+ export function getAllPlatforms() {
23
+ return [...PLATFORMS.values()];
24
+ }
25
+ export function isPlatformId(value) {
26
+ return PLATFORMS.has(value);
27
+ }
@@ -0,0 +1,8 @@
1
+ import type { Platform } from "./types.js";
2
+ /**
3
+ * Resolve the platform for a project from its config, defaulting to claude-code.
4
+ *
5
+ * Used by doctor and upgrade commands to determine which platform checks and
6
+ * assets to use. Falls back to claude-code when config is missing or unreadable.
7
+ */
8
+ export declare function resolveProjectPlatform(projectDir: string): Promise<Platform>;
@@ -0,0 +1,24 @@
1
+ import { readConfig } from "../utils/config.js";
2
+ import { isEnoent, formatError } from "../utils/errors.js";
3
+ import { warn } from "../utils/logger.js";
4
+ import { getPlatform } from "./registry.js";
5
+ /**
6
+ * Resolve the platform for a project from its config, defaulting to claude-code.
7
+ *
8
+ * Used by doctor and upgrade commands to determine which platform checks and
9
+ * assets to use. Falls back to claude-code when config is missing or unreadable.
10
+ */
11
+ export async function resolveProjectPlatform(projectDir) {
12
+ try {
13
+ const config = await readConfig(projectDir);
14
+ if (config?.platform) {
15
+ return getPlatform(config.platform);
16
+ }
17
+ }
18
+ catch (err) {
19
+ if (!isEnoent(err)) {
20
+ warn(`Failed to read project config: ${formatError(err)}`);
21
+ }
22
+ }
23
+ return getPlatform("claude-code");
24
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Platform abstraction layer for bmalph.
3
+ *
4
+ * Controls how `bmalph init/upgrade/doctor` install instruction files,
5
+ * deliver slash commands, and run health checks per platform.
6
+ */
7
+ /** Supported platform identifiers. */
8
+ export type PlatformId = "claude-code" | "codex" | "cursor" | "windsurf" | "copilot" | "aider";
9
+ /** Full platforms support Phases 1-4 (planning + Ralph implementation). */
10
+ /** Instructions-only platforms support Phases 1-3 (planning only). */
11
+ export type PlatformTier = "full" | "instructions-only";
12
+ /** How slash commands are delivered to the platform. */
13
+ export type CommandDelivery = {
14
+ kind: "directory";
15
+ dir: string;
16
+ } | {
17
+ kind: "inline";
18
+ } | {
19
+ kind: "none";
20
+ };
21
+ /** Result of a single platform-specific doctor check. */
22
+ export interface PlatformDoctorCheck {
23
+ id: string;
24
+ label: string;
25
+ check: (projectDir: string) => Promise<{
26
+ passed: boolean;
27
+ detail?: string;
28
+ hint?: string;
29
+ }>;
30
+ }
31
+ /** Platform definition controlling install, upgrade, and doctor behavior. */
32
+ export interface Platform {
33
+ readonly id: PlatformId;
34
+ readonly displayName: string;
35
+ readonly tier: PlatformTier;
36
+ readonly instructionsFile: string;
37
+ readonly commandDelivery: CommandDelivery;
38
+ readonly instructionsSectionMarker: string;
39
+ readonly generateInstructionsSnippet: () => string;
40
+ readonly getDoctorChecks: () => PlatformDoctorCheck[];
41
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Platform abstraction layer for bmalph.
3
+ *
4
+ * Controls how `bmalph init/upgrade/doctor` install instruction files,
5
+ * deliver slash commands, and run health checks per platform.
6
+ */
7
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { Platform } from "./types.js";
2
+ export declare const windsurfPlatform: Platform;
@@ -0,0 +1,71 @@
1
+ import { readFile } from "fs/promises";
2
+ import { join } from "path";
3
+ import { isEnoent, formatError } from "../utils/errors.js";
4
+ export const windsurfPlatform = {
5
+ id: "windsurf",
6
+ displayName: "Windsurf",
7
+ tier: "instructions-only",
8
+ instructionsFile: ".windsurf/rules/bmad.md",
9
+ commandDelivery: { kind: "none" },
10
+ instructionsSectionMarker: "## BMAD-METHOD Integration",
11
+ generateInstructionsSnippet: () => `
12
+ ## BMAD-METHOD Integration
13
+
14
+ Ask the BMAD master agent to navigate phases. Ask for help to discover all available agents and workflows.
15
+
16
+ ### Phases
17
+
18
+ | Phase | Focus | Key Agents |
19
+ |-------|-------|-----------|
20
+ | 1. Analysis | Understand the problem | Analyst agent |
21
+ | 2. Planning | Define the solution | Product Manager agent |
22
+ | 3. Solutioning | Design the architecture | Architect agent |
23
+
24
+ ### Workflow
25
+
26
+ Work through Phases 1-3 using BMAD agents and workflows interactively.
27
+
28
+ > **Note:** Ralph (Phase 4 — autonomous implementation) is not supported on this platform.
29
+
30
+ ### Available Agents
31
+
32
+ | Agent | Role |
33
+ |-------|------|
34
+ | Analyst | Research, briefs, discovery |
35
+ | Architect | Technical design, architecture |
36
+ | Product Manager | PRDs, epics, stories |
37
+ | Scrum Master | Sprint planning, status, coordination |
38
+ | Developer | Implementation, coding |
39
+ | UX Designer | User experience, wireframes |
40
+ | QA Engineer | Test automation, quality assurance |
41
+ `,
42
+ getDoctorChecks: () => [
43
+ {
44
+ id: "instructions-file",
45
+ label: ".windsurf/rules/bmad.md contains BMAD snippet",
46
+ check: async (projectDir) => {
47
+ try {
48
+ const content = await readFile(join(projectDir, ".windsurf/rules/bmad.md"), "utf-8");
49
+ if (content.includes("BMAD-METHOD Integration")) {
50
+ return { passed: true };
51
+ }
52
+ return {
53
+ passed: false,
54
+ detail: "missing BMAD-METHOD Integration section",
55
+ hint: "Run: bmalph init",
56
+ };
57
+ }
58
+ catch (err) {
59
+ if (isEnoent(err)) {
60
+ return {
61
+ passed: false,
62
+ detail: ".windsurf/rules/bmad.md not found",
63
+ hint: "Run: bmalph init",
64
+ };
65
+ }
66
+ return { passed: false, detail: formatError(err), hint: "Check file permissions" };
67
+ }
68
+ },
69
+ },
70
+ ],
71
+ };
@@ -39,7 +39,7 @@ export async function validateArtifacts(files, artifactsDir) {
39
39
  }
40
40
  }
41
41
  catch {
42
- // Cannot read readiness file, skip
42
+ warnings.push("Could not read readiness report — NO-GO status unverified");
43
43
  }
44
44
  }
45
45
  return warnings;
@@ -1,5 +1,5 @@
1
1
  import type { Story, FixPlanItemWithTitle } from "./types.js";
2
- export declare function generateFixPlan(stories: Story[]): string;
2
+ export declare function generateFixPlan(stories: Story[], storiesFileName?: string): string;
3
3
  export declare function hasFixPlanProgress(content: string): boolean;
4
4
  export declare function parseFixPlan(content: string): FixPlanItemWithTitle[];
5
5
  /**
@@ -1,4 +1,4 @@
1
- export function generateFixPlan(stories) {
1
+ export function generateFixPlan(stories, storiesFileName) {
2
2
  const lines = ["# Ralph Fix Plan", "", "## Stories to Implement", ""];
3
3
  let currentEpic = "";
4
4
  for (const story of stories) {
@@ -25,7 +25,8 @@ export function generateFixPlan(stories) {
25
25
  }
26
26
  // Add spec-link for easy reference to full story details
27
27
  const anchor = story.id.replace(".", "-");
28
- lines.push(` > Spec: specs/planning-artifacts/stories.md#story-${anchor}`);
28
+ const fileName = storiesFileName ?? "stories.md";
29
+ lines.push(` > Spec: specs/planning-artifacts/${fileName}#story-${anchor}`);
29
30
  }
30
31
  lines.push("", "## Completed", "", "## Notes", "- Follow TDD methodology (red-green-refactor)", "- One story per Ralph loop iteration", "- Update this file after completing each story", "");
31
32
  return lines.join("\n");
@@ -64,7 +64,7 @@ export async function runTransition(projectDir) {
64
64
  }
65
65
  // Generate new fix_plan from current stories, preserving completion status
66
66
  info(`Generating fix plan for ${stories.length} stories...`);
67
- const newFixPlan = generateFixPlan(stories);
67
+ const newFixPlan = generateFixPlan(stories, storiesFile);
68
68
  const mergedFixPlan = mergeFixPlanProgress(newFixPlan, completedIds);
69
69
  await atomicWriteFile(fixPlanPath, mergedFixPlan);
70
70
  // Track whether progress was preserved for return value
@@ -36,7 +36,10 @@ export async function generateSpecsChangelog(oldSpecsDir, newSourceDir) {
36
36
  debug(`Could not read old spec file ${file}: ${formatError(err)}`);
37
37
  return "";
38
38
  });
39
- const newContent = await readFile(join(newSourceDir, file), "utf-8");
39
+ const newContent = await readFile(join(newSourceDir, file), "utf-8").catch((err) => {
40
+ debug(`Could not read new spec file ${file}: ${formatError(err)}`);
41
+ return "";
42
+ });
40
43
  if (oldContent !== newContent) {
41
44
  changes.push({
42
45
  file,
@@ -10,14 +10,13 @@ export function detectSpecFileType(filename, _content) {
10
10
  if (lower.includes("arch"))
11
11
  return "architecture";
12
12
  // Check stories/epic BEFORE brainstorm (Bug #5: brainstorm-stories.md should be "stories")
13
- // Use "stori" to match "stories"/"story" but not "brainstorm" (which contains "stor")
14
- if (lower.includes("stori") || lower.includes("epic"))
13
+ if (/stor(y|ies)/i.test(lower) || lower.includes("epic"))
15
14
  return "stories";
16
15
  if (lower.includes("brainstorm"))
17
16
  return "brainstorm";
18
17
  if (lower.includes("ux"))
19
18
  return "ux";
20
- if (lower.includes("test"))
19
+ if (/\btest/i.test(lower))
21
20
  return "test-design";
22
21
  if (lower.includes("readiness"))
23
22
  return "readiness";
@@ -1,11 +1,12 @@
1
+ import type { PlatformId } from "../platform/types.js";
1
2
  export interface UpstreamVersions {
2
3
  bmadCommit: string;
3
- ralphCommit: string;
4
4
  }
5
5
  export interface BmalphConfig {
6
6
  name: string;
7
7
  description: string;
8
8
  createdAt: string;
9
+ platform?: PlatformId;
9
10
  upstreamVersions?: UpstreamVersions;
10
11
  }
11
12
  export declare function readConfig(projectDir: string): Promise<BmalphConfig | null>;
@@ -30,6 +30,9 @@ export function isEnoent(err) {
30
30
  }
31
31
  export function formatError(error) {
32
32
  if (error instanceof Error) {
33
+ if (error.cause) {
34
+ return `${error.message}: ${formatError(error.cause)}`;
35
+ }
33
36
  return error.message;
34
37
  }
35
38
  return String(error);
@@ -32,7 +32,6 @@ export interface UpstreamStatus {
32
32
  }
33
33
  export interface CheckUpstreamResult {
34
34
  bmad: UpstreamStatus | null;
35
- ralph: UpstreamStatus | null;
36
35
  errors: GitHubError[];
37
36
  }
38
37
  interface FetchOptions {