pi-bmad-flow 0.1.0 → 0.1.1

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.
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { collectMarkdownFiles, collectYamlFiles } from "./files.js";
4
- import { loadSprintStatus, resolveStoryLocation } from "./sprint.js";
4
+ import { loadSprintStatus, resolveSprintStatusPath, resolveStoryLocation } from "./sprint.js";
5
5
  import type { ArtifactInventory, BmadInstallState, BmadPaths, BmadPhase, BmadProjectState } from "./types.js";
6
6
 
7
7
  function matches(files: string[], pattern: RegExp): string[] {
@@ -17,8 +17,9 @@ function collectStructuredFiles(dirPath: string): string[] {
17
17
  }
18
18
 
19
19
  function detectInventory(paths: BmadPaths): ArtifactInventory {
20
- const sprint = loadSprintStatus(paths.sprintStatusPath);
21
- const storyLocationDir = resolveStoryLocation(paths.sprintStatusPath, sprint);
20
+ const resolvedSprintStatusPath = resolveSprintStatusPath(paths.sprintStatusPath);
21
+ const sprint = loadSprintStatus(resolvedSprintStatusPath);
22
+ const storyLocationDir = resolveStoryLocation(resolvedSprintStatusPath, sprint);
22
23
  const planningFiles = collectMarkdownFiles(paths.planningArtifactsDir);
23
24
  const implementationFiles = collectMarkdownFiles(paths.implementationArtifactsDir);
24
25
  const storyLocationFiles =
@@ -135,7 +136,8 @@ export function detectBmadProjectState(cwd: string): BmadProjectState {
135
136
  const inventory = detectInventory(install.paths);
136
137
  const hasPlanningArtifacts = inventory.planningFiles.length > 0;
137
138
  const hasImplementationArtifacts = inventory.implementationFiles.length > 0;
138
- const hasSprintStatus = existsSync(install.paths.sprintStatusPath);
139
+ const resolvedSprintStatusPath = resolveSprintStatusPath(install.paths.sprintStatusPath);
140
+ const hasSprintStatus = existsSync(resolvedSprintStatusPath);
139
141
  const phase = detectPhase(inventory, hasSprintStatus);
140
142
  const hasWdsArtifacts =
141
143
  inventory.wdsScenarioFiles.length > 0 ||
@@ -148,7 +150,7 @@ export function detectBmadProjectState(cwd: string): BmadProjectState {
148
150
  inventory.teaReviewFiles.length > 0 ||
149
151
  inventory.teaNfrFiles.length > 0;
150
152
 
151
- const sprint = hasSprintStatus ? loadSprintStatus(install.paths.sprintStatusPath) : undefined;
153
+ const sprint = hasSprintStatus ? loadSprintStatus(resolvedSprintStatusPath) : undefined;
152
154
  const nextBacklogStory = sprint?.storyOrder.find((story) => sprint.developmentStatus[story] === "backlog");
153
155
  const nextReadyStory = sprint?.storyOrder.find((story) => sprint.developmentStatus[story] === "ready-for-dev");
154
156
  const activeStory = sprint?.storyOrder.find((story) => sprint.developmentStatus[story] === "in-progress");
@@ -2,6 +2,8 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import type { SprintStatus } from "./types.js";
4
4
 
5
+ const STATUS_FILE_CANDIDATES = ["sprint-status.yaml", "story-status.yaml"];
6
+
5
7
  const STORY_KEY_PATTERN = /^\d+-\d+-/;
6
8
 
7
9
  function parseStatusLine(line: string): { key: string; value: string } | undefined {
@@ -10,9 +12,22 @@ function parseStatusLine(line: string): { key: string; value: string } | undefin
10
12
  return { key: match[1], value: match[2] };
11
13
  }
12
14
 
15
+ export function resolveSprintStatusPath(statusPath: string): string {
16
+ if (existsSync(statusPath)) return statusPath;
17
+
18
+ const directory = dirname(statusPath);
19
+ for (const candidate of STATUS_FILE_CANDIDATES) {
20
+ const candidatePath = resolve(directory, candidate);
21
+ if (existsSync(candidatePath)) return candidatePath;
22
+ }
23
+
24
+ return statusPath;
25
+ }
26
+
13
27
  export function loadSprintStatus(statusPath: string): SprintStatus | undefined {
14
- if (!existsSync(statusPath)) return undefined;
15
- const content = readFileSync(statusPath, "utf8");
28
+ const resolvedStatusPath = resolveSprintStatusPath(statusPath);
29
+ if (!existsSync(resolvedStatusPath)) return undefined;
30
+ const content = readFileSync(resolvedStatusPath, "utf8");
16
31
  const lines = content.split(/\r?\n/);
17
32
 
18
33
  const developmentStatus: Record<string, string> = {};
@@ -46,8 +61,9 @@ export function loadSprintStatus(statusPath: string): SprintStatus | undefined {
46
61
  }
47
62
 
48
63
  export function updateStoryStatus(statusPath: string, storyKey: string, nextStatus: string): boolean {
49
- if (!existsSync(statusPath)) return false;
50
- const content = readFileSync(statusPath, "utf8");
64
+ const resolvedStatusPath = resolveSprintStatusPath(statusPath);
65
+ if (!existsSync(resolvedStatusPath)) return false;
66
+ const content = readFileSync(resolvedStatusPath, "utf8");
51
67
  const lines = content.split(/\r?\n/);
52
68
 
53
69
  let changed = false;
@@ -68,7 +84,7 @@ export function updateStoryStatus(statusPath: string, storyKey: string, nextStat
68
84
  }
69
85
 
70
86
  if (!changed) return false;
71
- writeFileSync(statusPath, `${lines.join("\n")}\n`, "utf8");
87
+ writeFileSync(resolvedStatusPath, `${lines.join("\n")}\n`, "utf8");
72
88
  return true;
73
89
  }
74
90
 
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "pi-bmad-flow",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "Pi-native orchestration overlay for BMAD workflows",
6
- "keywords": ["pi-package", "bmad", "workflow", "orchestration"],
6
+ "keywords": [
7
+ "pi-package",
8
+ "bmad",
9
+ "workflow",
10
+ "orchestration"
11
+ ],
7
12
  "license": "MIT",
8
13
  "publishConfig": {
9
14
  "access": "public"
@@ -30,7 +35,11 @@
30
35
  "@sinclair/typebox": "*"
31
36
  },
32
37
  "pi": {
33
- "extensions": ["./extensions"],
34
- "skills": ["./skills"]
38
+ "extensions": [
39
+ "./extensions"
40
+ ],
41
+ "skills": [
42
+ "./skills"
43
+ ]
35
44
  }
36
45
  }
@@ -45,12 +45,28 @@ function readJson(path) {
45
45
  return JSON.parse(readFileSync(path, "utf8"));
46
46
  }
47
47
 
48
+ function resolveSprintStatusPath(path) {
49
+ if (existsSync(path)) return path;
50
+
51
+ const candidates = [
52
+ path.replace(/sprint-status\.yaml$/, "story-status.yaml"),
53
+ path.replace(/story-status\.yaml$/, "sprint-status.yaml"),
54
+ ];
55
+
56
+ for (const candidate of candidates) {
57
+ if (candidate !== path && existsSync(candidate)) return candidate;
58
+ }
59
+
60
+ return path;
61
+ }
62
+
48
63
  function parseSprintStatus(path) {
49
- if (!existsSync(path)) {
64
+ const resolvedPath = resolveSprintStatusPath(path);
65
+ if (!existsSync(resolvedPath)) {
50
66
  return { storyOrder: [], developmentStatus: {}, storyLocation: undefined };
51
67
  }
52
68
 
53
- const lines = readFileSync(path, "utf8").split(/\r?\n/);
69
+ const lines = readFileSync(resolvedPath, "utf8").split(/\r?\n/);
54
70
  const state = {
55
71
  storyOrder: [],
56
72
  developmentStatus: {},
@@ -203,8 +219,9 @@ function main() {
203
219
  teaNfrFiles: matches(allContextFiles, /nfr-assessment|nfr-report/),
204
220
  };
205
221
 
206
- const sprint = parseSprintStatus(paths.sprintStatusPath);
207
- const sprintStatusExists = existsSync(paths.sprintStatusPath);
222
+ const resolvedSprintStatusPath = resolveSprintStatusPath(paths.sprintStatusPath);
223
+ const sprint = parseSprintStatus(resolvedSprintStatusPath);
224
+ const sprintStatusExists = existsSync(resolvedSprintStatusPath);
208
225
  const nextAction = decideNextAction(inventory, sprintStatusExists, sprint);
209
226
 
210
227
  console.log("pi-bmad-flow project audit");