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
|
|
21
|
-
const
|
|
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
|
|
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(
|
|
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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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(
|
|
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.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pi-native orchestration overlay for BMAD workflows",
|
|
6
|
-
"keywords": [
|
|
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": [
|
|
34
|
-
|
|
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
|
-
|
|
64
|
+
const resolvedPath = resolveSprintStatusPath(path);
|
|
65
|
+
if (!existsSync(resolvedPath)) {
|
|
50
66
|
return { storyOrder: [], developmentStatus: {}, storyLocation: undefined };
|
|
51
67
|
}
|
|
52
68
|
|
|
53
|
-
const lines = readFileSync(
|
|
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
|
|
207
|
-
const
|
|
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");
|