@hyperdrive.bot/bmad-workflow 1.0.20 → 1.0.22
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.
|
@@ -27,6 +27,7 @@ export default class Workflow extends Command {
|
|
|
27
27
|
'auto-fix': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
28
|
cwd: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
29
29
|
'dev-agent': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
30
|
+
'sm-agent': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
30
31
|
'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
31
32
|
'epic-interval': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
32
33
|
parallel: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -60,6 +60,9 @@ export default class Workflow extends Command {
|
|
|
60
60
|
'dev-agent': Flags.string({
|
|
61
61
|
description: 'Absolute path to a custom dev agent file (default: .bmad-core/agents/dev.md)',
|
|
62
62
|
}),
|
|
63
|
+
'sm-agent': Flags.string({
|
|
64
|
+
description: 'Absolute path to a custom SM (scrum master) agent file (default: .bmad-core/agents/sm.md)',
|
|
65
|
+
}),
|
|
63
66
|
'dry-run': Flags.boolean({
|
|
64
67
|
default: false,
|
|
65
68
|
description: 'Preview actions without execution',
|
|
@@ -281,6 +284,7 @@ export default class Workflow extends Command {
|
|
|
281
284
|
reviewScanners: flags['review-scanners'],
|
|
282
285
|
reviewTimeout: flags['review-timeout'],
|
|
283
286
|
skipDev: flags['skip-dev'],
|
|
287
|
+
smAgent: flags['sm-agent'],
|
|
284
288
|
skipEpics: flags['skip-epics'],
|
|
285
289
|
skipStories: flags['skip-stories'],
|
|
286
290
|
storyInterval: flags['story-interval'],
|
|
@@ -23,6 +23,14 @@ export interface WorkflowConfig {
|
|
|
23
23
|
* @example '/Users/marcelo/Developer/ds/super-repo/_bmad/bmm/agents/ibra.md'
|
|
24
24
|
*/
|
|
25
25
|
devAgent?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Absolute path to a custom SM (scrum master) agent file
|
|
28
|
+
*
|
|
29
|
+
* When specified, this file is used instead of the default `.bmad-core/agents/sm.md`
|
|
30
|
+
* in epic and story phase prompts.
|
|
31
|
+
* @example '/Users/marcelo/Developer/ds/super-repo/_bmad/bmm/agents/sm-custom.md'
|
|
32
|
+
*/
|
|
33
|
+
smAgent?: string;
|
|
26
34
|
/**
|
|
27
35
|
* Working directory for agent execution
|
|
28
36
|
*
|
|
@@ -118,6 +118,8 @@ export interface EpicPromptOptions {
|
|
|
118
118
|
prefix: string;
|
|
119
119
|
/** Reference file paths */
|
|
120
120
|
references: string[];
|
|
121
|
+
/** Absolute path to a custom SM agent file (optional) */
|
|
122
|
+
smAgent?: string;
|
|
121
123
|
}
|
|
122
124
|
/**
|
|
123
125
|
* Options for building a story creation prompt
|
|
@@ -133,6 +135,8 @@ export interface StoryPromptOptions {
|
|
|
133
135
|
prefix: string;
|
|
134
136
|
/** Reference file paths */
|
|
135
137
|
references: string[];
|
|
138
|
+
/** Absolute path to a custom SM agent file (optional) */
|
|
139
|
+
smAgent?: string;
|
|
136
140
|
}
|
|
137
141
|
/**
|
|
138
142
|
* WorkflowOrchestrator service for coordinating multi-phase workflows
|
|
@@ -726,6 +730,13 @@ export declare class WorkflowOrchestrator {
|
|
|
726
730
|
* @private
|
|
727
731
|
*/
|
|
728
732
|
private sleep;
|
|
733
|
+
/**
|
|
734
|
+
* Parse the `### Dev Context` section from a story file's content.
|
|
735
|
+
*
|
|
736
|
+
* Returns sidecar reference paths and an optional deploy target string.
|
|
737
|
+
* If the section is missing or empty, returns empty arrays / undefined (backward compatible).
|
|
738
|
+
*/
|
|
739
|
+
private parseDevContext;
|
|
729
740
|
/**
|
|
730
741
|
* Update story status in file
|
|
731
742
|
*
|
|
@@ -170,10 +170,11 @@ export class WorkflowOrchestrator {
|
|
|
170
170
|
* @private
|
|
171
171
|
*/
|
|
172
172
|
buildEpicPrompt(epic, options) {
|
|
173
|
-
const { cwd, outputPath, prdPath, references } = options;
|
|
173
|
+
const { cwd, outputPath, prdPath, references, smAgent } = options;
|
|
174
174
|
const referencesText = references.length > 0 ? `\nReferences: ${references.join(', ')}` : '';
|
|
175
175
|
const cwdText = cwd ? `\n\nWorking directory: ${cwd}` : '';
|
|
176
|
-
|
|
176
|
+
const agentRef = smAgent ? `@${smAgent}` : `@.bmad-core/agents/sm.md`;
|
|
177
|
+
return `${agentRef}${cwdText}
|
|
177
178
|
|
|
178
179
|
Create epic '${epic.number}: ${epic.title}' for PRD '${prdPath}'.${referencesText}.
|
|
179
180
|
|
|
@@ -216,10 +217,11 @@ Write output to: '${outputPath}'`;
|
|
|
216
217
|
* @private
|
|
217
218
|
*/
|
|
218
219
|
buildStoryPrompt(story, options) {
|
|
219
|
-
const { cwd, epicPath, outputPath, references } = options;
|
|
220
|
+
const { cwd, epicPath, outputPath, references, smAgent } = options;
|
|
220
221
|
const referencesText = references.length > 0 ? `\nReferences: ${references.join(', ')}` : '';
|
|
221
222
|
const cwdText = cwd ? `\n\nWorking directory: ${cwd}` : '';
|
|
222
|
-
|
|
223
|
+
const agentRef = smAgent ? `@${smAgent}` : `@.bmad-core/agents/sm.md`;
|
|
224
|
+
return `${agentRef}${cwdText}
|
|
223
225
|
|
|
224
226
|
Create story '${story.fullNumber}: ${story.title}' for epic '${epicPath}'. ${referencesText}
|
|
225
227
|
|
|
@@ -630,8 +632,10 @@ Write output to: ${outputPath}`;
|
|
|
630
632
|
prompt += `Working directory: ${config.cwd}\n\n`;
|
|
631
633
|
}
|
|
632
634
|
prompt += `*develop-story ${storyFilePath}\n\n`;
|
|
633
|
-
//
|
|
634
|
-
const
|
|
635
|
+
// Parse Dev Context section for sidecars and deploy target
|
|
636
|
+
const devContext = this.parseDevContext(storyContent);
|
|
637
|
+
// Combine auto-detected references with user-provided references and sidecars
|
|
638
|
+
const allReferences = [...autoReferences, ...(config.references || []), ...devContext.sidecarRefs];
|
|
635
639
|
if (allReferences.length > 0) {
|
|
636
640
|
prompt += 'References:\n';
|
|
637
641
|
for (const ref of allReferences) {
|
|
@@ -639,6 +643,10 @@ Write output to: ${outputPath}`;
|
|
|
639
643
|
}
|
|
640
644
|
prompt += '\n';
|
|
641
645
|
}
|
|
646
|
+
// Add deploy target context if specified in story
|
|
647
|
+
if (devContext.deployTarget) {
|
|
648
|
+
prompt += `Deploy target: ${devContext.deployTarget}\n\n`;
|
|
649
|
+
}
|
|
642
650
|
prompt += '*yolo mode*\n';
|
|
643
651
|
// Generate unique spawn ID
|
|
644
652
|
const spawnId = `dev-${story.fullNumber}-${storyStartTime}`;
|
|
@@ -905,8 +913,10 @@ Write output to: ${outputPath}`;
|
|
|
905
913
|
prompt += `Working directory: ${config.cwd}\n\n`;
|
|
906
914
|
}
|
|
907
915
|
prompt += `Implement story: ${storyFilePath}\n\n`;
|
|
908
|
-
//
|
|
909
|
-
const
|
|
916
|
+
// Parse Dev Context section for sidecars and deploy target
|
|
917
|
+
const devContext = this.parseDevContext(storyContent);
|
|
918
|
+
// Combine auto-detected references with user-provided references and sidecars
|
|
919
|
+
const allReferences = [...autoReferences, ...(config.references || []), ...devContext.sidecarRefs];
|
|
910
920
|
if (allReferences.length > 0) {
|
|
911
921
|
prompt += 'References:\n';
|
|
912
922
|
for (const ref of allReferences) {
|
|
@@ -914,6 +924,10 @@ Write output to: ${outputPath}`;
|
|
|
914
924
|
}
|
|
915
925
|
prompt += '\n';
|
|
916
926
|
}
|
|
927
|
+
// Add deploy target context if specified in story
|
|
928
|
+
if (devContext.deployTarget) {
|
|
929
|
+
prompt += `Deploy target: ${devContext.deployTarget}\n\n`;
|
|
930
|
+
}
|
|
917
931
|
prompt += '*yolo mode*\n';
|
|
918
932
|
// Generate unique spawn ID and timestamp
|
|
919
933
|
const spawnStartTime = Date.now();
|
|
@@ -1241,6 +1255,7 @@ Write output to: ${outputPath}`;
|
|
|
1241
1255
|
prdPath: prdFilePath,
|
|
1242
1256
|
prefix,
|
|
1243
1257
|
references: config.references,
|
|
1258
|
+
smAgent: config.smAgent,
|
|
1244
1259
|
});
|
|
1245
1260
|
const prompt = mcpPrefix ? `${mcpPrefix}\n\n${basePrompt}` : basePrompt;
|
|
1246
1261
|
// Log prompt if verbose
|
|
@@ -2232,6 +2247,7 @@ Write output to: ${outputPath}`;
|
|
|
2232
2247
|
outputPath: storyFilePath,
|
|
2233
2248
|
prefix,
|
|
2234
2249
|
references: config.references,
|
|
2250
|
+
smAgent: config.smAgent,
|
|
2235
2251
|
});
|
|
2236
2252
|
const prompt = mcpPrefix ? `${mcpPrefix}\n\n${basePrompt}` : basePrompt;
|
|
2237
2253
|
// Log prompt if verbose
|
|
@@ -2556,6 +2572,7 @@ Write output to: ${outputPath}`;
|
|
|
2556
2572
|
outputPath: storyFilePath,
|
|
2557
2573
|
prefix,
|
|
2558
2574
|
references: config.references,
|
|
2575
|
+
smAgent: config.smAgent,
|
|
2559
2576
|
});
|
|
2560
2577
|
const prompt = mcpPrefix ? `${mcpPrefix}\n\n${basePrompt}` : basePrompt;
|
|
2561
2578
|
// Log prompt if verbose
|
|
@@ -3080,6 +3097,49 @@ Write output to: ${outputPath}`;
|
|
|
3080
3097
|
async sleep(ms) {
|
|
3081
3098
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
3082
3099
|
}
|
|
3100
|
+
/**
|
|
3101
|
+
* Parse the `### Dev Context` section from a story file's content.
|
|
3102
|
+
*
|
|
3103
|
+
* Returns sidecar reference paths and an optional deploy target string.
|
|
3104
|
+
* If the section is missing or empty, returns empty arrays / undefined (backward compatible).
|
|
3105
|
+
*/
|
|
3106
|
+
parseDevContext(storyContent) {
|
|
3107
|
+
const sidecarRefs = [];
|
|
3108
|
+
let deployTarget;
|
|
3109
|
+
// Find the ### Dev Context section
|
|
3110
|
+
const devCtxMatch = storyContent.match(/^### Dev Context\s*$/m);
|
|
3111
|
+
if (!devCtxMatch || devCtxMatch.index === undefined) {
|
|
3112
|
+
return { deployTarget, sidecarRefs };
|
|
3113
|
+
}
|
|
3114
|
+
// Extract section content up to the next heading or end of file
|
|
3115
|
+
const sectionStart = devCtxMatch.index + devCtxMatch[0].length;
|
|
3116
|
+
const nextHeadingMatch = storyContent.slice(sectionStart).match(/^#{1,3} /m);
|
|
3117
|
+
const sectionEnd = nextHeadingMatch?.index !== undefined ? sectionStart + nextHeadingMatch.index : storyContent.length;
|
|
3118
|
+
const sectionContent = storyContent.slice(sectionStart, sectionEnd);
|
|
3119
|
+
// Parse Sidecars line — supports "- **Sidecars:**" or "- Sidecars:" (flexible)
|
|
3120
|
+
const sidecarsMatch = sectionContent.match(/^-\s+\*{0,2}Sidecars:?\*{0,2}\s*(.+)$/im);
|
|
3121
|
+
if (sidecarsMatch?.[1]) {
|
|
3122
|
+
const raw = sidecarsMatch[1].trim();
|
|
3123
|
+
for (const part of raw.split(',')) {
|
|
3124
|
+
const name = part.trim();
|
|
3125
|
+
if (name.length === 0)
|
|
3126
|
+
continue;
|
|
3127
|
+
// If already a path, use as-is; otherwise prefix with _bmad/bmm/agents/
|
|
3128
|
+
if (name.includes('/')) {
|
|
3129
|
+
sidecarRefs.push(name);
|
|
3130
|
+
}
|
|
3131
|
+
else {
|
|
3132
|
+
sidecarRefs.push(`_bmad/bmm/agents/${name}`);
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
// Parse Deploy target line
|
|
3137
|
+
const deployMatch = sectionContent.match(/^-\s+\*{0,2}Deploy target:?\*{0,2}\s*(.+)$/im);
|
|
3138
|
+
if (deployMatch?.[1]) {
|
|
3139
|
+
deployTarget = deployMatch[1].trim();
|
|
3140
|
+
}
|
|
3141
|
+
return { deployTarget, sidecarRefs };
|
|
3142
|
+
}
|
|
3083
3143
|
/**
|
|
3084
3144
|
* Update story status in file
|
|
3085
3145
|
*
|
package/package.json
CHANGED