@hyperdrive.bot/bmad-workflow 1.0.2
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/LICENSE +21 -0
- package/README.md +1017 -0
- package/bin/dev +5 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/config/show.d.ts +34 -0
- package/dist/commands/config/show.js +108 -0
- package/dist/commands/config/validate.d.ts +29 -0
- package/dist/commands/config/validate.js +131 -0
- package/dist/commands/decompose.d.ts +79 -0
- package/dist/commands/decompose.js +327 -0
- package/dist/commands/demo.d.ts +18 -0
- package/dist/commands/demo.js +107 -0
- package/dist/commands/epics/create.d.ts +123 -0
- package/dist/commands/epics/create.js +459 -0
- package/dist/commands/epics/list.d.ts +120 -0
- package/dist/commands/epics/list.js +280 -0
- package/dist/commands/hello/index.d.ts +12 -0
- package/dist/commands/hello/index.js +34 -0
- package/dist/commands/hello/world.d.ts +8 -0
- package/dist/commands/hello/world.js +24 -0
- package/dist/commands/prd/fix.d.ts +39 -0
- package/dist/commands/prd/fix.js +140 -0
- package/dist/commands/prd/validate.d.ts +112 -0
- package/dist/commands/prd/validate.js +302 -0
- package/dist/commands/stories/create.d.ts +95 -0
- package/dist/commands/stories/create.js +431 -0
- package/dist/commands/stories/develop.d.ts +91 -0
- package/dist/commands/stories/develop.js +460 -0
- package/dist/commands/stories/list.d.ts +84 -0
- package/dist/commands/stories/list.js +291 -0
- package/dist/commands/stories/move.d.ts +66 -0
- package/dist/commands/stories/move.js +273 -0
- package/dist/commands/stories/qa.d.ts +99 -0
- package/dist/commands/stories/qa.js +530 -0
- package/dist/commands/workflow.d.ts +97 -0
- package/dist/commands/workflow.js +390 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/models/agent-options.d.ts +50 -0
- package/dist/models/agent-options.js +1 -0
- package/dist/models/agent-result.d.ts +29 -0
- package/dist/models/agent-result.js +1 -0
- package/dist/models/index.d.ts +10 -0
- package/dist/models/index.js +10 -0
- package/dist/models/phase-result.d.ts +65 -0
- package/dist/models/phase-result.js +7 -0
- package/dist/models/provider.d.ts +28 -0
- package/dist/models/provider.js +18 -0
- package/dist/models/story.d.ts +154 -0
- package/dist/models/story.js +18 -0
- package/dist/models/workflow-config.d.ts +148 -0
- package/dist/models/workflow-config.js +1 -0
- package/dist/models/workflow-result.d.ts +164 -0
- package/dist/models/workflow-result.js +7 -0
- package/dist/services/agents/agent-runner-factory.d.ts +31 -0
- package/dist/services/agents/agent-runner-factory.js +44 -0
- package/dist/services/agents/agent-runner.d.ts +46 -0
- package/dist/services/agents/agent-runner.js +29 -0
- package/dist/services/agents/claude-agent-runner.d.ts +81 -0
- package/dist/services/agents/claude-agent-runner.js +332 -0
- package/dist/services/agents/gemini-agent-runner.d.ts +82 -0
- package/dist/services/agents/gemini-agent-runner.js +350 -0
- package/dist/services/agents/index.d.ts +7 -0
- package/dist/services/agents/index.js +7 -0
- package/dist/services/file-system/file-manager.d.ts +110 -0
- package/dist/services/file-system/file-manager.js +223 -0
- package/dist/services/file-system/glob-matcher.d.ts +75 -0
- package/dist/services/file-system/glob-matcher.js +126 -0
- package/dist/services/file-system/path-resolver.d.ts +183 -0
- package/dist/services/file-system/path-resolver.js +400 -0
- package/dist/services/logging/workflow-logger.d.ts +232 -0
- package/dist/services/logging/workflow-logger.js +552 -0
- package/dist/services/orchestration/batch-processor.d.ts +113 -0
- package/dist/services/orchestration/batch-processor.js +187 -0
- package/dist/services/orchestration/dependency-graph-executor.d.ts +60 -0
- package/dist/services/orchestration/dependency-graph-executor.js +447 -0
- package/dist/services/orchestration/index.d.ts +10 -0
- package/dist/services/orchestration/index.js +8 -0
- package/dist/services/orchestration/input-detector.d.ts +125 -0
- package/dist/services/orchestration/input-detector.js +381 -0
- package/dist/services/orchestration/story-queue.d.ts +94 -0
- package/dist/services/orchestration/story-queue.js +170 -0
- package/dist/services/orchestration/story-type-detector.d.ts +80 -0
- package/dist/services/orchestration/story-type-detector.js +258 -0
- package/dist/services/orchestration/task-decomposition-service.d.ts +67 -0
- package/dist/services/orchestration/task-decomposition-service.js +607 -0
- package/dist/services/orchestration/workflow-orchestrator.d.ts +659 -0
- package/dist/services/orchestration/workflow-orchestrator.js +2201 -0
- package/dist/services/parsers/epic-parser.d.ts +117 -0
- package/dist/services/parsers/epic-parser.js +264 -0
- package/dist/services/parsers/prd-fixer.d.ts +86 -0
- package/dist/services/parsers/prd-fixer.js +194 -0
- package/dist/services/parsers/prd-parser.d.ts +123 -0
- package/dist/services/parsers/prd-parser.js +286 -0
- package/dist/services/parsers/standalone-story-parser.d.ts +114 -0
- package/dist/services/parsers/standalone-story-parser.js +255 -0
- package/dist/services/parsers/story-parser-factory.d.ts +81 -0
- package/dist/services/parsers/story-parser-factory.js +108 -0
- package/dist/services/parsers/story-parser.d.ts +122 -0
- package/dist/services/parsers/story-parser.js +262 -0
- package/dist/services/scaffolding/decompose-session-scaffolder.d.ts +74 -0
- package/dist/services/scaffolding/decompose-session-scaffolder.js +315 -0
- package/dist/services/scaffolding/file-scaffolder.d.ts +94 -0
- package/dist/services/scaffolding/file-scaffolder.js +314 -0
- package/dist/services/validation/config-validator.d.ts +88 -0
- package/dist/services/validation/config-validator.js +167 -0
- package/dist/types/task-graph.d.ts +142 -0
- package/dist/types/task-graph.js +5 -0
- package/dist/utils/colors.d.ts +49 -0
- package/dist/utils/colors.js +50 -0
- package/dist/utils/error-formatter.d.ts +64 -0
- package/dist/utils/error-formatter.js +279 -0
- package/dist/utils/errors.d.ts +170 -0
- package/dist/utils/errors.js +233 -0
- package/dist/utils/formatters.d.ts +84 -0
- package/dist/utils/formatters.js +162 -0
- package/dist/utils/logger.d.ts +63 -0
- package/dist/utils/logger.js +78 -0
- package/dist/utils/progress.d.ts +104 -0
- package/dist/utils/progress.js +161 -0
- package/dist/utils/retry.d.ts +114 -0
- package/dist/utils/retry.js +160 -0
- package/dist/utils/shared-flags.d.ts +28 -0
- package/dist/utils/shared-flags.js +43 -0
- package/package.json +119 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Scaffolder Service
|
|
3
|
+
*
|
|
4
|
+
* Creates scaffolded markdown files for epics and stories with pre-populated
|
|
5
|
+
* metadata headers and empty content sections following template structure.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const scaffolder = new FileScaffolder(logger)
|
|
10
|
+
* const epicContent = scaffolder.scaffoldEpic({
|
|
11
|
+
* epicNumber: 1,
|
|
12
|
+
* epicTitle: 'Foundation Setup',
|
|
13
|
+
* prefix: 'SIGN-TEMPLATES'
|
|
14
|
+
* })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
import type pino from 'pino';
|
|
18
|
+
/**
|
|
19
|
+
* Epic scaffolding data
|
|
20
|
+
*/
|
|
21
|
+
export interface EpicScaffoldData {
|
|
22
|
+
/**
|
|
23
|
+
* Epic number (1, 2, 3, etc.)
|
|
24
|
+
*/
|
|
25
|
+
epicNumber: number;
|
|
26
|
+
/**
|
|
27
|
+
* Epic title
|
|
28
|
+
*/
|
|
29
|
+
epicTitle: string;
|
|
30
|
+
/**
|
|
31
|
+
* Project prefix (e.g., 'SIGN-TEMPLATES', 'USER-GROUPS')
|
|
32
|
+
*/
|
|
33
|
+
prefix: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Story scaffolding data
|
|
37
|
+
*/
|
|
38
|
+
export interface StoryScaffoldData {
|
|
39
|
+
/**
|
|
40
|
+
* Epic number
|
|
41
|
+
*/
|
|
42
|
+
epicNumber: number;
|
|
43
|
+
/**
|
|
44
|
+
* Story number within epic
|
|
45
|
+
*/
|
|
46
|
+
storyNumber: number;
|
|
47
|
+
/**
|
|
48
|
+
* Story title
|
|
49
|
+
*/
|
|
50
|
+
storyTitle: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* File Scaffolder Service
|
|
54
|
+
*
|
|
55
|
+
* Generates structured markdown files with populated metadata sections
|
|
56
|
+
* and empty content sections ready for AI agent population.
|
|
57
|
+
*/
|
|
58
|
+
export declare class FileScaffolder {
|
|
59
|
+
private readonly logger;
|
|
60
|
+
/**
|
|
61
|
+
* Create a new FileScaffolder instance
|
|
62
|
+
*
|
|
63
|
+
* @param logger - Logger instance for structured logging
|
|
64
|
+
*/
|
|
65
|
+
constructor(logger: pino.Logger);
|
|
66
|
+
/**
|
|
67
|
+
* Scaffold an epic markdown file
|
|
68
|
+
*
|
|
69
|
+
* Creates a structured epic file with:
|
|
70
|
+
* - Populated metadata: Epic ID, Status (Draft), Creation Date
|
|
71
|
+
* - Empty content sections: Epic Goal, Description, Stories, etc.
|
|
72
|
+
*
|
|
73
|
+
* @param data - Epic scaffolding data
|
|
74
|
+
* @returns Scaffolded epic markdown content
|
|
75
|
+
*/
|
|
76
|
+
scaffoldEpic(data: EpicScaffoldData): string;
|
|
77
|
+
/**
|
|
78
|
+
* Scaffold a story markdown file
|
|
79
|
+
*
|
|
80
|
+
* Creates a structured story file with:
|
|
81
|
+
* - Populated metadata: Status (Draft)
|
|
82
|
+
* - Empty content sections: Story, Acceptance Criteria, Tasks, etc.
|
|
83
|
+
*
|
|
84
|
+
* @param data - Story scaffolding data
|
|
85
|
+
* @returns Scaffolded story markdown content
|
|
86
|
+
*/
|
|
87
|
+
scaffoldStory(data: StoryScaffoldData): string;
|
|
88
|
+
/**
|
|
89
|
+
* Get current date in YYYY-MM-DD format
|
|
90
|
+
*
|
|
91
|
+
* @returns Current date string
|
|
92
|
+
*/
|
|
93
|
+
private getCurrentDate;
|
|
94
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Scaffolder Service
|
|
3
|
+
*
|
|
4
|
+
* Creates scaffolded markdown files for epics and stories with pre-populated
|
|
5
|
+
* metadata headers and empty content sections following template structure.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const scaffolder = new FileScaffolder(logger)
|
|
10
|
+
* const epicContent = scaffolder.scaffoldEpic({
|
|
11
|
+
* epicNumber: 1,
|
|
12
|
+
* epicTitle: 'Foundation Setup',
|
|
13
|
+
* prefix: 'SIGN-TEMPLATES'
|
|
14
|
+
* })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* File Scaffolder Service
|
|
19
|
+
*
|
|
20
|
+
* Generates structured markdown files with populated metadata sections
|
|
21
|
+
* and empty content sections ready for AI agent population.
|
|
22
|
+
*/
|
|
23
|
+
export class FileScaffolder {
|
|
24
|
+
logger;
|
|
25
|
+
/**
|
|
26
|
+
* Create a new FileScaffolder instance
|
|
27
|
+
*
|
|
28
|
+
* @param logger - Logger instance for structured logging
|
|
29
|
+
*/
|
|
30
|
+
constructor(logger) {
|
|
31
|
+
this.logger = logger;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Scaffold an epic markdown file
|
|
35
|
+
*
|
|
36
|
+
* Creates a structured epic file with:
|
|
37
|
+
* - Populated metadata: Epic ID, Status (Draft), Creation Date
|
|
38
|
+
* - Empty content sections: Epic Goal, Description, Stories, etc.
|
|
39
|
+
*
|
|
40
|
+
* @param data - Epic scaffolding data
|
|
41
|
+
* @returns Scaffolded epic markdown content
|
|
42
|
+
*/
|
|
43
|
+
scaffoldEpic(data) {
|
|
44
|
+
const epicId = `${data.prefix}-EPIC-${data.epicNumber}`;
|
|
45
|
+
const currentDate = this.getCurrentDate();
|
|
46
|
+
this.logger.info({
|
|
47
|
+
epicId,
|
|
48
|
+
epicNumber: data.epicNumber,
|
|
49
|
+
epicTitle: data.epicTitle,
|
|
50
|
+
}, 'Scaffolding epic file');
|
|
51
|
+
// Hardcoded epic scaffold following epic-tmpl.yaml structure
|
|
52
|
+
const content = `# Epic ${data.epicNumber}: ${data.epicTitle}
|
|
53
|
+
|
|
54
|
+
<!-- Powered by BMAD™ Core -->
|
|
55
|
+
|
|
56
|
+
## Epic Header
|
|
57
|
+
|
|
58
|
+
**Epic ID:** ${epicId}
|
|
59
|
+
**Epic Type:** _[To be determined by sm agent]_
|
|
60
|
+
**Status:** Draft
|
|
61
|
+
**Priority:** _[To be determined by sm agent]_
|
|
62
|
+
**Created:** ${currentDate}
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Epic Goal
|
|
67
|
+
|
|
68
|
+
_[AI Agent will populate: 2-3 sentences describing what this epic will accomplish and the end state it will deliver]_
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Epic Description
|
|
73
|
+
|
|
74
|
+
### Existing System Context
|
|
75
|
+
|
|
76
|
+
_[AI Agent will populate if Brownfield Enhancement]_
|
|
77
|
+
|
|
78
|
+
**Current relevant functionality:**
|
|
79
|
+
|
|
80
|
+
**Technology stack:**
|
|
81
|
+
|
|
82
|
+
**Integration points:**
|
|
83
|
+
|
|
84
|
+
### Enhancement Details
|
|
85
|
+
|
|
86
|
+
#### What's Being Added/Changed
|
|
87
|
+
|
|
88
|
+
_[AI Agent will populate: Specific deliverables with file locations]_
|
|
89
|
+
|
|
90
|
+
#### How It Integrates
|
|
91
|
+
|
|
92
|
+
_[AI Agent will populate: Integration approach and patterns]_
|
|
93
|
+
|
|
94
|
+
#### Success Criteria
|
|
95
|
+
|
|
96
|
+
_[AI Agent will populate: Measurable outcomes defining "done"]_
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Stories
|
|
101
|
+
|
|
102
|
+
_[AI Agent will populate: List of stories with descriptions and key tasks]_
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Compatibility Requirements
|
|
107
|
+
|
|
108
|
+
_[AI Agent will populate: Backward compatibility checklist]_
|
|
109
|
+
|
|
110
|
+
- [ ] Existing APIs remain unchanged (or document breaking changes)
|
|
111
|
+
- [ ] Database schema changes are backward compatible
|
|
112
|
+
- [ ] UI changes follow existing patterns
|
|
113
|
+
- [ ] Performance impact is minimal
|
|
114
|
+
- [ ] No regression in existing functionality
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Risk Mitigation
|
|
119
|
+
|
|
120
|
+
### Primary Risk
|
|
121
|
+
|
|
122
|
+
_[AI Agent will populate]_
|
|
123
|
+
|
|
124
|
+
### Mitigation
|
|
125
|
+
|
|
126
|
+
_[AI Agent will populate: Specific actions to prevent or reduce risk]_
|
|
127
|
+
|
|
128
|
+
### Rollback Plan
|
|
129
|
+
|
|
130
|
+
_[AI Agent will populate: Step-by-step rollback procedure]_
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Definition of Done
|
|
135
|
+
|
|
136
|
+
- [ ] All stories completed with acceptance criteria met
|
|
137
|
+
- [ ] Unit test coverage ≥ 80% for new code
|
|
138
|
+
- [ ] Integration tests verify end-to-end flows
|
|
139
|
+
- [ ] TypeScript compilation passes with strict mode
|
|
140
|
+
- [ ] Code follows project style guides
|
|
141
|
+
- [ ] Documentation updated appropriately
|
|
142
|
+
- [ ] No regression in existing features verified
|
|
143
|
+
- [ ] Performance targets met
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Validation Checklist
|
|
148
|
+
|
|
149
|
+
### Scope Validation
|
|
150
|
+
|
|
151
|
+
- [ ] Epic contains appropriate number of stories (1-10)
|
|
152
|
+
- [ ] No major architectural changes (or documented if required)
|
|
153
|
+
- [ ] Enhancement follows existing patterns where applicable
|
|
154
|
+
- [ ] Integration complexity is manageable
|
|
155
|
+
|
|
156
|
+
### Risk Assessment
|
|
157
|
+
|
|
158
|
+
- [ ] Risk to existing system is acceptable
|
|
159
|
+
- [ ] Rollback plan is feasible
|
|
160
|
+
- [ ] Testing approach covers critical paths
|
|
161
|
+
- [ ] Team has sufficient knowledge/expertise
|
|
162
|
+
|
|
163
|
+
### Completeness Check
|
|
164
|
+
|
|
165
|
+
- [ ] Epic goal is clear and achievable
|
|
166
|
+
- [ ] Stories are properly scoped and sequenced
|
|
167
|
+
- [ ] Success criteria are measurable
|
|
168
|
+
- [ ] Dependencies are identified
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Technical Implementation Notes
|
|
173
|
+
|
|
174
|
+
_[AI Agent will populate if needed: Key integration patterns, architecture decisions, file locations, testing strategy]_
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Story Manager Handoff
|
|
179
|
+
|
|
180
|
+
_[AI Agent will populate: Handoff message to Story Manager with context and requirements]_
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Change Log
|
|
185
|
+
|
|
186
|
+
| Date | Version | Description | Author |
|
|
187
|
+
|------|---------|-------------|--------|
|
|
188
|
+
| ${currentDate} | 1.0 | Epic created | AI Agent |
|
|
189
|
+
`;
|
|
190
|
+
this.logger.debug({ epicId, length: content.length }, 'Epic scaffold generated');
|
|
191
|
+
return content;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Scaffold a story markdown file
|
|
195
|
+
*
|
|
196
|
+
* Creates a structured story file with:
|
|
197
|
+
* - Populated metadata: Status (Draft)
|
|
198
|
+
* - Empty content sections: Story, Acceptance Criteria, Tasks, etc.
|
|
199
|
+
*
|
|
200
|
+
* @param data - Story scaffolding data
|
|
201
|
+
* @returns Scaffolded story markdown content
|
|
202
|
+
*/
|
|
203
|
+
scaffoldStory(data) {
|
|
204
|
+
const storyId = `${data.epicNumber}.${data.storyNumber}`;
|
|
205
|
+
const currentDate = this.getCurrentDate();
|
|
206
|
+
this.logger.info({
|
|
207
|
+
storyId,
|
|
208
|
+
storyTitle: data.storyTitle,
|
|
209
|
+
}, 'Scaffolding story file');
|
|
210
|
+
// Hardcoded story scaffold following story-tmpl.yaml structure
|
|
211
|
+
const content = `# Story ${storyId}: ${data.storyTitle}
|
|
212
|
+
|
|
213
|
+
<!-- Powered by BMAD™ Core -->
|
|
214
|
+
|
|
215
|
+
## Status
|
|
216
|
+
|
|
217
|
+
Draft
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Story
|
|
222
|
+
|
|
223
|
+
**As a** _[AI Agent will populate]_,
|
|
224
|
+
**I want** _[AI Agent will populate]_,
|
|
225
|
+
**so that** _[AI Agent will populate]_
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Acceptance Criteria
|
|
230
|
+
|
|
231
|
+
_[AI Agent will populate: Numbered list copied from epic]_
|
|
232
|
+
|
|
233
|
+
1. _[Criterion 1]_
|
|
234
|
+
2. _[Criterion 2]_
|
|
235
|
+
3. _[Criterion 3]_
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Tasks / Subtasks
|
|
240
|
+
|
|
241
|
+
_[AI Agent will populate: Break down into specific tasks with subtasks]_
|
|
242
|
+
|
|
243
|
+
- [ ] Task 1 (AC: #)
|
|
244
|
+
- [ ] Subtask 1.1
|
|
245
|
+
- [ ] Subtask 1.2
|
|
246
|
+
- [ ] Task 2 (AC: #)
|
|
247
|
+
- [ ] Subtask 2.1
|
|
248
|
+
- [ ] Task 3 (AC: #)
|
|
249
|
+
- [ ] Subtask 3.1
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Dev Notes
|
|
254
|
+
|
|
255
|
+
_[AI Agent will populate: Relevant architecture info, source tree context, and previous story notes]_
|
|
256
|
+
|
|
257
|
+
### Testing
|
|
258
|
+
|
|
259
|
+
_[AI Agent will populate: Testing standards, file locations, frameworks, patterns]_
|
|
260
|
+
|
|
261
|
+
- Test file location:
|
|
262
|
+
- Test standards:
|
|
263
|
+
- Testing frameworks:
|
|
264
|
+
- Specific requirements:
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Change Log
|
|
269
|
+
|
|
270
|
+
| Date | Version | Description | Author |
|
|
271
|
+
|------|---------|-------------|--------|
|
|
272
|
+
| ${currentDate} | 1.0 | Story created | AI Agent |
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Dev Agent Record
|
|
277
|
+
|
|
278
|
+
_[This section will be populated by the development agent during implementation]_
|
|
279
|
+
|
|
280
|
+
### Agent Model Used
|
|
281
|
+
|
|
282
|
+
_[AI Agent will record model and version]_
|
|
283
|
+
|
|
284
|
+
### Debug Log References
|
|
285
|
+
|
|
286
|
+
_[AI Agent will record debug log references]_
|
|
287
|
+
|
|
288
|
+
### Completion Notes List
|
|
289
|
+
|
|
290
|
+
_[AI Agent will record completion notes and issues encountered]_
|
|
291
|
+
|
|
292
|
+
### File List
|
|
293
|
+
|
|
294
|
+
_[AI Agent will list all files created, modified, or affected]_
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## QA Results
|
|
299
|
+
|
|
300
|
+
_[This section will be populated by QA Agent after review]_
|
|
301
|
+
`;
|
|
302
|
+
this.logger.debug({ length: content.length, storyId }, 'Story scaffold generated');
|
|
303
|
+
return content;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Get current date in YYYY-MM-DD format
|
|
307
|
+
*
|
|
308
|
+
* @returns Current date string
|
|
309
|
+
*/
|
|
310
|
+
getCurrentDate() {
|
|
311
|
+
const now = new Date();
|
|
312
|
+
return now.toISOString().split('T')[0];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigValidator Service
|
|
3
|
+
*
|
|
4
|
+
* Validates configuration files against schemas using Zod.
|
|
5
|
+
* Ensures configuration has all required fields with correct types and that
|
|
6
|
+
* referenced directories exist.
|
|
7
|
+
*/
|
|
8
|
+
import type pino from 'pino';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import type { FileManager } from '../file-system/file-manager.js';
|
|
11
|
+
/**
|
|
12
|
+
* Zod schema for core configuration
|
|
13
|
+
*
|
|
14
|
+
* Defines the expected structure of .bmad-core/core-config.yaml
|
|
15
|
+
* with all required fields for the BMAD Orchestrator CLI.
|
|
16
|
+
*/
|
|
17
|
+
declare const configSchema: z.ZodObject<{
|
|
18
|
+
devStoryLocation: z.ZodString;
|
|
19
|
+
prd: z.ZodOptional<z.ZodObject<{
|
|
20
|
+
prdFile: z.ZodOptional<z.ZodString>;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
qa: z.ZodOptional<z.ZodObject<{
|
|
23
|
+
qaLocation: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, z.core.$strip>>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
/**
|
|
27
|
+
* Inferred TypeScript type from Zod schema
|
|
28
|
+
*/
|
|
29
|
+
export type CoreConfig = z.infer<typeof configSchema>;
|
|
30
|
+
/**
|
|
31
|
+
* ConfigValidator service validates configuration files against schemas
|
|
32
|
+
*
|
|
33
|
+
* Uses Zod for schema validation and provides clear, actionable error messages
|
|
34
|
+
* when validation fails. Also validates that referenced directories exist.
|
|
35
|
+
*/
|
|
36
|
+
export declare class ConfigValidator {
|
|
37
|
+
/**
|
|
38
|
+
* FileManager instance for directory existence checks
|
|
39
|
+
*/
|
|
40
|
+
private readonly fileManager;
|
|
41
|
+
/**
|
|
42
|
+
* Logger instance for validation operations
|
|
43
|
+
*/
|
|
44
|
+
private readonly logger;
|
|
45
|
+
/**
|
|
46
|
+
* Create a new ConfigValidator instance
|
|
47
|
+
*
|
|
48
|
+
* @param fileManager - FileManager instance for file system operations
|
|
49
|
+
* @param logger - Pino logger instance for logging validation operations
|
|
50
|
+
* @example
|
|
51
|
+
* const logger = createLogger({ namespace: 'services:validation' })
|
|
52
|
+
* const fileManager = new FileManager(logger)
|
|
53
|
+
* const validator = new ConfigValidator(fileManager, logger)
|
|
54
|
+
*/
|
|
55
|
+
constructor(fileManager: FileManager, logger: pino.Logger);
|
|
56
|
+
/**
|
|
57
|
+
* Validate configuration object against schema
|
|
58
|
+
*
|
|
59
|
+
* Validates that:
|
|
60
|
+
* 1. All required fields are present
|
|
61
|
+
* 2. All fields have correct types
|
|
62
|
+
* 3. Referenced directories exist
|
|
63
|
+
*
|
|
64
|
+
* @param config - Unknown configuration object to validate
|
|
65
|
+
* @returns Validated CoreConfig object
|
|
66
|
+
* @throws {ValidationError} If validation fails with detailed error messages
|
|
67
|
+
* @example
|
|
68
|
+
* const config = { epicDir: 'docs/epics', storyDir: 'docs/stories', ... }
|
|
69
|
+
* const validConfig = validator.validate(config)
|
|
70
|
+
*/
|
|
71
|
+
validate(config: unknown): Promise<CoreConfig>;
|
|
72
|
+
/**
|
|
73
|
+
* Get custom error message and helpful suggestion based on Zod validation error
|
|
74
|
+
*
|
|
75
|
+
* @param error - Zod issue from validation failure
|
|
76
|
+
* @param config - The configuration object being validated
|
|
77
|
+
* @returns Object with error message and suggestion
|
|
78
|
+
*/
|
|
79
|
+
private getErrorMessageAndSuggestion;
|
|
80
|
+
/**
|
|
81
|
+
* Validate that all directory paths in config exist
|
|
82
|
+
*
|
|
83
|
+
* @param config - Validated configuration object
|
|
84
|
+
* @throws {ValidationError} If any directory does not exist
|
|
85
|
+
*/
|
|
86
|
+
private validateDirectories;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigValidator Service
|
|
3
|
+
*
|
|
4
|
+
* Validates configuration files against schemas using Zod.
|
|
5
|
+
* Ensures configuration has all required fields with correct types and that
|
|
6
|
+
* referenced directories exist.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { ValidationError } from '../../utils/errors.js';
|
|
10
|
+
/**
|
|
11
|
+
* Zod schema for core configuration
|
|
12
|
+
*
|
|
13
|
+
* Defines the expected structure of .bmad-core/core-config.yaml
|
|
14
|
+
* with all required fields for the BMAD Orchestrator CLI.
|
|
15
|
+
*/
|
|
16
|
+
const configSchema = z.object({
|
|
17
|
+
devStoryLocation: z.string().min(1, { message: 'Story directory path (devStoryLocation) is required' }),
|
|
18
|
+
prd: z
|
|
19
|
+
.object({
|
|
20
|
+
prdFile: z.string().optional(),
|
|
21
|
+
})
|
|
22
|
+
.optional(),
|
|
23
|
+
qa: z
|
|
24
|
+
.object({
|
|
25
|
+
qaLocation: z.string().optional(),
|
|
26
|
+
})
|
|
27
|
+
.optional(),
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* ConfigValidator service validates configuration files against schemas
|
|
31
|
+
*
|
|
32
|
+
* Uses Zod for schema validation and provides clear, actionable error messages
|
|
33
|
+
* when validation fails. Also validates that referenced directories exist.
|
|
34
|
+
*/
|
|
35
|
+
export class ConfigValidator {
|
|
36
|
+
/**
|
|
37
|
+
* FileManager instance for directory existence checks
|
|
38
|
+
*/
|
|
39
|
+
fileManager;
|
|
40
|
+
/**
|
|
41
|
+
* Logger instance for validation operations
|
|
42
|
+
*/
|
|
43
|
+
logger;
|
|
44
|
+
/**
|
|
45
|
+
* Create a new ConfigValidator instance
|
|
46
|
+
*
|
|
47
|
+
* @param fileManager - FileManager instance for file system operations
|
|
48
|
+
* @param logger - Pino logger instance for logging validation operations
|
|
49
|
+
* @example
|
|
50
|
+
* const logger = createLogger({ namespace: 'services:validation' })
|
|
51
|
+
* const fileManager = new FileManager(logger)
|
|
52
|
+
* const validator = new ConfigValidator(fileManager, logger)
|
|
53
|
+
*/
|
|
54
|
+
constructor(fileManager, logger) {
|
|
55
|
+
this.fileManager = fileManager;
|
|
56
|
+
this.logger = logger;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validate configuration object against schema
|
|
60
|
+
*
|
|
61
|
+
* Validates that:
|
|
62
|
+
* 1. All required fields are present
|
|
63
|
+
* 2. All fields have correct types
|
|
64
|
+
* 3. Referenced directories exist
|
|
65
|
+
*
|
|
66
|
+
* @param config - Unknown configuration object to validate
|
|
67
|
+
* @returns Validated CoreConfig object
|
|
68
|
+
* @throws {ValidationError} If validation fails with detailed error messages
|
|
69
|
+
* @example
|
|
70
|
+
* const config = { epicDir: 'docs/epics', storyDir: 'docs/stories', ... }
|
|
71
|
+
* const validConfig = validator.validate(config)
|
|
72
|
+
*/
|
|
73
|
+
async validate(config) {
|
|
74
|
+
this.logger.info('Validating configuration');
|
|
75
|
+
// Step 1: Validate schema (required fields, types)
|
|
76
|
+
const result = configSchema.safeParse(config);
|
|
77
|
+
if (!result.success) {
|
|
78
|
+
const firstError = result.error.issues[0];
|
|
79
|
+
const fieldPath = firstError.path.join('.');
|
|
80
|
+
// Get custom error message and suggestion
|
|
81
|
+
const { message: errorMessage, suggestion } = this.getErrorMessageAndSuggestion(firstError, config);
|
|
82
|
+
const fullMessage = `Configuration validation failed: ${errorMessage}. ${suggestion}`;
|
|
83
|
+
this.logger.error({ field: fieldPath }, 'Configuration validation failed: %s', errorMessage);
|
|
84
|
+
throw new ValidationError(fullMessage, {
|
|
85
|
+
field: fieldPath,
|
|
86
|
+
received: config?.[firstError.path[0]],
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const validConfig = result.data;
|
|
90
|
+
// Step 2: Validate directory existence
|
|
91
|
+
await this.validateDirectories(validConfig);
|
|
92
|
+
this.logger.info('Configuration validated successfully');
|
|
93
|
+
return validConfig;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get custom error message and helpful suggestion based on Zod validation error
|
|
97
|
+
*
|
|
98
|
+
* @param error - Zod issue from validation failure
|
|
99
|
+
* @param config - The configuration object being validated
|
|
100
|
+
* @returns Object with error message and suggestion
|
|
101
|
+
*/
|
|
102
|
+
getErrorMessageAndSuggestion(error, config) {
|
|
103
|
+
const fieldName = error.path[0];
|
|
104
|
+
const examples = {
|
|
105
|
+
devStoryLocation: 'docs/stories',
|
|
106
|
+
'prd.prdFile': 'docs/prd.md',
|
|
107
|
+
'qa.qaLocation': 'docs/qa',
|
|
108
|
+
};
|
|
109
|
+
const fieldDisplayNames = {
|
|
110
|
+
devStoryLocation: 'Story directory path (devStoryLocation)',
|
|
111
|
+
'prd.prdFile': 'PRD file path (prd.prdFile)',
|
|
112
|
+
'qa.qaLocation': 'QA location path (qa.qaLocation)',
|
|
113
|
+
};
|
|
114
|
+
const example = examples[fieldName] || 'path/to/directory';
|
|
115
|
+
const displayName = fieldDisplayNames[fieldName] || fieldName;
|
|
116
|
+
// Missing field or empty string
|
|
117
|
+
if (error.code === 'too_small') {
|
|
118
|
+
return {
|
|
119
|
+
message: `${displayName} is required`,
|
|
120
|
+
suggestion: `Add this field to .bmad-core/core-config.yaml with a valid path (e.g., "${example}").`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// Wrong type or missing field
|
|
124
|
+
if (error.code === 'invalid_type') {
|
|
125
|
+
const invalidTypeError = error;
|
|
126
|
+
// Check if field exists in config (to differentiate missing vs wrong type)
|
|
127
|
+
const configObj = config;
|
|
128
|
+
const fieldValue = configObj?.[fieldName];
|
|
129
|
+
const fieldIsMissing = fieldValue === undefined || fieldValue === null;
|
|
130
|
+
// If field is missing, provide custom message
|
|
131
|
+
if (fieldIsMissing) {
|
|
132
|
+
return {
|
|
133
|
+
message: `${displayName} is required`,
|
|
134
|
+
suggestion: `Add this field to .bmad-core/core-config.yaml with a valid path (e.g., "${example}").`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// Wrong type provided - use Zod's message which includes the types
|
|
138
|
+
return {
|
|
139
|
+
message: error.message, // e.g., "Invalid input: expected string, received number"
|
|
140
|
+
suggestion: `Update the value in .bmad-core/core-config.yaml to a valid ${invalidTypeError.expected}.`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// Generic fallback
|
|
144
|
+
return {
|
|
145
|
+
message: error.message,
|
|
146
|
+
suggestion: `Check the value for '${fieldName}' in .bmad-core/core-config.yaml.`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Validate that all directory paths in config exist
|
|
151
|
+
*
|
|
152
|
+
* @param config - Validated configuration object
|
|
153
|
+
* @throws {ValidationError} If any directory does not exist
|
|
154
|
+
*/
|
|
155
|
+
async validateDirectories(config) {
|
|
156
|
+
// Validate story directory exists
|
|
157
|
+
const storyDir = config.devStoryLocation;
|
|
158
|
+
const exists = await this.fileManager.fileExists(storyDir);
|
|
159
|
+
if (!exists) {
|
|
160
|
+
const message = `Configuration validation failed: Story directory '${storyDir}' does not exist. ` +
|
|
161
|
+
`Create the directory with 'mkdir -p ${storyDir}' or update 'devStoryLocation' in .bmad-core/core-config.yaml.`;
|
|
162
|
+
this.logger.error({ field: 'devStoryLocation', path: storyDir }, 'Directory validation failed: %s', message);
|
|
163
|
+
throw new ValidationError(message, { field: 'devStoryLocation', path: storyDir });
|
|
164
|
+
}
|
|
165
|
+
this.logger.debug({ field: 'devStoryLocation' }, 'Directory exists: %s', storyDir);
|
|
166
|
+
}
|
|
167
|
+
}
|