pi-bmad-flow 0.1.3 → 0.1.4

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 CHANGED
@@ -107,5 +107,71 @@ Current behavior:
107
107
  - BMAD-specific compaction summaries
108
108
  - lightweight BMAD status widget and footer state
109
109
  - optional LLM access to deterministic BMAD state through the `bmad_orchestrator` tool
110
+ - workflow-aware model and thinking presets for routing, story prep, story start, review, and gates
110
111
 
111
112
  This package does not replace official BMAD workflows. It reduces routing overhead around them.
113
+
114
+ ## Optional model policy override
115
+
116
+ By default, the overlay uses a GPT-only policy aimed at:
117
+
118
+ - `openai-codex/gpt-5.4-mini` for routing and status
119
+ - `openai-codex/gpt-5.4` for story prep, story start, review, and gates
120
+ - thinking level as the main optimization knob
121
+
122
+ The policy is applied both for overlay commands and for common BMAD workflow inputs such as:
123
+
124
+ - `bmad-create-story`
125
+ - `bmad-dev-story`
126
+ - `bmad-create-prd`
127
+ - `bmad-create-architecture`
128
+ - `bmad-create-epics-and-stories`
129
+ - `bmad-code-review`
130
+ - `bmad-testarch-test-review`
131
+ - `bmad-testarch-trace`
132
+ - `bmad-testarch-nfr`
133
+
134
+ You can override the default preset behavior with:
135
+
136
+ ```text
137
+ .pi/bmad/model-policy.json
138
+ ```
139
+
140
+ Shape:
141
+
142
+ ```json
143
+ {
144
+ "presets": {
145
+ "routing": {
146
+ "model": "openai-codex/gpt-5.4-mini",
147
+ "thinking": "minimal"
148
+ },
149
+ "story-prep": {
150
+ "model": "openai-codex/gpt-5.4",
151
+ "thinking": "low"
152
+ },
153
+ "story-start-lean": {
154
+ "model": "openai-codex/gpt-5.4",
155
+ "thinking": "low"
156
+ },
157
+ "story-start-full": {
158
+ "model": "openai-codex/gpt-5.4",
159
+ "thinking": "medium"
160
+ },
161
+ "review": {
162
+ "model": "openai-codex/gpt-5.4",
163
+ "thinking": "low"
164
+ },
165
+ "gate-light": {
166
+ "model": "openai-codex/gpt-5.4",
167
+ "thinking": "low"
168
+ },
169
+ "gate-strong": {
170
+ "model": "openai-codex/gpt-5.4",
171
+ "thinking": "medium"
172
+ }
173
+ }
174
+ }
175
+ ```
176
+
177
+ If you omit `model`, the overlay falls back to tier-based matching.
@@ -2,6 +2,7 @@ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
2
  import { detectBmadInstall, detectBmadProjectState } from "./detector.js";
3
3
  import { decideGate } from "./gates.js";
4
4
  import { buildStoryPacket, packetHint, selectPacketMode } from "./packets.js";
5
+ import { applyPreset, presetForNextCommand } from "./policy.js";
5
6
  import { decideNextAction } from "./router.js";
6
7
  import { updateStoryStatus } from "./sprint.js";
7
8
  import type { GatePlan, StoryPacket } from "./types.js";
@@ -45,6 +46,11 @@ function formatPacketLaunchMessage(story: string, packet: StoryPacket): string {
45
46
  return lines.join("\n");
46
47
  }
47
48
 
49
+ function currentModelLabel(ctx: { model?: { provider: string; id: string } }): string | undefined {
50
+ if (!ctx.model) return undefined;
51
+ return `${ctx.model.provider}/${ctx.model.id}`;
52
+ }
53
+
48
54
  function formatGateMessage(plan: GatePlan): string {
49
55
  const lines = [
50
56
  `Gate level: ${plan.level}`,
@@ -66,6 +72,7 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
66
72
  pi.registerCommand("bmad-status", {
67
73
  description: "Show BMAD install, phase, and story queue status",
68
74
  handler: async (_args, ctx) => {
75
+ await applyPreset(pi, ctx, cwd, "routing");
69
76
  const install = detectBmadInstall(cwd);
70
77
  const state = detectBmadProjectState(cwd);
71
78
  const next = decideNextAction(state);
@@ -93,7 +100,11 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
93
100
  }
94
101
  ctx.ui.notify(`Next: ${next.command} - ${next.summary}`, "info");
95
102
 
96
- refreshBmadUi(ctx, state, next);
103
+ refreshBmadUi(ctx, state, next, {
104
+ preset: "routing",
105
+ model: currentModelLabel(ctx),
106
+ thinking: pi.getThinkingLevel(),
107
+ });
97
108
  appendBmadState(pi, { event: "status", nextCommand: next.command });
98
109
  },
99
110
  });
@@ -101,6 +112,7 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
101
112
  pi.registerCommand("bmad-phase", {
102
113
  description: "Show current workflow phase and recommended route",
103
114
  handler: async (_args, ctx) => {
115
+ await applyPreset(pi, ctx, cwd, "routing");
104
116
  const state = detectBmadProjectState(cwd);
105
117
  const next = decideNextAction(state);
106
118
  ctx.ui.notify(`Current phase: ${state.phase}`, "info");
@@ -115,7 +127,11 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
115
127
  ctx.ui.notify(`Story location: ${state.activeStoryLocation}`, "info");
116
128
  }
117
129
  ctx.ui.notify(`Recommended: ${next.command} (${next.reason})`, "info");
118
- refreshBmadUi(ctx, state, next);
130
+ refreshBmadUi(ctx, state, next, {
131
+ preset: "routing",
132
+ model: currentModelLabel(ctx),
133
+ thinking: pi.getThinkingLevel(),
134
+ });
119
135
  appendBmadState(pi, { event: "status", nextCommand: next.command });
120
136
  },
121
137
  });
@@ -123,6 +139,7 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
123
139
  pi.registerCommand("bmad-next", {
124
140
  description: "Determine next action from BMAD artifacts",
125
141
  handler: async (_args, ctx) => {
142
+ await applyPreset(pi, ctx, cwd, "routing");
126
143
  const install = detectBmadInstall(cwd);
127
144
  if (!install.installed) {
128
145
  ctx.ui.notify("No BMAD installation detected at _bmad/_config/manifest.yaml", "warning");
@@ -133,12 +150,17 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
133
150
  const next = decideNextAction(state);
134
151
  ctx.ui.notify(next.summary, "info");
135
152
  ctx.ui.notify(`Recommended command: ${next.command}`, "info");
136
- refreshBmadUi(ctx, state, next);
153
+ refreshBmadUi(ctx, state, next, {
154
+ preset: "routing",
155
+ model: currentModelLabel(ctx),
156
+ thinking: pi.getThinkingLevel(),
157
+ });
137
158
  appendBmadState(pi, { event: "next", nextCommand: next.command });
138
159
 
139
160
  if (!ctx.hasUI) return;
140
161
  const shouldLaunch = await ctx.ui.confirm("Launch recommended workflow?", next.command);
141
162
  if (shouldLaunch) {
163
+ await applyPreset(pi, ctx, cwd, presetForNextCommand(next.command));
142
164
  pi.sendUserMessage(next.command, { source: "extension" });
143
165
  }
144
166
  },
@@ -162,6 +184,7 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
162
184
  }
163
185
 
164
186
  const mode = selectPacketMode(state);
187
+ await applyPreset(pi, ctx, cwd, mode === "full" ? "story-start-full" : "story-start-lean");
165
188
  const packet = buildStoryPacket(state, story, mode);
166
189
  const statusUpdated = updateStoryStatus(install.paths.sprintStatusPath, story, "in-progress");
167
190
  if (!statusUpdated) {
@@ -198,7 +221,11 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
198
221
 
199
222
  const refreshedState = detectBmadProjectState(cwd);
200
223
  const refreshedNext = decideNextAction(refreshedState);
201
- refreshBmadUi(ctx, refreshedState, refreshedNext);
224
+ refreshBmadUi(ctx, refreshedState, refreshedNext, {
225
+ preset: mode === "full" ? "story-start-full" : "story-start-lean",
226
+ model: currentModelLabel(ctx),
227
+ thinking: pi.getThinkingLevel(),
228
+ });
202
229
  pi.sendUserMessage(formatPacketLaunchMessage(story, packet), { source: "extension" });
203
230
  },
204
231
  });
@@ -206,6 +233,7 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
206
233
  pi.registerCommand("bmad-review", {
207
234
  description: "Run review workflow for active story",
208
235
  handler: async (_args, ctx) => {
236
+ await applyPreset(pi, ctx, cwd, "review");
209
237
  const state = detectBmadProjectState(cwd);
210
238
  const story = state.activeStory ?? state.nextReadyStory;
211
239
  if (!story) {
@@ -215,7 +243,11 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
215
243
 
216
244
  ctx.ui.notify(`Running review for ${story}`, "info");
217
245
  appendBmadState(pi, { event: "review", storyKey: story });
218
- refreshBmadUi(ctx, state, decideNextAction(state));
246
+ refreshBmadUi(ctx, state, decideNextAction(state), {
247
+ preset: "review",
248
+ model: currentModelLabel(ctx),
249
+ thinking: pi.getThinkingLevel(),
250
+ });
219
251
  pi.sendUserMessage(`bmad-code-review ${story}`, { source: "extension" });
220
252
  },
221
253
  });
@@ -231,6 +263,7 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
231
263
  return;
232
264
  }
233
265
  const decision = decideGate(state, install.modules.includes("tea"));
266
+ await applyPreset(pi, ctx, cwd, decision.level === "strong" ? "gate-strong" : "gate-light");
234
267
  const plan: GatePlan = {
235
268
  storyKey: story,
236
269
  level: decision.level,
@@ -246,7 +279,11 @@ export function registerBmadCommands(pi: ExtensionAPI, cwd: string): void {
246
279
  ctx.ui.notify(`Evidence files: ${decision.evidenceFiles.length}`, "info");
247
280
  }
248
281
  appendBmadState(pi, { event: "gate", storyKey: story, gateLevel: decision.level });
249
- refreshBmadUi(ctx, state, decideNextAction(state));
282
+ refreshBmadUi(ctx, state, decideNextAction(state), {
283
+ preset: decision.level === "strong" ? "gate-strong" : "gate-light",
284
+ model: currentModelLabel(ctx),
285
+ thinking: pi.getThinkingLevel(),
286
+ });
250
287
  pi.sendUserMessage(formatGateMessage(plan), { source: "extension" });
251
288
  },
252
289
  });
@@ -2,6 +2,7 @@ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
2
  import { detectBmadInstall, detectBmadProjectState } from "./detector.js";
3
3
  import { registerBmadCommands } from "./commands.js";
4
4
  import { decideNextAction } from "./router.js";
5
+ import { applyPreset, presetForWorkflowInput } from "./policy.js";
5
6
  import { registerBmadTool } from "./tool.js";
6
7
  import { clearBmadUi, refreshBmadUi } from "./ui.js";
7
8
 
@@ -55,12 +56,25 @@ export default function bmadOrchestrator(pi: ExtensionAPI): void {
55
56
  registerBmadCommands(pi, cwd);
56
57
  registerBmadTool(pi, cwd);
57
58
 
58
- pi.on("input", async (event) => {
59
+ pi.on("input", async (event, ctx) => {
59
60
  if (event.source === "extension") return { action: "continue" };
61
+
60
62
  const command = routeIntent(event.text);
61
- if (!command) return { action: "continue" };
62
- pi.sendUserMessage(command, { source: "extension" });
63
- return { action: "handled" };
63
+ if (command) {
64
+ const preset = presetForWorkflowInput(command);
65
+ if (preset) {
66
+ await applyPreset(pi, ctx, cwd, preset);
67
+ }
68
+ pi.sendUserMessage(command, { source: "extension" });
69
+ return { action: "handled" };
70
+ }
71
+
72
+ const workflowPreset = presetForWorkflowInput(event.text);
73
+ if (workflowPreset) {
74
+ await applyPreset(pi, ctx, cwd, workflowPreset);
75
+ }
76
+
77
+ return { action: "continue" };
64
78
  });
65
79
 
66
80
  pi.on("session_start", async (_event, ctx) => {
@@ -74,7 +88,10 @@ export default function bmadOrchestrator(pi: ExtensionAPI): void {
74
88
  const modules = install.modules.length > 0 ? install.modules.join(", ") : "none";
75
89
  const state = detectBmadProjectState(cwd);
76
90
  const next = decideNextAction(state);
77
- refreshBmadUi(ctx, state, next);
91
+ refreshBmadUi(ctx, state, next, {
92
+ model: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined,
93
+ thinking: pi.getThinkingLevel(),
94
+ });
78
95
  ctx.ui.notify(`pi-bmad-flow ready. BMAD modules: ${modules}`, "info");
79
96
  });
80
97
 
@@ -83,7 +100,10 @@ export default function bmadOrchestrator(pi: ExtensionAPI): void {
83
100
  if (!install.installed) return;
84
101
  const state = detectBmadProjectState(cwd);
85
102
  const next = decideNextAction(state);
86
- refreshBmadUi(ctx, state, next);
103
+ refreshBmadUi(ctx, state, next, {
104
+ model: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined,
105
+ thinking: pi.getThinkingLevel(),
106
+ });
87
107
  });
88
108
 
89
109
  pi.on("session_before_compact", async (event, ctx) => {
@@ -0,0 +1,163 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import type { ExtensionAPI, ExtensionContext, ThinkingLevel } from "@mariozechner/pi-coding-agent";
4
+
5
+ export type BmadPresetName =
6
+ | "routing"
7
+ | "story-prep"
8
+ | "story-start-lean"
9
+ | "story-start-full"
10
+ | "review"
11
+ | "gate-light"
12
+ | "gate-strong";
13
+
14
+ type ModelTier = "fast" | "balanced" | "strong";
15
+
16
+ interface AvailableModel {
17
+ provider: string;
18
+ id: string;
19
+ name?: string;
20
+ }
21
+
22
+ interface PresetConfig {
23
+ model?: string;
24
+ tier?: ModelTier;
25
+ thinking: ThinkingLevel;
26
+ }
27
+
28
+ interface ModelPolicyConfig {
29
+ tiers?: Partial<Record<ModelTier, string[]>>;
30
+ presets?: Partial<Record<BmadPresetName, Partial<PresetConfig>>>;
31
+ }
32
+
33
+ const DEFAULT_TIERS: Record<ModelTier, string[]> = {
34
+ fast: ["openai-codex/gpt-5.4-mini", "openai-codex/*mini*"],
35
+ balanced: ["openai-codex/gpt-5.4", "openai-codex/*gpt-5.4*", "openai-codex/*codex*"],
36
+ strong: ["openai-codex/gpt-5.4", "openai-codex/*gpt-5.4*", "openai-codex/*codex*"],
37
+ };
38
+
39
+ const DEFAULT_PRESETS: Record<BmadPresetName, PresetConfig> = {
40
+ routing: { model: "openai-codex/gpt-5.4-mini", thinking: "minimal" },
41
+ "story-prep": { model: "openai-codex/gpt-5.4", thinking: "low" },
42
+ "story-start-lean": { model: "openai-codex/gpt-5.4", thinking: "low" },
43
+ "story-start-full": { model: "openai-codex/gpt-5.4", thinking: "medium" },
44
+ review: { model: "openai-codex/gpt-5.4", thinking: "low" },
45
+ "gate-light": { model: "openai-codex/gpt-5.4", thinking: "low" },
46
+ "gate-strong": { model: "openai-codex/gpt-5.4", thinking: "medium" },
47
+ };
48
+
49
+ function loadPolicyConfig(cwd: string): ModelPolicyConfig | undefined {
50
+ const configPath = join(cwd, ".pi", "bmad", "model-policy.json");
51
+ if (!existsSync(configPath)) return undefined;
52
+
53
+ try {
54
+ return JSON.parse(readFileSync(configPath, "utf8")) as ModelPolicyConfig;
55
+ } catch {
56
+ return undefined;
57
+ }
58
+ }
59
+
60
+ function escapeRegex(value: string): string {
61
+ return value.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
62
+ }
63
+
64
+ function matchesPattern(value: string, pattern: string): boolean {
65
+ const regex = new RegExp(`^${escapeRegex(pattern.toLowerCase()).replace(/\*/g, ".*")}$`);
66
+ return regex.test(value.toLowerCase());
67
+ }
68
+
69
+ function modelKey(model: AvailableModel): string {
70
+ return `${model.provider}/${model.id}`.toLowerCase();
71
+ }
72
+
73
+ function resolvePresetConfig(cwd: string, preset: BmadPresetName): { config: PresetConfig; tierPatterns?: string[] } {
74
+ const loaded = loadPolicyConfig(cwd);
75
+ const base = DEFAULT_PRESETS[preset];
76
+ const override = loaded?.presets?.[preset];
77
+ const config: PresetConfig = {
78
+ model: override?.model ?? base.model,
79
+ tier: override?.tier ?? base.tier,
80
+ thinking: override?.thinking ?? base.thinking,
81
+ };
82
+
83
+ const tierPatterns = config.tier ? loaded?.tiers?.[config.tier] ?? DEFAULT_TIERS[config.tier] : undefined;
84
+ return { config, tierPatterns };
85
+ }
86
+
87
+ async function selectModel(
88
+ ctx: ExtensionContext,
89
+ explicitModel: string | undefined,
90
+ tierPatterns: string[] | undefined,
91
+ ): Promise<AvailableModel | undefined> {
92
+ const available = (await ctx.modelRegistry.getAvailable()) as AvailableModel[];
93
+ const current = ctx.model as AvailableModel | undefined;
94
+
95
+ if (explicitModel) {
96
+ const found = available.find((candidate) => modelKey(candidate) === explicitModel.toLowerCase());
97
+ if (found) return found;
98
+ }
99
+
100
+ if (tierPatterns) {
101
+ if (current) {
102
+ const currentKey = modelKey(current);
103
+ if (tierPatterns.some((pattern) => matchesPattern(currentKey, pattern))) return current;
104
+ }
105
+
106
+ for (const pattern of tierPatterns) {
107
+ const found = available.find((candidate) => matchesPattern(modelKey(candidate), pattern));
108
+ if (found) return found;
109
+ }
110
+ }
111
+
112
+ return current ?? available[0];
113
+ }
114
+
115
+ export async function applyPreset(pi: ExtensionAPI, ctx: ExtensionContext, cwd: string, preset: BmadPresetName): Promise<void> {
116
+ const { config, tierPatterns } = resolvePresetConfig(cwd, preset);
117
+ const selectedModel = await selectModel(ctx, config.model, tierPatterns);
118
+
119
+ if (selectedModel) {
120
+ const current = ctx.model as AvailableModel | undefined;
121
+ const currentKey = current ? modelKey(current) : undefined;
122
+ const selectedKey = modelKey(selectedModel);
123
+ if (currentKey !== selectedKey) {
124
+ const changed = await pi.setModel(selectedModel);
125
+ if (changed) {
126
+ ctx.ui.notify(`BMAD preset ${preset}: model ${selectedModel.provider}/${selectedModel.id}`, "info");
127
+ }
128
+ }
129
+ }
130
+
131
+ if (pi.getThinkingLevel() !== config.thinking) {
132
+ pi.setThinkingLevel(config.thinking);
133
+ ctx.ui.notify(`BMAD preset ${preset}: thinking ${config.thinking}`, "info");
134
+ }
135
+ }
136
+
137
+ export function presetForNextCommand(command: string): BmadPresetName {
138
+ if (command === "/bmad-start") return "story-start-lean";
139
+ if (command === "bmad-create-story") return "story-prep";
140
+ if (command === "bmad-create-prd" || command === "bmad-create-architecture") return "story-start-full";
141
+ return "routing";
142
+ }
143
+
144
+ export function presetForWorkflowInput(text: string): BmadPresetName | undefined {
145
+ const normalized = text.trim().toLowerCase();
146
+ if (!normalized) return undefined;
147
+
148
+ if (normalized === "/bmad-status" || normalized === "/bmad-next" || normalized === "/bmad-phase") return "routing";
149
+ if (normalized === "/bmad-review") return "review";
150
+ if (normalized === "/bmad-gate") return "gate-light";
151
+ if (normalized === "/bmad-start") return "story-start-lean";
152
+ if (/^bmad-create-story\b/.test(normalized)) return "story-prep";
153
+ if (/^bmad-dev-story\b/.test(normalized)) return "story-start-lean";
154
+ if (/^bmad-create-prd\b/.test(normalized)) return "story-start-full";
155
+ if (/^bmad-create-architecture\b/.test(normalized)) return "story-start-full";
156
+ if (/^bmad-create-epics-and-stories\b/.test(normalized)) return "story-prep";
157
+ if (/^bmad-create-ux-design\b/.test(normalized)) return "story-prep";
158
+ if (/^bmad-code-review\b/.test(normalized)) return "review";
159
+ if (/^bmad-testarch-(test-review|trace)\b/.test(normalized)) return "gate-light";
160
+ if (/^bmad-testarch-nfr\b/.test(normalized)) return "gate-strong";
161
+
162
+ return undefined;
163
+ }
@@ -1,15 +1,26 @@
1
- import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionContext, ThinkingLevel } from "@mariozechner/pi-coding-agent";
2
2
  import type { BmadProjectState } from "./types.js";
3
3
  import type { NextAction } from "./router.js";
4
4
 
5
- export function refreshBmadUi(ctx: ExtensionContext, state: BmadProjectState, next: NextAction): void {
5
+ interface BmadUiMeta {
6
+ preset?: string;
7
+ model?: string;
8
+ thinking?: ThinkingLevel;
9
+ }
10
+
11
+ export function refreshBmadUi(ctx: ExtensionContext, state: BmadProjectState, next: NextAction, meta?: BmadUiMeta): void {
6
12
  const activeStory = state.activeStory ?? state.nextReadyStory ?? "none";
7
- ctx.ui.setStatus("bmad", `BMAD ${state.phase} | story ${activeStory}`);
13
+ const modelLine = meta?.model ? ` | ${meta.model}` : "";
14
+ const presetLine = meta?.preset ? ` | ${meta.preset}` : "";
15
+ const thinkingLine = meta?.thinking ? ` | ${meta.thinking}` : "";
16
+
17
+ ctx.ui.setStatus("bmad", `BMAD ${state.phase} | story ${activeStory}${presetLine}${thinkingLine}`);
8
18
  ctx.ui.setWidget("bmad", [
9
19
  `Phase: ${state.phase}`,
10
20
  `Active: ${state.activeStory ?? "none"}`,
11
21
  `Ready: ${state.nextReadyStory ?? "none"}`,
12
22
  `Next: ${next.command} — ${next.summary}`,
23
+ `Preset: ${meta?.preset ?? "default"}${thinkingLine}${modelLine}`,
13
24
  ]);
14
25
  }
15
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-bmad-flow",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Pi-native orchestration overlay for BMAD workflows",
6
6
  "keywords": [
package/scripts/check.mjs CHANGED
@@ -34,6 +34,7 @@ function main() {
34
34
  "extensions/bmad-orchestrator/commands.ts",
35
35
  "extensions/bmad-orchestrator/detector.ts",
36
36
  "extensions/bmad-orchestrator/packets.ts",
37
+ "extensions/bmad-orchestrator/policy.ts",
37
38
  "extensions/bmad-orchestrator/tool.ts",
38
39
  "extensions/bmad-orchestrator/ui.ts",
39
40
  "scripts/bootstrap.mjs",