@hyperdrive.bot/bmad-workflow 1.0.17 → 1.0.19

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 (110) hide show
  1. package/dist/commands/config/show.js +8 -2
  2. package/dist/commands/decompose.js +26 -5
  3. package/dist/commands/epics/create.d.ts +1 -0
  4. package/dist/commands/mcp/add.d.ts +16 -0
  5. package/dist/commands/mcp/add.js +77 -0
  6. package/dist/commands/mcp/credential/get.d.ts +14 -0
  7. package/dist/commands/mcp/credential/get.js +35 -0
  8. package/dist/commands/mcp/credential/list.d.ts +17 -0
  9. package/dist/commands/mcp/credential/list.js +67 -0
  10. package/dist/commands/mcp/credential/remove.d.ts +18 -0
  11. package/dist/commands/mcp/credential/remove.js +84 -0
  12. package/dist/commands/mcp/credential/set.d.ts +16 -0
  13. package/dist/commands/mcp/credential/set.js +41 -0
  14. package/dist/commands/mcp/credential/validate.d.ts +12 -0
  15. package/dist/commands/mcp/credential/validate.js +150 -0
  16. package/dist/commands/mcp/list.d.ts +17 -0
  17. package/dist/commands/mcp/list.js +80 -0
  18. package/dist/commands/mcp/logs.d.ts +15 -0
  19. package/dist/commands/mcp/logs.js +64 -0
  20. package/dist/commands/mcp/preset.d.ts +15 -0
  21. package/dist/commands/mcp/preset.js +84 -0
  22. package/dist/commands/mcp/remove.d.ts +14 -0
  23. package/dist/commands/mcp/remove.js +36 -0
  24. package/dist/commands/mcp/start.d.ts +12 -0
  25. package/dist/commands/mcp/start.js +80 -0
  26. package/dist/commands/mcp/status.d.ts +30 -0
  27. package/dist/commands/mcp/status.js +180 -0
  28. package/dist/commands/mcp/stop.d.ts +12 -0
  29. package/dist/commands/mcp/stop.js +47 -0
  30. package/dist/commands/stories/create.d.ts +1 -0
  31. package/dist/commands/stories/develop.d.ts +1 -0
  32. package/dist/commands/stories/qa.js +34 -75
  33. package/dist/commands/stories/review.d.ts +124 -0
  34. package/dist/commands/stories/review.js +516 -0
  35. package/dist/commands/workflow.d.ts +89 -0
  36. package/dist/commands/workflow.js +487 -14
  37. package/dist/mcp/types.d.ts +99 -0
  38. package/dist/mcp/types.js +7 -0
  39. package/dist/mcp/utils/docker-utils.d.ts +56 -0
  40. package/dist/mcp/utils/docker-utils.js +108 -0
  41. package/dist/mcp/utils/template-loader.d.ts +21 -0
  42. package/dist/mcp/utils/template-loader.js +60 -0
  43. package/dist/models/agent-options.d.ts +10 -1
  44. package/dist/models/index.d.ts +1 -0
  45. package/dist/models/index.js +1 -0
  46. package/dist/models/workflow-callbacks.d.ts +251 -0
  47. package/dist/models/workflow-callbacks.js +10 -0
  48. package/dist/models/workflow-config.d.ts +77 -0
  49. package/dist/models/workflow-result.d.ts +7 -0
  50. package/dist/services/WorkflowReporter.d.ts +165 -0
  51. package/dist/services/WorkflowReporter.js +691 -0
  52. package/dist/services/agents/claude-agent-runner.js +25 -4
  53. package/dist/services/file-system/path-resolver.d.ts +10 -0
  54. package/dist/services/file-system/path-resolver.js +12 -0
  55. package/dist/services/mcp/mcp-config-manager.d.ts +54 -0
  56. package/dist/services/mcp/mcp-config-manager.js +146 -0
  57. package/dist/services/mcp/mcp-context-injector.d.ts +92 -0
  58. package/dist/services/mcp/mcp-context-injector.js +168 -0
  59. package/dist/services/mcp/mcp-credential-manager.d.ts +48 -0
  60. package/dist/services/mcp/mcp-credential-manager.js +124 -0
  61. package/dist/services/mcp/mcp-health-checker.d.ts +56 -0
  62. package/dist/services/mcp/mcp-health-checker.js +162 -0
  63. package/dist/services/mcp/types/health-types.d.ts +31 -0
  64. package/dist/services/mcp/types/health-types.js +7 -0
  65. package/dist/services/orchestration/dependency-graph-executor.js +1 -1
  66. package/dist/services/orchestration/task-decomposition-service.d.ts +2 -1
  67. package/dist/services/orchestration/task-decomposition-service.js +90 -36
  68. package/dist/services/orchestration/workflow-orchestrator.d.ts +87 -3
  69. package/dist/services/orchestration/workflow-orchestrator.js +1169 -289
  70. package/dist/services/review/ai-review-scanner.d.ts +66 -0
  71. package/dist/services/review/ai-review-scanner.js +142 -0
  72. package/dist/services/review/coderabbit-scanner.d.ts +25 -0
  73. package/dist/services/review/coderabbit-scanner.js +31 -0
  74. package/dist/services/review/index.d.ts +20 -0
  75. package/dist/services/review/index.js +15 -0
  76. package/dist/services/review/lint-scanner.d.ts +46 -0
  77. package/dist/services/review/lint-scanner.js +172 -0
  78. package/dist/services/review/review-config.d.ts +62 -0
  79. package/dist/services/review/review-config.js +91 -0
  80. package/dist/services/review/review-phase-executor.d.ts +69 -0
  81. package/dist/services/review/review-phase-executor.js +152 -0
  82. package/dist/services/review/review-queue.d.ts +98 -0
  83. package/dist/services/review/review-queue.js +174 -0
  84. package/dist/services/review/review-reporter.d.ts +94 -0
  85. package/dist/services/review/review-reporter.js +386 -0
  86. package/dist/services/review/scanner-factory.d.ts +42 -0
  87. package/dist/services/review/scanner-factory.js +60 -0
  88. package/dist/services/review/self-heal-loop.d.ts +58 -0
  89. package/dist/services/review/self-heal-loop.js +132 -0
  90. package/dist/services/review/severity-classifier.d.ts +17 -0
  91. package/dist/services/review/severity-classifier.js +314 -0
  92. package/dist/services/review/tech-debt-tracker.d.ts +52 -0
  93. package/dist/services/review/tech-debt-tracker.js +245 -0
  94. package/dist/services/review/types.d.ts +93 -0
  95. package/dist/services/review/types.js +23 -0
  96. package/dist/services/scaffolding/workflow-session-scaffolder.d.ts +182 -0
  97. package/dist/services/scaffolding/workflow-session-scaffolder.js +236 -0
  98. package/dist/services/validation/config-validator.d.ts +84 -0
  99. package/dist/services/validation/config-validator.js +78 -0
  100. package/dist/utils/colors.d.ts +10 -10
  101. package/dist/utils/colors.js +15 -15
  102. package/dist/utils/credential-utils.d.ts +14 -0
  103. package/dist/utils/credential-utils.js +19 -0
  104. package/dist/utils/duration.d.ts +41 -0
  105. package/dist/utils/duration.js +89 -0
  106. package/dist/utils/listr2-helpers.d.ts +216 -0
  107. package/dist/utils/listr2-helpers.js +334 -0
  108. package/dist/utils/shared-flags.d.ts +1 -0
  109. package/dist/utils/shared-flags.js +11 -2
  110. package/package.json +6 -3
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Review Types
3
+ *
4
+ * Core type definitions for the automated code review system.
5
+ * Scanners return raw output; classification into severity levels
6
+ * is handled separately by SeverityClassifier (Story 1.2).
7
+ *
8
+ * Severity model maps to BMAD governance:
9
+ * CRITICAL = NON-NEGOTIABLE (blocks pipeline)
10
+ * HIGH = MUST (blocks pipeline)
11
+ * MEDIUM = SHOULD (documented as tech debt)
12
+ * LOW = MAY (noted only)
13
+ */
14
+ /**
15
+ * Issue severity levels aligned with BMAD governance tiers
16
+ */
17
+ export declare enum Severity {
18
+ CRITICAL = "CRITICAL",
19
+ HIGH = "HIGH",
20
+ LOW = "LOW",
21
+ MEDIUM = "MEDIUM"
22
+ }
23
+ /**
24
+ * Review verdict — PASS allows pipeline to continue, FAIL blocks it
25
+ */
26
+ export type ReviewVerdict = 'FAIL' | 'PASS';
27
+ /**
28
+ * Context provided to scanners describing what to review
29
+ */
30
+ export interface ReviewContext {
31
+ /** Base branch to diff against (e.g., "main", "develop") */
32
+ baseBranch: string;
33
+ /** List of changed file paths (relative to projectRoot) */
34
+ changedFiles: string[];
35
+ /** Absolute path to the project root directory */
36
+ projectRoot: string;
37
+ /** List of reference file paths for context (e.g., architecture docs) */
38
+ referenceFiles: string[];
39
+ /** Absolute path to the story markdown file */
40
+ storyFile: string;
41
+ /** Story identifier (e.g., "PROJ-story-1.001") */
42
+ storyId: string;
43
+ }
44
+ /**
45
+ * Raw output from a scanner before classification
46
+ */
47
+ export interface RawReviewOutput {
48
+ /** Raw scanner output (lint text, AI response, etc.) */
49
+ raw: string;
50
+ /** Identifier of the scanner that produced this output (e.g., "eslint", "claude-ai", "coderabbit") */
51
+ source: string;
52
+ }
53
+ /**
54
+ * A single classified issue with severity and location
55
+ */
56
+ export interface ClassifiedIssue {
57
+ /** File path where the issue was found */
58
+ file: string;
59
+ /** Suggested fix (optional) */
60
+ fix?: string;
61
+ /** Description of the issue */
62
+ issue: string;
63
+ /** Line number where the issue occurs */
64
+ line: number;
65
+ /** Severity level of the issue */
66
+ severity: Severity;
67
+ }
68
+ /**
69
+ * Final review result after classification and optional self-heal iterations
70
+ */
71
+ export interface ReviewResult {
72
+ /** All classified issues found during review */
73
+ issues: ClassifiedIssue[];
74
+ /** Number of self-heal iterations performed (0 if no retries) */
75
+ iterations: number;
76
+ /** Optional summary message */
77
+ message?: string;
78
+ /** Overall verdict — PASS or FAIL */
79
+ verdict: ReviewVerdict;
80
+ }
81
+ /**
82
+ * Scanner interface — all scanner implementations (lint, AI, CodeRabbit) must implement this.
83
+ * Mirrors the AIProviderRunner pattern: single async method with typed input/output.
84
+ */
85
+ export interface ReviewScanner {
86
+ /**
87
+ * Scan the given context and produce raw review output
88
+ *
89
+ * @param context - Review context describing what to scan
90
+ * @returns Raw output from the scanner
91
+ */
92
+ scan(context: ReviewContext): Promise<RawReviewOutput>;
93
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Review Types
3
+ *
4
+ * Core type definitions for the automated code review system.
5
+ * Scanners return raw output; classification into severity levels
6
+ * is handled separately by SeverityClassifier (Story 1.2).
7
+ *
8
+ * Severity model maps to BMAD governance:
9
+ * CRITICAL = NON-NEGOTIABLE (blocks pipeline)
10
+ * HIGH = MUST (blocks pipeline)
11
+ * MEDIUM = SHOULD (documented as tech debt)
12
+ * LOW = MAY (noted only)
13
+ */
14
+ /**
15
+ * Issue severity levels aligned with BMAD governance tiers
16
+ */
17
+ export var Severity;
18
+ (function (Severity) {
19
+ Severity["CRITICAL"] = "CRITICAL";
20
+ Severity["HIGH"] = "HIGH";
21
+ Severity["LOW"] = "LOW";
22
+ Severity["MEDIUM"] = "MEDIUM";
23
+ })(Severity || (Severity = {}));
@@ -0,0 +1,182 @@
1
+ /**
2
+ * WorkflowSessionScaffolder
3
+ *
4
+ * Creates structured session directories with spawn output files and summary reports.
5
+ * Provides persistent, browsable artifacts for troubleshooting and audit trails
6
+ * after each workflow run.
7
+ */
8
+ import type pino from 'pino';
9
+ import type { FileManager } from '../file-system/file-manager.js';
10
+ import type { WorkflowLogFile } from '../logging/workflow-logger.js';
11
+ /**
12
+ * Configuration for creating a workflow session
13
+ */
14
+ export interface WorkflowSessionConfig {
15
+ /** Base directory for workflow sessions (e.g., 'docs/workflow-sessions') */
16
+ baseDir: string;
17
+ /** Session prefix (e.g., 'workflow', 'bmad-run') */
18
+ prefix: string;
19
+ }
20
+ /**
21
+ * Spawn output payload structure
22
+ */
23
+ export interface SpawnOutputPayload {
24
+ /** Timestamp when spawn completed */
25
+ completedAt?: string;
26
+ /** Spawn output content */
27
+ content: string;
28
+ /** Spawn execution duration in milliseconds */
29
+ duration?: number;
30
+ /** Any errors from the spawn */
31
+ errors?: string;
32
+ /** Unique spawn identifier */
33
+ spawnId: string;
34
+ /** Whether the spawn succeeded */
35
+ success?: boolean;
36
+ /** Type of spawn: epic, story, or dev */
37
+ type: 'dev' | 'epic' | 'story';
38
+ }
39
+ /**
40
+ * Session report summary structure
41
+ */
42
+ export interface SessionReportSummary {
43
+ /** Total duration in milliseconds */
44
+ duration: number;
45
+ /** Session end timestamp */
46
+ endedAt: string;
47
+ /** List of errors encountered */
48
+ errors: Array<{
49
+ error: string;
50
+ identifier: string;
51
+ phase: string;
52
+ timestamp: string;
53
+ }>;
54
+ /** Overall success status */
55
+ overallSuccess: boolean;
56
+ /** Phase execution counts */
57
+ phases: {
58
+ developments: {
59
+ completed: number;
60
+ failed: number;
61
+ total: number;
62
+ };
63
+ epics: {
64
+ completed: number;
65
+ failed: number;
66
+ total: number;
67
+ };
68
+ stories: {
69
+ completed: number;
70
+ failed: number;
71
+ total: number;
72
+ };
73
+ };
74
+ /** Session identifier */
75
+ sessionId: string;
76
+ /** List of spawn files written */
77
+ spawnFiles: string[];
78
+ /** Session start timestamp */
79
+ startedAt: string;
80
+ }
81
+ /**
82
+ * Scaffolder for workflow session directory structure
83
+ */
84
+ export declare class WorkflowSessionScaffolder {
85
+ private readonly fileManager;
86
+ private readonly logger;
87
+ private sessionDir;
88
+ constructor(fileManager: FileManager, logger: pino.Logger);
89
+ /**
90
+ * Create the session directory structure
91
+ *
92
+ * Creates:
93
+ * - Session root directory at `{baseDir}/{prefix}-{timestamp}/`
94
+ * - `spawns/` subdirectory for individual spawn output files
95
+ *
96
+ * @param config - Session configuration
97
+ * @returns Session directory path
98
+ */
99
+ createSessionStructure(config: WorkflowSessionConfig): Promise<string>;
100
+ /**
101
+ * Get the current session directory path
102
+ *
103
+ * @returns Session directory path or null if not created
104
+ */
105
+ getSessionDir(): null | string;
106
+ /**
107
+ * Write session report markdown file
108
+ *
109
+ * Generates SESSION_REPORT.md with execution summary, pass/fail counts,
110
+ * durations, and error listings.
111
+ *
112
+ * @param summary - Session execution summary
113
+ */
114
+ writeSessionReport(summary: SessionReportSummary): Promise<void>;
115
+ /**
116
+ * Write individual spawn output file
117
+ *
118
+ * Writes immediately (no buffering) to ensure partial results survive crashes.
119
+ *
120
+ * @param spawnId - Unique spawn identifier
121
+ * @param type - Type of spawn (epic, story, dev)
122
+ * @param content - Spawn output content
123
+ */
124
+ writeSpawnOutput(spawnId: string, type: 'dev' | 'epic' | 'story', content: string): Promise<void>;
125
+ /**
126
+ * Write individual spawn output file with full payload
127
+ *
128
+ * Writes immediately (no buffering) to ensure partial results survive crashes.
129
+ *
130
+ * @param payload - Full spawn output payload
131
+ */
132
+ writeSpawnOutput(payload: SpawnOutputPayload): Promise<void>;
133
+ /**
134
+ * Write workflow log YAML file
135
+ *
136
+ * Generates workflow-log.yaml machine-parseable audit trail file.
137
+ *
138
+ * @param logData - Full workflow log data (WorkflowLogFile interface)
139
+ */
140
+ writeWorkflowLog(logData: WorkflowLogFile): Promise<void>;
141
+ /**
142
+ * Build markdown content for session report
143
+ *
144
+ * @param summary - Session report summary
145
+ * @returns Formatted markdown content
146
+ * @private
147
+ */
148
+ private buildSessionReportMarkdown;
149
+ /**
150
+ * Build markdown content for spawn output file
151
+ *
152
+ * @param payload - Spawn output payload
153
+ * @returns Formatted markdown content
154
+ * @private
155
+ */
156
+ private buildSpawnMarkdown;
157
+ /**
158
+ * Capitalize first letter of a string
159
+ *
160
+ * @param str - String to capitalize
161
+ * @returns Capitalized string
162
+ * @private
163
+ */
164
+ private capitalizeFirst;
165
+ /**
166
+ * Format duration in human-readable format
167
+ *
168
+ * @param ms - Duration in milliseconds
169
+ * @returns Formatted duration string
170
+ * @private
171
+ */
172
+ private formatDuration;
173
+ /**
174
+ * Generate timestamp string for session directory name
175
+ *
176
+ * Format: YYYYMMDD-HHmmss
177
+ *
178
+ * @returns Formatted timestamp
179
+ * @private
180
+ */
181
+ private generateTimestamp;
182
+ }
@@ -0,0 +1,236 @@
1
+ /**
2
+ * WorkflowSessionScaffolder
3
+ *
4
+ * Creates structured session directories with spawn output files and summary reports.
5
+ * Provides persistent, browsable artifacts for troubleshooting and audit trails
6
+ * after each workflow run.
7
+ */
8
+ import * as yaml from 'js-yaml';
9
+ import { join } from 'node:path';
10
+ /**
11
+ * Scaffolder for workflow session directory structure
12
+ */
13
+ export class WorkflowSessionScaffolder {
14
+ fileManager;
15
+ logger;
16
+ sessionDir = null;
17
+ constructor(fileManager, logger) {
18
+ this.fileManager = fileManager;
19
+ this.logger = logger;
20
+ }
21
+ /**
22
+ * Create the session directory structure
23
+ *
24
+ * Creates:
25
+ * - Session root directory at `{baseDir}/{prefix}-{timestamp}/`
26
+ * - `spawns/` subdirectory for individual spawn output files
27
+ *
28
+ * @param config - Session configuration
29
+ * @returns Session directory path
30
+ */
31
+ async createSessionStructure(config) {
32
+ const timestamp = this.generateTimestamp();
33
+ const sessionDirName = `${config.prefix}-${timestamp}`;
34
+ const sessionDir = join(config.baseDir, sessionDirName);
35
+ this.logger.info({ prefix: config.prefix, sessionDir }, 'Creating workflow session structure');
36
+ // Create root session directory
37
+ await this.fileManager.createDirectory(sessionDir);
38
+ // Create spawns subdirectory
39
+ await this.fileManager.createDirectory(join(sessionDir, 'spawns'));
40
+ this.sessionDir = sessionDir;
41
+ this.logger.info({ sessionDir }, 'Workflow session structure created');
42
+ return sessionDir;
43
+ }
44
+ /**
45
+ * Get the current session directory path
46
+ *
47
+ * @returns Session directory path or null if not created
48
+ */
49
+ getSessionDir() {
50
+ return this.sessionDir;
51
+ }
52
+ /**
53
+ * Write session report markdown file
54
+ *
55
+ * Generates SESSION_REPORT.md with execution summary, pass/fail counts,
56
+ * durations, and error listings.
57
+ *
58
+ * @param summary - Session execution summary
59
+ */
60
+ async writeSessionReport(summary) {
61
+ if (!this.sessionDir) {
62
+ throw new Error('Session structure must be created before writing session report');
63
+ }
64
+ const reportPath = join(this.sessionDir, 'SESSION_REPORT.md');
65
+ this.logger.info({ reportPath, sessionId: summary.sessionId }, 'Writing session report');
66
+ const markdownContent = this.buildSessionReportMarkdown(summary);
67
+ await this.fileManager.writeFile(reportPath, markdownContent);
68
+ this.logger.info({ reportPath }, 'Session report written');
69
+ }
70
+ async writeSpawnOutput(spawnIdOrPayload, type, content) {
71
+ if (!this.sessionDir) {
72
+ throw new Error('Session structure must be created before writing spawn output');
73
+ }
74
+ // Normalize to payload
75
+ const payload = typeof spawnIdOrPayload === 'string'
76
+ ? {
77
+ content: content,
78
+ spawnId: spawnIdOrPayload,
79
+ type: type,
80
+ }
81
+ : spawnIdOrPayload;
82
+ const fileName = `${payload.type}-${payload.spawnId}.md`;
83
+ const filePath = join(this.sessionDir, 'spawns', fileName);
84
+ this.logger.info({ filePath, spawnId: payload.spawnId, type: payload.type }, 'Writing spawn output');
85
+ // Build markdown content with metadata header
86
+ const markdownContent = this.buildSpawnMarkdown(payload);
87
+ // Immediate write for crash resilience
88
+ await this.fileManager.writeFile(filePath, markdownContent);
89
+ this.logger.info({ filePath, spawnId: payload.spawnId }, 'Spawn output written');
90
+ }
91
+ /**
92
+ * Write workflow log YAML file
93
+ *
94
+ * Generates workflow-log.yaml machine-parseable audit trail file.
95
+ *
96
+ * @param logData - Full workflow log data (WorkflowLogFile interface)
97
+ */
98
+ async writeWorkflowLog(logData) {
99
+ if (!this.sessionDir) {
100
+ throw new Error('Session structure must be created before writing workflow log');
101
+ }
102
+ const logPath = join(this.sessionDir, 'workflow-log.yaml');
103
+ this.logger.info({ logPath, workflowId: logData.metadata.workflowId }, 'Writing workflow log');
104
+ const yamlContent = yaml.dump(logData, {
105
+ indent: 2,
106
+ lineWidth: 120,
107
+ noRefs: true,
108
+ });
109
+ await this.fileManager.writeFile(logPath, yamlContent);
110
+ this.logger.info({ logPath }, 'Workflow log written');
111
+ }
112
+ /**
113
+ * Build markdown content for session report
114
+ *
115
+ * @param summary - Session report summary
116
+ * @returns Formatted markdown content
117
+ * @private
118
+ */
119
+ buildSessionReportMarkdown(summary) {
120
+ const statusIcon = summary.overallSuccess ? '✅' : '❌';
121
+ const durationStr = this.formatDuration(summary.duration);
122
+ let md = `# Workflow Session Report\n\n`;
123
+ // Metadata section
124
+ md += `## Metadata\n\n`;
125
+ md += `- **Session ID:** ${summary.sessionId}\n`;
126
+ md += `- **Status:** ${statusIcon} ${summary.overallSuccess ? 'Completed Successfully' : 'Completed with Failures'}\n`;
127
+ md += `- **Started:** ${summary.startedAt}\n`;
128
+ md += `- **Ended:** ${summary.endedAt}\n`;
129
+ md += `- **Duration:** ${durationStr}\n\n`;
130
+ // Execution summary table
131
+ md += `## Execution Summary\n\n`;
132
+ md += `| Phase | Total | Completed | Failed | Pass Rate |\n`;
133
+ md += `|-------|-------|-----------|--------|------------|\n`;
134
+ for (const [phase, counts] of Object.entries(summary.phases)) {
135
+ const passRate = counts.total > 0 ? ((counts.completed / counts.total) * 100).toFixed(1) : '0.0';
136
+ md += `| ${this.capitalizeFirst(phase)} | ${counts.total} | ${counts.completed} | ${counts.failed} | ${passRate}% |\n`;
137
+ }
138
+ md += `\n`;
139
+ // Error listings (if any)
140
+ if (summary.errors.length > 0) {
141
+ md += `## Errors (${summary.errors.length})\n\n`;
142
+ for (const error of summary.errors) {
143
+ md += `### ${error.phase.toUpperCase()} - ${error.identifier}\n\n`;
144
+ md += `- **Timestamp:** ${error.timestamp}\n`;
145
+ md += `- **Error:** ${error.error}\n\n`;
146
+ }
147
+ }
148
+ // Spawn file inventory
149
+ md += `## Spawn Files\n\n`;
150
+ if (summary.spawnFiles.length > 0) {
151
+ for (const file of summary.spawnFiles) {
152
+ md += `- \`${file}\`\n`;
153
+ }
154
+ }
155
+ else {
156
+ md += `_No spawn files generated_\n`;
157
+ }
158
+ md += `\n---\n\n`;
159
+ md += `<!-- Powered by BMAD™ Core -->\n`;
160
+ return md;
161
+ }
162
+ /**
163
+ * Build markdown content for spawn output file
164
+ *
165
+ * @param payload - Spawn output payload
166
+ * @returns Formatted markdown content
167
+ * @private
168
+ */
169
+ buildSpawnMarkdown(payload) {
170
+ const statusIcon = payload.success === false ? '❌' : payload.success === true ? '✅' : '⏳';
171
+ const durationStr = payload.duration ? this.formatDuration(payload.duration) : 'N/A';
172
+ let md = `# ${payload.type.toUpperCase()} Spawn: ${payload.spawnId}\n\n`;
173
+ md += `## Metadata\n\n`;
174
+ md += `- **Spawn ID:** ${payload.spawnId}\n`;
175
+ md += `- **Type:** ${payload.type}\n`;
176
+ md += `- **Status:** ${statusIcon} ${payload.success === false ? 'Failed' : payload.success === true ? 'Success' : 'Unknown'}\n`;
177
+ md += `- **Duration:** ${durationStr}\n`;
178
+ if (payload.completedAt) {
179
+ md += `- **Completed At:** ${payload.completedAt}\n`;
180
+ }
181
+ md += `\n`;
182
+ if (payload.errors) {
183
+ md += `## Errors\n\n`;
184
+ md += `\`\`\`\n${payload.errors}\n\`\`\`\n\n`;
185
+ }
186
+ md += `## Output\n\n`;
187
+ md += `${payload.content}\n\n`;
188
+ md += `---\n\n`;
189
+ md += `<!-- Powered by BMAD™ Core -->\n`;
190
+ return md;
191
+ }
192
+ /**
193
+ * Capitalize first letter of a string
194
+ *
195
+ * @param str - String to capitalize
196
+ * @returns Capitalized string
197
+ * @private
198
+ */
199
+ capitalizeFirst(str) {
200
+ return str.charAt(0).toUpperCase() + str.slice(1);
201
+ }
202
+ /**
203
+ * Format duration in human-readable format
204
+ *
205
+ * @param ms - Duration in milliseconds
206
+ * @returns Formatted duration string
207
+ * @private
208
+ */
209
+ formatDuration(ms) {
210
+ if (ms < 1000)
211
+ return `${ms}ms`;
212
+ if (ms < 60_000)
213
+ return `${(ms / 1000).toFixed(1)}s`;
214
+ if (ms < 3_600_000)
215
+ return `${(ms / 60_000).toFixed(1)}m`;
216
+ return `${(ms / 3_600_000).toFixed(1)}h`;
217
+ }
218
+ /**
219
+ * Generate timestamp string for session directory name
220
+ *
221
+ * Format: YYYYMMDD-HHmmss
222
+ *
223
+ * @returns Formatted timestamp
224
+ * @private
225
+ */
226
+ generateTimestamp() {
227
+ const now = new Date();
228
+ const year = now.getFullYear();
229
+ const month = String(now.getMonth() + 1).padStart(2, '0');
230
+ const day = String(now.getDate()).padStart(2, '0');
231
+ const hours = String(now.getHours()).padStart(2, '0');
232
+ const minutes = String(now.getMinutes()).padStart(2, '0');
233
+ const seconds = String(now.getSeconds()).padStart(2, '0');
234
+ return `${year}${month}${day}-${hours}${minutes}${seconds}`;
235
+ }
236
+ }
@@ -8,6 +8,53 @@
8
8
  import type pino from 'pino';
9
9
  import { z } from 'zod';
10
10
  import type { FileManager } from '../file-system/file-manager.js';
11
+ /**
12
+ * Zod schema for review configuration section
13
+ *
14
+ * Defines scanners, severity thresholds, self-heal limits, and path rules
15
+ * for automated code review in the BMAD workflow pipeline.
16
+ */
17
+ export declare const reviewConfigSchema: z.ZodObject<{
18
+ enabled: z.ZodDefault<z.ZodBoolean>;
19
+ pathRules: z.ZodOptional<z.ZodArray<z.ZodObject<{
20
+ focus: z.ZodString;
21
+ pattern: z.ZodString;
22
+ }, z.core.$strip>>>;
23
+ scanners: z.ZodDefault<z.ZodArray<z.ZodEnum<{
24
+ ai: "ai";
25
+ coderabbit: "coderabbit";
26
+ lint: "lint";
27
+ }>>>;
28
+ selfHeal: z.ZodDefault<z.ZodObject<{
29
+ fixAgent: z.ZodDefault<z.ZodString>;
30
+ fixTimeout: z.ZodDefault<z.ZodNumber>;
31
+ maxIterations: z.ZodDefault<z.ZodNumber>;
32
+ }, z.core.$strip>>;
33
+ severity: z.ZodDefault<z.ZodObject<{
34
+ blockOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
35
+ CRITICAL: "CRITICAL";
36
+ HIGH: "HIGH";
37
+ LOW: "LOW";
38
+ MEDIUM: "MEDIUM";
39
+ }>>>;
40
+ documentOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
41
+ CRITICAL: "CRITICAL";
42
+ HIGH: "HIGH";
43
+ LOW: "LOW";
44
+ MEDIUM: "MEDIUM";
45
+ }>>>;
46
+ ignoreOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
47
+ CRITICAL: "CRITICAL";
48
+ HIGH: "HIGH";
49
+ LOW: "LOW";
50
+ MEDIUM: "MEDIUM";
51
+ }>>>;
52
+ }, z.core.$strip>>;
53
+ }, z.core.$strip>;
54
+ /**
55
+ * Inferred TypeScript type from review config Zod schema
56
+ */
57
+ export type ReviewConfig = z.infer<typeof reviewConfigSchema>;
11
58
  /**
12
59
  * Zod schema for core configuration
13
60
  *
@@ -22,6 +69,43 @@ declare const configSchema: z.ZodObject<{
22
69
  qa: z.ZodOptional<z.ZodObject<{
23
70
  qaLocation: z.ZodOptional<z.ZodString>;
24
71
  }, z.core.$strip>>;
72
+ review: z.ZodOptional<z.ZodObject<{
73
+ enabled: z.ZodDefault<z.ZodBoolean>;
74
+ pathRules: z.ZodOptional<z.ZodArray<z.ZodObject<{
75
+ focus: z.ZodString;
76
+ pattern: z.ZodString;
77
+ }, z.core.$strip>>>;
78
+ scanners: z.ZodDefault<z.ZodArray<z.ZodEnum<{
79
+ ai: "ai";
80
+ coderabbit: "coderabbit";
81
+ lint: "lint";
82
+ }>>>;
83
+ selfHeal: z.ZodDefault<z.ZodObject<{
84
+ fixAgent: z.ZodDefault<z.ZodString>;
85
+ fixTimeout: z.ZodDefault<z.ZodNumber>;
86
+ maxIterations: z.ZodDefault<z.ZodNumber>;
87
+ }, z.core.$strip>>;
88
+ severity: z.ZodDefault<z.ZodObject<{
89
+ blockOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
90
+ CRITICAL: "CRITICAL";
91
+ HIGH: "HIGH";
92
+ LOW: "LOW";
93
+ MEDIUM: "MEDIUM";
94
+ }>>>;
95
+ documentOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
96
+ CRITICAL: "CRITICAL";
97
+ HIGH: "HIGH";
98
+ LOW: "LOW";
99
+ MEDIUM: "MEDIUM";
100
+ }>>>;
101
+ ignoreOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
102
+ CRITICAL: "CRITICAL";
103
+ HIGH: "HIGH";
104
+ LOW: "LOW";
105
+ MEDIUM: "MEDIUM";
106
+ }>>>;
107
+ }, z.core.$strip>>;
108
+ }, z.core.$strip>>;
25
109
  }, z.core.$strip>;
26
110
  /**
27
111
  * Inferred TypeScript type from Zod schema