@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.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1017 -0
  3. package/bin/dev +5 -0
  4. package/bin/dev.cmd +3 -0
  5. package/bin/dev.js +5 -0
  6. package/bin/run +5 -0
  7. package/bin/run.cmd +3 -0
  8. package/bin/run.js +5 -0
  9. package/dist/commands/config/show.d.ts +34 -0
  10. package/dist/commands/config/show.js +108 -0
  11. package/dist/commands/config/validate.d.ts +29 -0
  12. package/dist/commands/config/validate.js +131 -0
  13. package/dist/commands/decompose.d.ts +79 -0
  14. package/dist/commands/decompose.js +327 -0
  15. package/dist/commands/demo.d.ts +18 -0
  16. package/dist/commands/demo.js +107 -0
  17. package/dist/commands/epics/create.d.ts +123 -0
  18. package/dist/commands/epics/create.js +459 -0
  19. package/dist/commands/epics/list.d.ts +120 -0
  20. package/dist/commands/epics/list.js +280 -0
  21. package/dist/commands/hello/index.d.ts +12 -0
  22. package/dist/commands/hello/index.js +34 -0
  23. package/dist/commands/hello/world.d.ts +8 -0
  24. package/dist/commands/hello/world.js +24 -0
  25. package/dist/commands/prd/fix.d.ts +39 -0
  26. package/dist/commands/prd/fix.js +140 -0
  27. package/dist/commands/prd/validate.d.ts +112 -0
  28. package/dist/commands/prd/validate.js +302 -0
  29. package/dist/commands/stories/create.d.ts +95 -0
  30. package/dist/commands/stories/create.js +431 -0
  31. package/dist/commands/stories/develop.d.ts +91 -0
  32. package/dist/commands/stories/develop.js +460 -0
  33. package/dist/commands/stories/list.d.ts +84 -0
  34. package/dist/commands/stories/list.js +291 -0
  35. package/dist/commands/stories/move.d.ts +66 -0
  36. package/dist/commands/stories/move.js +273 -0
  37. package/dist/commands/stories/qa.d.ts +99 -0
  38. package/dist/commands/stories/qa.js +530 -0
  39. package/dist/commands/workflow.d.ts +97 -0
  40. package/dist/commands/workflow.js +390 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.js +1 -0
  43. package/dist/models/agent-options.d.ts +50 -0
  44. package/dist/models/agent-options.js +1 -0
  45. package/dist/models/agent-result.d.ts +29 -0
  46. package/dist/models/agent-result.js +1 -0
  47. package/dist/models/index.d.ts +10 -0
  48. package/dist/models/index.js +10 -0
  49. package/dist/models/phase-result.d.ts +65 -0
  50. package/dist/models/phase-result.js +7 -0
  51. package/dist/models/provider.d.ts +28 -0
  52. package/dist/models/provider.js +18 -0
  53. package/dist/models/story.d.ts +154 -0
  54. package/dist/models/story.js +18 -0
  55. package/dist/models/workflow-config.d.ts +148 -0
  56. package/dist/models/workflow-config.js +1 -0
  57. package/dist/models/workflow-result.d.ts +164 -0
  58. package/dist/models/workflow-result.js +7 -0
  59. package/dist/services/agents/agent-runner-factory.d.ts +31 -0
  60. package/dist/services/agents/agent-runner-factory.js +44 -0
  61. package/dist/services/agents/agent-runner.d.ts +46 -0
  62. package/dist/services/agents/agent-runner.js +29 -0
  63. package/dist/services/agents/claude-agent-runner.d.ts +81 -0
  64. package/dist/services/agents/claude-agent-runner.js +332 -0
  65. package/dist/services/agents/gemini-agent-runner.d.ts +82 -0
  66. package/dist/services/agents/gemini-agent-runner.js +350 -0
  67. package/dist/services/agents/index.d.ts +7 -0
  68. package/dist/services/agents/index.js +7 -0
  69. package/dist/services/file-system/file-manager.d.ts +110 -0
  70. package/dist/services/file-system/file-manager.js +223 -0
  71. package/dist/services/file-system/glob-matcher.d.ts +75 -0
  72. package/dist/services/file-system/glob-matcher.js +126 -0
  73. package/dist/services/file-system/path-resolver.d.ts +183 -0
  74. package/dist/services/file-system/path-resolver.js +400 -0
  75. package/dist/services/logging/workflow-logger.d.ts +232 -0
  76. package/dist/services/logging/workflow-logger.js +552 -0
  77. package/dist/services/orchestration/batch-processor.d.ts +113 -0
  78. package/dist/services/orchestration/batch-processor.js +187 -0
  79. package/dist/services/orchestration/dependency-graph-executor.d.ts +60 -0
  80. package/dist/services/orchestration/dependency-graph-executor.js +447 -0
  81. package/dist/services/orchestration/index.d.ts +10 -0
  82. package/dist/services/orchestration/index.js +8 -0
  83. package/dist/services/orchestration/input-detector.d.ts +125 -0
  84. package/dist/services/orchestration/input-detector.js +381 -0
  85. package/dist/services/orchestration/story-queue.d.ts +94 -0
  86. package/dist/services/orchestration/story-queue.js +170 -0
  87. package/dist/services/orchestration/story-type-detector.d.ts +80 -0
  88. package/dist/services/orchestration/story-type-detector.js +258 -0
  89. package/dist/services/orchestration/task-decomposition-service.d.ts +67 -0
  90. package/dist/services/orchestration/task-decomposition-service.js +607 -0
  91. package/dist/services/orchestration/workflow-orchestrator.d.ts +659 -0
  92. package/dist/services/orchestration/workflow-orchestrator.js +2201 -0
  93. package/dist/services/parsers/epic-parser.d.ts +117 -0
  94. package/dist/services/parsers/epic-parser.js +264 -0
  95. package/dist/services/parsers/prd-fixer.d.ts +86 -0
  96. package/dist/services/parsers/prd-fixer.js +194 -0
  97. package/dist/services/parsers/prd-parser.d.ts +123 -0
  98. package/dist/services/parsers/prd-parser.js +286 -0
  99. package/dist/services/parsers/standalone-story-parser.d.ts +114 -0
  100. package/dist/services/parsers/standalone-story-parser.js +255 -0
  101. package/dist/services/parsers/story-parser-factory.d.ts +81 -0
  102. package/dist/services/parsers/story-parser-factory.js +108 -0
  103. package/dist/services/parsers/story-parser.d.ts +122 -0
  104. package/dist/services/parsers/story-parser.js +262 -0
  105. package/dist/services/scaffolding/decompose-session-scaffolder.d.ts +74 -0
  106. package/dist/services/scaffolding/decompose-session-scaffolder.js +315 -0
  107. package/dist/services/scaffolding/file-scaffolder.d.ts +94 -0
  108. package/dist/services/scaffolding/file-scaffolder.js +314 -0
  109. package/dist/services/validation/config-validator.d.ts +88 -0
  110. package/dist/services/validation/config-validator.js +167 -0
  111. package/dist/types/task-graph.d.ts +142 -0
  112. package/dist/types/task-graph.js +5 -0
  113. package/dist/utils/colors.d.ts +49 -0
  114. package/dist/utils/colors.js +50 -0
  115. package/dist/utils/error-formatter.d.ts +64 -0
  116. package/dist/utils/error-formatter.js +279 -0
  117. package/dist/utils/errors.d.ts +170 -0
  118. package/dist/utils/errors.js +233 -0
  119. package/dist/utils/formatters.d.ts +84 -0
  120. package/dist/utils/formatters.js +162 -0
  121. package/dist/utils/logger.d.ts +63 -0
  122. package/dist/utils/logger.js +78 -0
  123. package/dist/utils/progress.d.ts +104 -0
  124. package/dist/utils/progress.js +161 -0
  125. package/dist/utils/retry.d.ts +114 -0
  126. package/dist/utils/retry.js +160 -0
  127. package/dist/utils/shared-flags.d.ts +28 -0
  128. package/dist/utils/shared-flags.js +43 -0
  129. package/package.json +119 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * PRD Parser Service
3
+ *
4
+ * Extracts epic information from Product Requirements Document (PRD) markdown files.
5
+ * Supports multiple epic header formats for resilient parsing.
6
+ *
7
+ * Supported Formats (in order of precedence):
8
+ * - ## Epic 1 Title (space-separated, PRIMARY format from prd-tmpl.yaml)
9
+ * - ## Epic 1: Title (colon-separated)
10
+ * - ## Epic 1 - Title (dash-separated)
11
+ * - ## 1: Title (number only with colon)
12
+ * - ## 1. Title (number with period)
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const logger = createLogger({ namespace: 'parser' })
17
+ * const parser = new PrdParser(logger)
18
+ * const epics = parser.parseEpics(prdContent, 'prd.md')
19
+ * ```
20
+ */
21
+ import type pino from 'pino';
22
+ /**
23
+ * Represents an epic extracted from a PRD document
24
+ */
25
+ export interface Epic {
26
+ /**
27
+ * Full number as it appears in source (e.g., "Epic 1", "1")
28
+ */
29
+ fullNumber: string;
30
+ /**
31
+ * Epic number (1, 2, 3, etc.)
32
+ */
33
+ number: number;
34
+ /**
35
+ * Position in source document (line number, 0-indexed)
36
+ */
37
+ position: number;
38
+ /**
39
+ * Epic title extracted from header
40
+ */
41
+ title: string;
42
+ }
43
+ /**
44
+ * PRD Parser Service
45
+ *
46
+ * Parses Product Requirements Documents to extract epic information
47
+ * using multiple resilient patterns for different markdown formats.
48
+ */
49
+ export declare class PrdParser {
50
+ private readonly logger;
51
+ /**
52
+ * Epic header patterns in order of specificity (most specific first)
53
+ *
54
+ * CRITICAL: Pattern order matches prd-tmpl.yaml output format
55
+ * Template generates: ## Epic 1 Title (space-separated)
56
+ */
57
+ private readonly patterns;
58
+ /**
59
+ * Create a new PrdParser instance
60
+ *
61
+ * @param logger - Logger instance for structured logging
62
+ */
63
+ constructor(logger: pino.Logger);
64
+ /**
65
+ * Parse epics from PRD content
66
+ *
67
+ * Extracts epic information using multiple pattern matching strategies.
68
+ * Returns epics sorted by their position in the document (natural order).
69
+ *
70
+ * Patterns are tried in order of specificity. If a more specific pattern
71
+ * (containing "Epic" keyword) finds matches, generic number-only patterns
72
+ * are skipped to avoid false positives from section headers.
73
+ *
74
+ * @param prdContent - Full PRD markdown content
75
+ * @param prdPath - Path to PRD file (for error messages)
76
+ * @returns Array of Epic objects sorted by document position
77
+ * @throws {ParserError} When no epics are found in the PRD
78
+ * @example
79
+ * ```typescript
80
+ * const epics = parser.parseEpics(prdContent, 'docs/prd.md')
81
+ * console.log(`Found ${epics.length} epics`)
82
+ * ```
83
+ */
84
+ parseEpics(prdContent: string, prdPath: string): Epic[];
85
+ /**
86
+ * Deduplicate matches that appear at the same position
87
+ *
88
+ * When multiple patterns match the same line, keep only the first match.
89
+ *
90
+ * @param matches - Array of pattern matches
91
+ * @returns Deduplicated array of Epic objects
92
+ */
93
+ private deduplicateMatches;
94
+ /**
95
+ * Find the line number where a match appears
96
+ *
97
+ * @param lines - Array of lines from the document
98
+ * @param matchText - Text to find
99
+ * @returns Line number (0-indexed)
100
+ */
101
+ private findLineNumber;
102
+ /**
103
+ * Match a single pattern against PRD content
104
+ *
105
+ * @param pattern - Pattern configuration with name and regex
106
+ * @param pattern.name - Pattern name
107
+ * @param pattern.regex - Pattern regular expression
108
+ * @param lines - PRD content split into lines
109
+ * @param content - Full PRD content
110
+ * @returns Array of matches for this pattern
111
+ */
112
+ private matchPattern;
113
+ /**
114
+ * Validate epic numbers for duplicates and sequential order
115
+ *
116
+ * Logs warnings for issues but does not throw errors to allow
117
+ * parsing of imperfect PRDs.
118
+ *
119
+ * @param matches - Array of pattern matches
120
+ * @param prdPath - Path to PRD file (for logging)
121
+ */
122
+ private validateEpicNumbers;
123
+ }
@@ -0,0 +1,286 @@
1
+ /**
2
+ * PRD Parser Service
3
+ *
4
+ * Extracts epic information from Product Requirements Document (PRD) markdown files.
5
+ * Supports multiple epic header formats for resilient parsing.
6
+ *
7
+ * Supported Formats (in order of precedence):
8
+ * - ## Epic 1 Title (space-separated, PRIMARY format from prd-tmpl.yaml)
9
+ * - ## Epic 1: Title (colon-separated)
10
+ * - ## Epic 1 - Title (dash-separated)
11
+ * - ## 1: Title (number only with colon)
12
+ * - ## 1. Title (number with period)
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const logger = createLogger({ namespace: 'parser' })
17
+ * const parser = new PrdParser(logger)
18
+ * const epics = parser.parseEpics(prdContent, 'prd.md')
19
+ * ```
20
+ */
21
+ import { ParserError } from '../../utils/errors.js';
22
+ /**
23
+ * PRD Parser Service
24
+ *
25
+ * Parses Product Requirements Documents to extract epic information
26
+ * using multiple resilient patterns for different markdown formats.
27
+ */
28
+ export class PrdParser {
29
+ logger;
30
+ /**
31
+ * Epic header patterns in order of specificity (most specific first)
32
+ *
33
+ * CRITICAL: Pattern order matches prd-tmpl.yaml output format
34
+ * Template generates: ## Epic 1 Title (space-separated)
35
+ */
36
+ patterns = [
37
+ {
38
+ name: 'Epic N Nested (N. Epic M:)',
39
+ regex: /^##\s+\d+\.\s+Epic\s+(\d+)\s*:\s*(.+?)$/gim,
40
+ },
41
+ {
42
+ name: 'Epic N: Title',
43
+ regex: /^##\s+Epic\s+(\d+)\s*:\s*(.+?)$/gim,
44
+ },
45
+ {
46
+ name: 'Epic N - Title',
47
+ regex: /^##\s+Epic\s+(\d+)\s+-\s+(.+?)$/gim,
48
+ },
49
+ {
50
+ name: 'Epic N Title (space)',
51
+ regex: /^##\s+Epic\s+(\d+)\s+(?![:-])(.+?)$/gim,
52
+ },
53
+ {
54
+ name: 'N: Title',
55
+ regex: /^##\s+(\d+)\s*:\s*(.+?)$/gim,
56
+ },
57
+ {
58
+ name: 'N. Title',
59
+ regex: /^##\s+(\d+)\s*\.\s+(.+?)$/gim,
60
+ },
61
+ ];
62
+ /**
63
+ * Create a new PrdParser instance
64
+ *
65
+ * @param logger - Logger instance for structured logging
66
+ */
67
+ constructor(logger) {
68
+ this.logger = logger;
69
+ }
70
+ /**
71
+ * Parse epics from PRD content
72
+ *
73
+ * Extracts epic information using multiple pattern matching strategies.
74
+ * Returns epics sorted by their position in the document (natural order).
75
+ *
76
+ * Patterns are tried in order of specificity. If a more specific pattern
77
+ * (containing "Epic" keyword) finds matches, generic number-only patterns
78
+ * are skipped to avoid false positives from section headers.
79
+ *
80
+ * @param prdContent - Full PRD markdown content
81
+ * @param prdPath - Path to PRD file (for error messages)
82
+ * @returns Array of Epic objects sorted by document position
83
+ * @throws {ParserError} When no epics are found in the PRD
84
+ * @example
85
+ * ```typescript
86
+ * const epics = parser.parseEpics(prdContent, 'docs/prd.md')
87
+ * console.log(`Found ${epics.length} epics`)
88
+ * ```
89
+ */
90
+ parseEpics(prdContent, prdPath) {
91
+ this.logger.info({ prdPath }, 'Parsing epics from PRD');
92
+ // Split content into lines for position tracking
93
+ const lines = prdContent.split('\n');
94
+ // First pass: check if nested format exists (e.g., "## 7. Epic 1:")
95
+ // If found, "N." format is being used for sections, not epics
96
+ let hasNestedEpicFormat = false;
97
+ for (const pattern of this.patterns) {
98
+ if (pattern.name.includes('Nested')) {
99
+ const matches = this.matchPattern(pattern, lines, prdContent);
100
+ if (matches.length > 0) {
101
+ hasNestedEpicFormat = true;
102
+ break;
103
+ }
104
+ }
105
+ }
106
+ // Collect matches from all patterns - patterns are ordered by specificity
107
+ // More specific "Epic N" patterns come first in the array
108
+ const allMatches = [];
109
+ for (const pattern of this.patterns) {
110
+ // Skip "N. Title" pattern if nested format found (N. is used for sections)
111
+ if (hasNestedEpicFormat && pattern.name === 'N. Title') {
112
+ this.logger.debug({ patternName: pattern.name }, 'Skipping N. pattern - nested Epic format found in PRD');
113
+ continue;
114
+ }
115
+ const matches = this.matchPattern(pattern, lines, prdContent);
116
+ if (matches.length > 0) {
117
+ allMatches.push(...matches);
118
+ this.logger.debug({ matches: matches.length, patternName: pattern.name }, 'Pattern matched epics');
119
+ }
120
+ }
121
+ // Check if any epics were found
122
+ if (allMatches.length === 0) {
123
+ this.logger.error({ prdPath }, 'No epics found in PRD');
124
+ throw new ParserError('No epics found in PRD. Expected format: `## Epic N: Title` or similar', {
125
+ filePath: prdPath,
126
+ suggestion: 'Ensure PRD has epic headers like: ## Epic 1: Foundation',
127
+ });
128
+ }
129
+ // Sort by position (natural document order)
130
+ allMatches.sort((a, b) => a.position - b.position);
131
+ // Check for duplicates and non-sequential numbers
132
+ this.validateEpicNumbers(allMatches, prdPath);
133
+ // Convert to Epic interface and deduplicate by position
134
+ const epics = this.deduplicateMatches(allMatches);
135
+ this.logger.info({ epicCount: epics.length, prdPath }, 'Successfully parsed epics from PRD');
136
+ return epics;
137
+ }
138
+ /**
139
+ * Deduplicate matches that appear at the same position
140
+ *
141
+ * When multiple patterns match the same line, keep only the first match.
142
+ *
143
+ * @param matches - Array of pattern matches
144
+ * @returns Deduplicated array of Epic objects
145
+ */
146
+ deduplicateMatches(matches) {
147
+ const seenPositions = new Set();
148
+ const epics = [];
149
+ for (const match of matches) {
150
+ // Skip if we've already seen this position
151
+ if (seenPositions.has(match.position)) {
152
+ this.logger.debug({
153
+ epicNumber: match.number,
154
+ line: match.position + 1,
155
+ patternName: match.patternName,
156
+ }, 'Skipping duplicate match at same position');
157
+ continue;
158
+ }
159
+ seenPositions.add(match.position);
160
+ epics.push({
161
+ fullNumber: match.fullNumber,
162
+ number: match.number,
163
+ position: match.position,
164
+ title: match.title,
165
+ });
166
+ this.logger.debug({
167
+ epicNumber: match.number,
168
+ line: match.position + 1,
169
+ patternName: match.patternName,
170
+ title: match.title,
171
+ }, 'Epic matched successfully');
172
+ }
173
+ return epics;
174
+ }
175
+ /**
176
+ * Find the line number where a match appears
177
+ *
178
+ * @param lines - Array of lines from the document
179
+ * @param matchText - Text to find
180
+ * @returns Line number (0-indexed)
181
+ */
182
+ findLineNumber(lines, matchText) {
183
+ for (const [i, line] of lines.entries()) {
184
+ if (line.includes(matchText.trim())) {
185
+ return i;
186
+ }
187
+ }
188
+ return 0; // Fallback to start of document
189
+ }
190
+ /**
191
+ * Match a single pattern against PRD content
192
+ *
193
+ * @param pattern - Pattern configuration with name and regex
194
+ * @param pattern.name - Pattern name
195
+ * @param pattern.regex - Pattern regular expression
196
+ * @param lines - PRD content split into lines
197
+ * @param content - Full PRD content
198
+ * @returns Array of matches for this pattern
199
+ */
200
+ matchPattern(pattern, lines, content) {
201
+ const matches = [];
202
+ const regex = new RegExp(pattern.regex.source, pattern.regex.flags);
203
+ let match;
204
+ // Reset regex state
205
+ regex.lastIndex = 0;
206
+ // Execute regex and collect all matches
207
+ while ((match = regex.exec(content)) !== null) {
208
+ const epicNumber = Number.parseInt(match[1], 10);
209
+ const epicTitle = match[2].trim();
210
+ const fullMatch = match[0];
211
+ // Find line number of this match
212
+ const position = this.findLineNumber(lines, fullMatch);
213
+ // Extract fullNumber based on pattern type
214
+ let fullNumber;
215
+ if (pattern.name.includes('Nested')) {
216
+ // For nested format "## N. Epic M:", use "Epic M"
217
+ fullNumber = `Epic ${epicNumber}`;
218
+ }
219
+ else if (pattern.name.startsWith('Epic N')) {
220
+ // For Epic patterns, use "Epic N"
221
+ fullNumber = `Epic ${epicNumber}`;
222
+ }
223
+ else {
224
+ // For generic patterns, extract from match
225
+ fullNumber = fullMatch
226
+ .replace(/^##\s*/, '')
227
+ .split(/[:-]/)[0]
228
+ .trim();
229
+ }
230
+ matches.push({
231
+ fullNumber,
232
+ number: epicNumber,
233
+ patternName: pattern.name,
234
+ position,
235
+ title: epicTitle,
236
+ });
237
+ }
238
+ return matches;
239
+ }
240
+ /**
241
+ * Validate epic numbers for duplicates and sequential order
242
+ *
243
+ * Logs warnings for issues but does not throw errors to allow
244
+ * parsing of imperfect PRDs.
245
+ *
246
+ * @param matches - Array of pattern matches
247
+ * @param prdPath - Path to PRD file (for logging)
248
+ */
249
+ validateEpicNumbers(matches, prdPath) {
250
+ // Check for duplicate numbers
251
+ const numberCounts = new Map();
252
+ const numberPositions = new Map();
253
+ for (const match of matches) {
254
+ const count = numberCounts.get(match.number) || 0;
255
+ numberCounts.set(match.number, count + 1);
256
+ const positions = numberPositions.get(match.number) || [];
257
+ positions.push(match.position);
258
+ numberPositions.set(match.number, positions);
259
+ }
260
+ // Log warnings for duplicates
261
+ for (const [number, count] of numberCounts.entries()) {
262
+ if (count > 1) {
263
+ const positions = numberPositions.get(number) || [];
264
+ this.logger.warn({
265
+ epicNumber: number,
266
+ lines: positions.map((p) => p + 1), // Convert to 1-indexed for user display
267
+ occurrences: count,
268
+ prdPath,
269
+ }, 'Duplicate epic number found');
270
+ }
271
+ }
272
+ // Check for non-sequential numbers
273
+ const uniqueNumbers = [...new Set(matches.map((m) => m.number))].sort((a, b) => a - b);
274
+ for (let i = 1; i < uniqueNumbers.length; i++) {
275
+ const current = uniqueNumbers[i];
276
+ const previous = uniqueNumbers[i - 1];
277
+ if (current !== previous + 1) {
278
+ this.logger.warn({
279
+ expected: previous + 1,
280
+ found: current,
281
+ prdPath,
282
+ }, 'Epic numbers are not sequential');
283
+ }
284
+ }
285
+ }
286
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * StandaloneStoryParser Service
3
+ *
4
+ * Parses standalone story files that don't follow the epic.story numbering pattern.
5
+ * Supports stories like JIRA tickets, bug fixes, and ad-hoc tasks.
6
+ *
7
+ * Examples:
8
+ * - JIRA-SIGN-10.md
9
+ * - bugfix-auth-timeout.md
10
+ * - feature-dark-mode.md
11
+ */
12
+ import type pino from 'pino';
13
+ import type { StandaloneStoryMetadata, StoryStatus } from '../../models/story.js';
14
+ import type { FileManager } from '../file-system/file-manager.js';
15
+ /**
16
+ * StandaloneStoryParser service for parsing non-epic stories
17
+ *
18
+ * Provides methods to parse standalone story files that don't follow
19
+ * the epic.story numbering convention. Uses filename as unique ID and
20
+ * optionally extracts category/prefix.
21
+ */
22
+ export declare class StandaloneStoryParser {
23
+ /**
24
+ * FileManager instance for file operations
25
+ */
26
+ private readonly fileManager;
27
+ /**
28
+ * Logger instance for parsing operations
29
+ */
30
+ private readonly logger;
31
+ /**
32
+ * Create a new StandaloneStoryParser instance
33
+ *
34
+ * @param fileManager - FileManager service for file operations
35
+ * @param logger - Pino logger instance for logging parsing operations
36
+ * @example
37
+ * const logger = createLogger({ namespace: 'services:parsers:standalone-story' })
38
+ * const fileManager = new FileManager(logger)
39
+ * const parser = new StandaloneStoryParser(fileManager, logger)
40
+ */
41
+ constructor(fileManager: FileManager, logger: pino.Logger);
42
+ /**
43
+ * Parse standalone story metadata from a story file
44
+ *
45
+ * Extracts ID from filename, optional category/prefix, title from H1 header,
46
+ * and status from either inline or section-based format. Does not require
47
+ * epic.story numbering pattern.
48
+ *
49
+ * @param storyPath - Path to the story markdown file
50
+ * @returns Standalone story metadata with ID, title, status, and optional category
51
+ * @throws If file cannot be read
52
+ * @throws {ParserError} If story structure is invalid (missing title, missing status)
53
+ * @example
54
+ * const metadata = await parser.parseStoryMetadata('docs/stories/JIRA-SIGN-10.md')
55
+ * console.log(metadata.id) // "JIRA-SIGN-10"
56
+ * console.log(metadata.category) // "JIRA-SIGN"
57
+ * console.log(metadata.type) // "standalone"
58
+ */
59
+ parseStoryMetadata(storyPath: string): Promise<StandaloneStoryMetadata>;
60
+ /**
61
+ * Update story status in a standalone story file
62
+ *
63
+ * Reads the story file, detects the current status format (inline or section-based),
64
+ * and updates the status value while preserving the original format.
65
+ *
66
+ * @param storyPath - Path to the story markdown file
67
+ * @param newStatus - New status value to set
68
+ * @throws If file cannot be read or written
69
+ * @throws {ParserError} If status format cannot be detected
70
+ * @example
71
+ * await parser.updateStoryStatus('docs/stories/JIRA-SIGN-10.md', 'Done')
72
+ */
73
+ updateStoryStatus(storyPath: string, newStatus: StoryStatus): Promise<void>;
74
+ /**
75
+ * Detect status format (inline vs section-based) and extract current status
76
+ *
77
+ * @param content - Story file content
78
+ * @param storyPath - Path to story file (for error context)
79
+ * @returns Object with format type and old status value
80
+ * @throws {ParserError} If status format cannot be detected
81
+ */
82
+ private detectStatusFormat;
83
+ /**
84
+ * Extract unique ID and optional category from filename
85
+ *
86
+ * Parses filename to create a unique ID (filename without extension)
87
+ * and optionally extracts category prefix. Supports patterns like:
88
+ * - JIRA-SIGN-10.md → id: "JIRA-SIGN-10", category: "JIRA-SIGN"
89
+ * - bugfix-auth.md → id: "bugfix-auth", category: "bugfix"
90
+ * - simple-task.md → id: "simple-task", category: undefined
91
+ *
92
+ * @param storyPath - Path to the story file
93
+ * @returns Object with id and optional category
94
+ */
95
+ private extractIdAndCategory;
96
+ /**
97
+ * Extract story status using multiple pattern strategies
98
+ *
99
+ * @param content - Story file content
100
+ * @param storyPath - Path to story file (for error context)
101
+ * @returns Extracted status value
102
+ * @throws {ParserError} If status cannot be found
103
+ */
104
+ private extractStatus;
105
+ /**
106
+ * Extract story title from H1 header
107
+ *
108
+ * @param content - Story file content
109
+ * @param storyPath - Path to story file (for error context)
110
+ * @returns Extracted title
111
+ * @throws {ParserError} If H1 header is not found
112
+ */
113
+ private extractTitle;
114
+ }