@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,400 @@
1
+ /**
2
+ * PathResolver Service
3
+ *
4
+ * Resolves and validates file paths from core-config.yaml configuration.
5
+ * All commands use this service to get correct directories for epics, stories, and PRD files.
6
+ */
7
+ import fs from 'fs-extra';
8
+ import { load as yamlLoad } from 'js-yaml';
9
+ import { dirname, resolve } from 'node:path';
10
+ import { ConfigurationError, FileSystemError } from '../../utils/errors.js';
11
+ /**
12
+ * Configuration file path relative to project root
13
+ */
14
+ const CONFIG_FILE_PATH = '.bmad-core/core-config.yaml';
15
+ /**
16
+ * PathResolver service for resolving and validating file paths
17
+ *
18
+ * Loads configuration from .bmad-core/core-config.yaml and provides methods
19
+ * to get correct directories for epics, stories, QA, and PRD files. All paths
20
+ * are resolved relative to the project root and validated for existence.
21
+ */
22
+ export class PathResolver {
23
+ /**
24
+ * Cached configuration to avoid repeated file reads
25
+ */
26
+ cachedConfig = null;
27
+ /**
28
+ * Cached resolved paths
29
+ */
30
+ cachedPaths = null;
31
+ /**
32
+ * FileManager instance for file operations
33
+ */
34
+ fileManager;
35
+ /**
36
+ * Logger instance for path resolution operations
37
+ */
38
+ logger;
39
+ /**
40
+ * Project root directory (current working directory)
41
+ */
42
+ projectRoot;
43
+ /**
44
+ * Create a new PathResolver instance
45
+ *
46
+ * @param fileManager - FileManager instance for file operations
47
+ * @param logger - Pino logger instance for logging path operations
48
+ * @example
49
+ * const logger = createLogger({ namespace: 'services:path-resolver' })
50
+ * const fileManager = new FileManager(logger)
51
+ * const pathResolver = new PathResolver(fileManager, logger)
52
+ */
53
+ constructor(fileManager, logger) {
54
+ this.fileManager = fileManager;
55
+ this.logger = logger;
56
+ this.projectRoot = process.cwd();
57
+ this.logger.debug('PathResolver initialized with project root: %s', this.projectRoot);
58
+ }
59
+ /**
60
+ * Get all story directories for existence checks
61
+ *
62
+ * Returns an array of all story directories to check when determining
63
+ * if a story already exists. This includes:
64
+ * - docs/stories (dev stories)
65
+ * - docs/qa/stories (QA stories)
66
+ * - docs/done/stories (completed stories)
67
+ *
68
+ * @returns Array of absolute paths to story directories
69
+ * @example
70
+ * const allDirs = pathResolver.getAllStoryDirs()
71
+ * // Returns: ['/path/to/project/docs/stories', '/path/to/project/docs/qa/stories', '/path/to/project/docs/done/stories']
72
+ */
73
+ getAllStoryDirs() {
74
+ const paths = this.getResolvedPaths();
75
+ const dirs = [paths.storyDir, paths.qaStoryDir, paths.doneStoryDir];
76
+ this.logger.debug('Getting all story directories: %O', dirs);
77
+ return dirs;
78
+ }
79
+ /**
80
+ * Get the configuration file path
81
+ *
82
+ * Returns the absolute path to .bmad-core/core-config.yaml
83
+ *
84
+ * @returns Absolute path to configuration file
85
+ * @example
86
+ * const configPath = pathResolver.getConfigPath()
87
+ * // Returns: '/path/to/project/.bmad-core/core-config.yaml'
88
+ */
89
+ getConfigPath() {
90
+ const configPath = resolve(this.projectRoot, CONFIG_FILE_PATH);
91
+ this.logger.debug('Getting config path: %s', configPath);
92
+ return configPath;
93
+ }
94
+ /**
95
+ * Get the Done story directory path
96
+ *
97
+ * Returns the docs/done/stories directory for completed stories.
98
+ *
99
+ * @returns Absolute path to Done story directory
100
+ * @example
101
+ * const doneStoryDir = pathResolver.getDoneStoryDir()
102
+ * // Returns: '/path/to/project/docs/done/stories'
103
+ */
104
+ getDoneStoryDir() {
105
+ const paths = this.getResolvedPaths();
106
+ this.logger.debug('Getting Done story directory: %s', paths.doneStoryDir);
107
+ return paths.doneStoryDir;
108
+ }
109
+ /**
110
+ * Get the epic directory path
111
+ *
112
+ * Derives epic directory from story location or explicit configuration.
113
+ * By convention, epics are in docs/epics if stories are in docs/stories.
114
+ *
115
+ * @returns Absolute path to epic directory
116
+ * @throws {FileSystemError} If epic directory does not exist
117
+ * @example
118
+ * const epicDir = pathResolver.getEpicDir()
119
+ * // Returns: '/path/to/project/docs/epics'
120
+ */
121
+ getEpicDir() {
122
+ const paths = this.getResolvedPaths();
123
+ this.logger.debug('Getting epic directory: %s', paths.epicDir);
124
+ return paths.epicDir;
125
+ }
126
+ /**
127
+ * Get the PRD file path
128
+ *
129
+ * Returns the configured PRD file path from core-config.yaml.
130
+ *
131
+ * @returns Absolute path to PRD file
132
+ * @example
133
+ * const prdFile = pathResolver.getPrdFile()
134
+ * // Returns: '/path/to/project/docs/prd.md'
135
+ */
136
+ getPrdFile() {
137
+ const paths = this.getResolvedPaths();
138
+ this.logger.debug('Getting PRD file: %s', paths.prdFile);
139
+ return paths.prdFile;
140
+ }
141
+ /**
142
+ * Get the QA story directory path
143
+ *
144
+ * Returns the configured QA location plus /stories subdirectory.
145
+ *
146
+ * @returns Absolute path to QA story directory
147
+ * @throws {FileSystemError} If QA story directory does not exist
148
+ * @example
149
+ * const qaStoryDir = pathResolver.getQaStoryDir()
150
+ * // Returns: '/path/to/project/docs/qa/stories'
151
+ */
152
+ getQaStoryDir() {
153
+ const paths = this.getResolvedPaths();
154
+ this.logger.debug('Getting QA story directory: %s', paths.qaStoryDir);
155
+ return paths.qaStoryDir;
156
+ }
157
+ /**
158
+ * Get the story directory path
159
+ *
160
+ * Returns the configured story location from core-config.yaml.
161
+ *
162
+ * @returns Absolute path to story directory
163
+ * @throws {FileSystemError} If story directory does not exist
164
+ * @example
165
+ * const storyDir = pathResolver.getStoryDir()
166
+ * // Returns: '/path/to/project/docs/stories'
167
+ */
168
+ getStoryDir() {
169
+ const paths = this.getResolvedPaths();
170
+ this.logger.debug('Getting story directory: %s', paths.storyDir);
171
+ return paths.storyDir;
172
+ }
173
+ /**
174
+ * Find configuration file by searching up the directory tree
175
+ *
176
+ * Searches for .bmad-core/core-config.yaml starting from project root
177
+ * and walking up to 5 parent directories.
178
+ *
179
+ * @returns Path to found config file, or null if not found
180
+ */
181
+ findConfigFile() {
182
+ const MAX_LEVELS = 5;
183
+ let currentDir = this.projectRoot;
184
+ for (let i = 0; i <= MAX_LEVELS; i++) {
185
+ const configPath = resolve(currentDir, CONFIG_FILE_PATH);
186
+ this.logger.debug('Searching for config at level %d: %s', i, configPath);
187
+ if (fs.existsSync(configPath)) {
188
+ this.logger.info('Found configuration file at: %s', configPath);
189
+ return configPath;
190
+ }
191
+ const parentDir = dirname(currentDir);
192
+ // Stop if we've reached the filesystem root
193
+ if (parentDir === currentDir) {
194
+ break;
195
+ }
196
+ currentDir = parentDir;
197
+ }
198
+ return null;
199
+ }
200
+ /**
201
+ * Get resolved paths (with caching)
202
+ *
203
+ * Loads configuration and resolves all paths on first access,
204
+ * then returns cached paths on subsequent calls.
205
+ *
206
+ * @returns Resolved paths structure
207
+ */
208
+ getResolvedPaths() {
209
+ if (this.cachedPaths) {
210
+ return this.cachedPaths;
211
+ }
212
+ const config = this.loadConfig();
213
+ // Resolve story directory
214
+ const storyDir = resolve(this.projectRoot, config.devStoryLocation);
215
+ // Derive epic directory from story directory
216
+ // Convention: if stories are in docs/stories, epics are in docs/epics
217
+ const epicDir = resolve(this.projectRoot, config.devStoryLocation.replace('stories', 'epics'));
218
+ // Resolve QA story directory
219
+ const qaLocation = config.qa?.qaLocation || 'docs/qa';
220
+ const qaStoryDir = resolve(this.projectRoot, qaLocation, 'stories');
221
+ // Resolve Done story directory
222
+ const doneStoryDir = resolve(this.projectRoot, 'docs/done/stories');
223
+ // Resolve PRD file
224
+ const prdFile = resolve(this.projectRoot, config.prd?.prdFile || 'docs/prd.md');
225
+ // Validate directories exist
226
+ this.validateDirectorySync(storyDir, 'story directory');
227
+ this.validateDirectorySync(epicDir, 'epic directory');
228
+ this.validateDirectorySync(qaStoryDir, 'QA story directory');
229
+ // Note: doneStoryDir is optional, don't validate it
230
+ // Stories may not have been moved to done yet
231
+ this.cachedPaths = {
232
+ doneStoryDir,
233
+ epicDir,
234
+ prdFile,
235
+ qaStoryDir,
236
+ storyDir,
237
+ };
238
+ this.logger.info({
239
+ doneStoryDir,
240
+ epicDir,
241
+ prdFile,
242
+ qaStoryDir,
243
+ storyDir,
244
+ }, 'Paths resolved successfully');
245
+ return this.cachedPaths;
246
+ }
247
+ /**
248
+ * Load configuration from .bmad-core/core-config.yaml
249
+ *
250
+ * Reads and parses YAML configuration file, validates structure,
251
+ * and caches the result for subsequent calls. Searches up to 5 parent
252
+ * directories to find the config file.
253
+ *
254
+ * @returns Parsed and validated configuration
255
+ * @throws {FileSystemError} If configuration file is missing
256
+ * @throws {ConfigurationError} If configuration structure is invalid
257
+ */
258
+ loadConfig() {
259
+ if (this.cachedConfig) {
260
+ this.logger.debug('Using cached configuration');
261
+ return this.cachedConfig;
262
+ }
263
+ const configPath = this.findConfigFile();
264
+ if (!configPath) {
265
+ const searchStart = resolve(this.projectRoot, CONFIG_FILE_PATH);
266
+ this.logger.error('Configuration file not found after searching up to 5 parent directories');
267
+ throw new FileSystemError(`Configuration file not found: ${searchStart} (searched up to 5 parent directories)`, {
268
+ configPath: searchStart,
269
+ operation: 'loadConfig',
270
+ });
271
+ }
272
+ this.logger.info('Loading configuration from: %s', configPath);
273
+ try {
274
+ // Read configuration file
275
+ const content = fs.readFileSync(configPath, 'utf8');
276
+ this.logger.debug('Configuration file read successfully');
277
+ // Parse YAML
278
+ const config = yamlLoad(content);
279
+ // Validate required fields
280
+ this.validateConfig(config);
281
+ this.cachedConfig = config;
282
+ this.logger.info('Configuration loaded and validated successfully');
283
+ return config;
284
+ }
285
+ catch (error) {
286
+ if (error instanceof FileSystemError || error instanceof ConfigurationError) {
287
+ throw error;
288
+ }
289
+ const err = error;
290
+ this.logger.error('Error loading configuration: %O', err);
291
+ throw new ConfigurationError(`Failed to load configuration: ${err.message}`, {
292
+ configPath,
293
+ originalError: err.message,
294
+ });
295
+ }
296
+ }
297
+ /**
298
+ * Validate configuration structure
299
+ *
300
+ * Checks that all required fields are present and have correct types.
301
+ *
302
+ * @param config - Configuration object to validate
303
+ * @throws {ConfigurationError} If configuration is invalid
304
+ */
305
+ validateConfig(config) {
306
+ if (!config || typeof config !== 'object') {
307
+ throw new ConfigurationError('Configuration must be an object', {
308
+ actualType: typeof config,
309
+ });
310
+ }
311
+ const cfg = config;
312
+ // Validate required field: devStoryLocation
313
+ if (!cfg.devStoryLocation || typeof cfg.devStoryLocation !== 'string') {
314
+ throw new ConfigurationError('Missing or invalid required field: devStoryLocation', {
315
+ field: 'devStoryLocation',
316
+ value: cfg.devStoryLocation,
317
+ });
318
+ }
319
+ // Validate optional prd field
320
+ if (cfg.prd) {
321
+ if (typeof cfg.prd !== 'object') {
322
+ throw new ConfigurationError('Invalid prd field: must be an object', {
323
+ field: 'prd',
324
+ value: cfg.prd,
325
+ });
326
+ }
327
+ const prd = cfg.prd;
328
+ if (prd.prdFile && typeof prd.prdFile !== 'string') {
329
+ throw new ConfigurationError('Invalid prd.prdFile field: must be a string', {
330
+ field: 'prd.prdFile',
331
+ value: prd.prdFile,
332
+ });
333
+ }
334
+ }
335
+ // Validate optional qa field
336
+ if (cfg.qa) {
337
+ if (typeof cfg.qa !== 'object') {
338
+ throw new ConfigurationError('Invalid qa field: must be an object', {
339
+ field: 'qa',
340
+ value: cfg.qa,
341
+ });
342
+ }
343
+ const qa = cfg.qa;
344
+ if (qa.qaLocation && typeof qa.qaLocation !== 'string') {
345
+ throw new ConfigurationError('Invalid qa.qaLocation field: must be a string', {
346
+ field: 'qa.qaLocation',
347
+ value: qa.qaLocation,
348
+ });
349
+ }
350
+ }
351
+ this.logger.debug('Configuration validation passed');
352
+ }
353
+ /**
354
+ * Validate that a directory exists (synchronous)
355
+ *
356
+ * Checks directory existence and throws error if not found.
357
+ * Uses synchronous fs check for initialization validation.
358
+ *
359
+ * @param dirPath - Absolute path to directory
360
+ * @param name - Human-readable directory name for error messages
361
+ * @throws {FileSystemError} If directory does not exist
362
+ */
363
+ validateDirectorySync(dirPath, name) {
364
+ this.logger.debug('Validating directory: %s (%s)', dirPath, name);
365
+ try {
366
+ if (!fs.existsSync(dirPath)) {
367
+ this.logger.error('Directory does not exist: %s (%s)', dirPath, name);
368
+ throw new FileSystemError(`${name} does not exist: ${dirPath}`, {
369
+ dirPath,
370
+ name,
371
+ operation: 'validateDirectory',
372
+ });
373
+ }
374
+ // Check if it's actually a directory
375
+ const stats = fs.statSync(dirPath);
376
+ if (!stats.isDirectory()) {
377
+ this.logger.error('Path is not a directory: %s (%s)', dirPath, name);
378
+ throw new FileSystemError(`${name} is not a directory: ${dirPath}`, {
379
+ dirPath,
380
+ name,
381
+ operation: 'validateDirectory',
382
+ });
383
+ }
384
+ this.logger.debug('Directory validation passed: %s (%s)', dirPath, name);
385
+ }
386
+ catch (error) {
387
+ if (error instanceof FileSystemError) {
388
+ throw error;
389
+ }
390
+ const err = error;
391
+ this.logger.error('Error validating directory %s (%s): %O', dirPath, name, err);
392
+ throw new FileSystemError(`Failed to validate ${name}: ${err.message}`, {
393
+ dirPath,
394
+ name,
395
+ operation: 'validateDirectory',
396
+ originalError: err.message,
397
+ });
398
+ }
399
+ }
400
+ }
@@ -0,0 +1,232 @@
1
+ /**
2
+ * WorkflowLogger Service
3
+ *
4
+ * Comprehensive logging for workflow executions including:
5
+ * - Execution metadata and configuration
6
+ * - Prompts sent to Claude agents
7
+ * - Responses received from agents
8
+ * - Execution timeline and state
9
+ * - Success/failure tracking
10
+ */
11
+ import type { Logger } from 'pino';
12
+ import type { AgentOptions, AgentResult, WorkflowConfig, WorkflowResult } from '../../models/index.js';
13
+ export interface LogEntry {
14
+ action: string;
15
+ details: Record<string, unknown>;
16
+ level: 'debug' | 'error' | 'info' | 'warn';
17
+ phase: 'dev' | 'epic' | 'story' | 'workflow';
18
+ timestamp: string;
19
+ }
20
+ export interface PromptLogEntry {
21
+ agentType: string;
22
+ itemIdentifier: string;
23
+ phase: 'dev' | 'epic' | 'story';
24
+ prompt: string;
25
+ promptLength: number;
26
+ references: string[];
27
+ timeout: number;
28
+ timestamp: string;
29
+ }
30
+ export interface ResponseLogEntry {
31
+ agentType: string;
32
+ duration: number;
33
+ errors: string;
34
+ exitCode: number;
35
+ itemIdentifier: string;
36
+ output: string;
37
+ outputLength: number;
38
+ phase: 'dev' | 'epic' | 'story';
39
+ success: boolean;
40
+ timestamp: string;
41
+ }
42
+ export interface ExecutionPlan {
43
+ epicsExisting: number;
44
+ epicsToCreate: number;
45
+ estimatedDuration: string;
46
+ storiesExisting: number;
47
+ storiesToCreate: number;
48
+ storiesToDevelop: number;
49
+ }
50
+ export interface PipelineState {
51
+ activeWorkers: number;
52
+ storiesCompleted: number;
53
+ storiesCreating: number;
54
+ storiesDeveloping: number;
55
+ storiesQueued: number;
56
+ }
57
+ export interface WorkflowLogFile {
58
+ configuration: WorkflowConfig;
59
+ errors: Array<{
60
+ error: string;
61
+ identifier: string;
62
+ phase: string;
63
+ stack?: string;
64
+ timestamp: string;
65
+ }>;
66
+ executionPlan: ExecutionPlan;
67
+ metadata: {
68
+ duration?: number;
69
+ endTime?: string;
70
+ startTime: string;
71
+ status: 'completed' | 'failed' | 'running';
72
+ workflowId: string;
73
+ };
74
+ pipeline?: PipelineState;
75
+ prompts: PromptLogEntry[];
76
+ responses: ResponseLogEntry[];
77
+ summary: {
78
+ completed: {
79
+ developments: number;
80
+ epics: number;
81
+ stories: number;
82
+ };
83
+ failed: {
84
+ developments: number;
85
+ epics: number;
86
+ stories: number;
87
+ };
88
+ pending: {
89
+ developments: number;
90
+ epics: number;
91
+ stories: number;
92
+ };
93
+ };
94
+ timeline: LogEntry[];
95
+ }
96
+ export declare class WorkflowLogger {
97
+ private readonly logger;
98
+ private readonly logsDir;
99
+ private logFile;
100
+ private logFilePath;
101
+ private workflowId;
102
+ constructor(logger: Logger, logsDir?: string);
103
+ /**
104
+ * Generate pipeline summary table for concurrent phases
105
+ *
106
+ * Creates a formatted table showing the status of each phase in the pipeline,
107
+ * including pending, in progress, completed, and failed counts.
108
+ *
109
+ * @returns Formatted summary table string
110
+ */
111
+ generatePipelineSummaryTable(): string;
112
+ /**
113
+ * Get log file path
114
+ */
115
+ getLogFilePath(): string;
116
+ /**
117
+ * Get current pipeline state
118
+ */
119
+ getPipelineState(): PipelineState | undefined;
120
+ /**
121
+ * Get workflow ID
122
+ */
123
+ getWorkflowId(): string;
124
+ /**
125
+ * Initialize workflow log with configuration
126
+ */
127
+ initialize(config: WorkflowConfig): Promise<void>;
128
+ /**
129
+ * Initialize pipeline state tracking
130
+ */
131
+ initializePipelineState(): void;
132
+ /**
133
+ * Log phase completion
134
+ */
135
+ logPhaseComplete(phase: 'dev' | 'epic' | 'story', successCount: number, failureCount: number, duration: number): Promise<void>;
136
+ /**
137
+ * Log phase start
138
+ */
139
+ logPhaseStart(phase: 'dev' | 'epic' | 'story', details: Record<string, unknown>): Promise<void>;
140
+ /**
141
+ * Log a prompt being sent to Claude
142
+ */
143
+ logPrompt(phase: 'dev' | 'epic' | 'story', itemIdentifier: string, prompt: string, options: AgentOptions): Promise<void>;
144
+ /**
145
+ * Log a response received from Claude
146
+ */
147
+ logResponse(phase: 'dev' | 'epic' | 'story', itemIdentifier: string, result: AgentResult): Promise<void>;
148
+ /**
149
+ * Log story development completed in pipeline mode
150
+ */
151
+ logStoryCompleted(storyIdentifier: string, duration: number, success: boolean): Promise<void>;
152
+ /**
153
+ * Log story created in pipeline mode
154
+ */
155
+ logStoryCreated(storyIdentifier: string): Promise<void>;
156
+ /**
157
+ * Log story development started in pipeline mode
158
+ */
159
+ logStoryDeveloping(storyIdentifier: string, workerId: number): Promise<void>;
160
+ /**
161
+ * Log story queued for development in pipeline mode
162
+ */
163
+ logStoryQueued(storyIdentifier: string, queuePosition?: number): Promise<void>;
164
+ /**
165
+ * Log verbose story transition with timestamp
166
+ *
167
+ * Formats transition as: [HH:MM:SS] Story X.Y 'Title' → STATE
168
+ *
169
+ * @param storyNumber - Story number (e.g., "1.1")
170
+ * @param storyTitle - Story title
171
+ * @param state - New state (CREATING, QUEUED, DEVELOPING, COMPLETED, FAILED)
172
+ * @param details - Optional additional details
173
+ */
174
+ logVerboseTransition(storyNumber: string, storyTitle: string, state: 'COMPLETED' | 'CREATING' | 'DEVELOPING' | 'FAILED' | 'QUEUED', details?: Record<string, unknown>): Promise<void>;
175
+ /**
176
+ * Log workflow completion
177
+ */
178
+ logWorkflowComplete(result: WorkflowResult): Promise<void>;
179
+ /**
180
+ * Set execution plan
181
+ */
182
+ setExecutionPlan(plan: ExecutionPlan): Promise<void>;
183
+ /**
184
+ * Update active worker count in pipeline mode
185
+ */
186
+ updateActiveWorkers(count: number): Promise<void>;
187
+ /**
188
+ * Add a timeline entry
189
+ */
190
+ private addLogEntry;
191
+ /**
192
+ * Build markdown summary content
193
+ */
194
+ private buildMarkdownSummary;
195
+ /**
196
+ * Format duration in human-readable format
197
+ */
198
+ private formatDuration;
199
+ /**
200
+ * Format time as HH:MM:SS
201
+ *
202
+ * @param date - Date to format
203
+ * @returns Formatted time string
204
+ * @private
205
+ */
206
+ private formatTime;
207
+ /**
208
+ * Generate human-readable markdown summary
209
+ */
210
+ private generateMarkdownSummary;
211
+ /**
212
+ * Generate unique workflow ID
213
+ */
214
+ private generateWorkflowId;
215
+ /**
216
+ * Log an error
217
+ */
218
+ private logError;
219
+ /**
220
+ * Pad a number to a specific width with spaces
221
+ *
222
+ * @param num - Number to pad
223
+ * @param width - Target width
224
+ * @returns Padded string
225
+ * @private
226
+ */
227
+ private padNumber;
228
+ /**
229
+ * Write log file to disk
230
+ */
231
+ private writeLogFile;
232
+ }