@hyperdrive.bot/bmad-workflow 1.0.18 → 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 (98) 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 +5 -2
  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 +8 -0
  36. package/dist/commands/workflow.js +110 -2
  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/workflow-config.d.ts +77 -0
  45. package/dist/models/workflow-result.d.ts +7 -0
  46. package/dist/services/agents/claude-agent-runner.js +19 -3
  47. package/dist/services/file-system/path-resolver.d.ts +10 -0
  48. package/dist/services/file-system/path-resolver.js +12 -0
  49. package/dist/services/mcp/mcp-config-manager.d.ts +54 -0
  50. package/dist/services/mcp/mcp-config-manager.js +146 -0
  51. package/dist/services/mcp/mcp-context-injector.d.ts +92 -0
  52. package/dist/services/mcp/mcp-context-injector.js +168 -0
  53. package/dist/services/mcp/mcp-credential-manager.d.ts +48 -0
  54. package/dist/services/mcp/mcp-credential-manager.js +124 -0
  55. package/dist/services/mcp/mcp-health-checker.d.ts +56 -0
  56. package/dist/services/mcp/mcp-health-checker.js +162 -0
  57. package/dist/services/mcp/types/health-types.d.ts +31 -0
  58. package/dist/services/mcp/types/health-types.js +7 -0
  59. package/dist/services/orchestration/dependency-graph-executor.js +1 -1
  60. package/dist/services/orchestration/task-decomposition-service.d.ts +2 -1
  61. package/dist/services/orchestration/task-decomposition-service.js +90 -36
  62. package/dist/services/orchestration/workflow-orchestrator.d.ts +54 -2
  63. package/dist/services/orchestration/workflow-orchestrator.js +303 -17
  64. package/dist/services/review/ai-review-scanner.d.ts +66 -0
  65. package/dist/services/review/ai-review-scanner.js +142 -0
  66. package/dist/services/review/coderabbit-scanner.d.ts +25 -0
  67. package/dist/services/review/coderabbit-scanner.js +31 -0
  68. package/dist/services/review/index.d.ts +20 -0
  69. package/dist/services/review/index.js +15 -0
  70. package/dist/services/review/lint-scanner.d.ts +46 -0
  71. package/dist/services/review/lint-scanner.js +172 -0
  72. package/dist/services/review/review-config.d.ts +62 -0
  73. package/dist/services/review/review-config.js +91 -0
  74. package/dist/services/review/review-phase-executor.d.ts +69 -0
  75. package/dist/services/review/review-phase-executor.js +152 -0
  76. package/dist/services/review/review-queue.d.ts +98 -0
  77. package/dist/services/review/review-queue.js +174 -0
  78. package/dist/services/review/review-reporter.d.ts +94 -0
  79. package/dist/services/review/review-reporter.js +386 -0
  80. package/dist/services/review/scanner-factory.d.ts +42 -0
  81. package/dist/services/review/scanner-factory.js +60 -0
  82. package/dist/services/review/self-heal-loop.d.ts +58 -0
  83. package/dist/services/review/self-heal-loop.js +132 -0
  84. package/dist/services/review/severity-classifier.d.ts +17 -0
  85. package/dist/services/review/severity-classifier.js +314 -0
  86. package/dist/services/review/tech-debt-tracker.d.ts +52 -0
  87. package/dist/services/review/tech-debt-tracker.js +245 -0
  88. package/dist/services/review/types.d.ts +93 -0
  89. package/dist/services/review/types.js +23 -0
  90. package/dist/services/validation/config-validator.d.ts +84 -0
  91. package/dist/services/validation/config-validator.js +78 -0
  92. package/dist/utils/credential-utils.d.ts +14 -0
  93. package/dist/utils/credential-utils.js +19 -0
  94. package/dist/utils/duration.d.ts +41 -0
  95. package/dist/utils/duration.js +89 -0
  96. package/dist/utils/shared-flags.d.ts +1 -0
  97. package/dist/utils/shared-flags.js +11 -2
  98. package/package.json +4 -2
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Review Phase Executor
3
+ *
4
+ * Orchestrates automated code review on completed stories. Runs scanners
5
+ * via SelfHealLoop, classifies issues, tracks tech debt, and produces
6
+ * PASS/FAIL verdicts per story.
7
+ *
8
+ * The interface is consumed by WorkflowOrchestrator for both sequential
9
+ * and pipelined review execution paths. The concrete implementation
10
+ * (DefaultReviewPhaseExecutor) composes SelfHealLoop and TechDebtTracker.
11
+ */
12
+ import { Severity } from './types.js';
13
+ /** Default severity threshold that blocks the pipeline */
14
+ const DEFAULT_BLOCK_ON = Severity.HIGH;
15
+ /** Severity rank for comparison (higher = more severe) */
16
+ const SEVERITY_RANK = {
17
+ [Severity.CRITICAL]: 4,
18
+ [Severity.HIGH]: 3,
19
+ [Severity.MEDIUM]: 2,
20
+ [Severity.LOW]: 1,
21
+ };
22
+ /**
23
+ * Concrete implementation of ReviewPhaseExecutor.
24
+ *
25
+ * Composes SelfHealLoop (scan + classify + fix) and TechDebtTracker
26
+ * (MEDIUM issues → story file / session backlog). Accepts dependencies
27
+ * via constructor injection for testability.
28
+ */
29
+ export class DefaultReviewPhaseExecutor {
30
+ logger;
31
+ reporter;
32
+ selfHealLoop;
33
+ techDebtTracker;
34
+ constructor(selfHealLoop, techDebtTracker, logger, reporter) {
35
+ this.selfHealLoop = selfHealLoop;
36
+ this.techDebtTracker = techDebtTracker;
37
+ this.logger = logger;
38
+ this.reporter = reporter;
39
+ }
40
+ /**
41
+ * Review a single story using the self-heal loop.
42
+ *
43
+ * @param story - Story to review
44
+ * @param config - Workflow configuration
45
+ * @returns ReviewResult with verdict and issues
46
+ */
47
+ async reviewStory(story, config) {
48
+ const storyId = story.fullNumber;
49
+ const storyFile = story.filePath ?? '';
50
+ const blockOn = config.reviewBlockOn ?? DEFAULT_BLOCK_ON;
51
+ this.logger.info({ storyId, blockOn }, 'Reviewing story');
52
+ const context = {
53
+ baseBranch: 'main',
54
+ changedFiles: [],
55
+ projectRoot: config.cwd ?? process.cwd(),
56
+ referenceFiles: config.references ?? [],
57
+ storyFile,
58
+ storyId,
59
+ };
60
+ // Run self-heal loop (scan → classify → fix → rescan)
61
+ const result = await this.selfHealLoop.execute(context);
62
+ // Override verdict based on config.reviewBlockOn threshold
63
+ const blockingIssues = result.issues.filter((issue) => SEVERITY_RANK[issue.severity] >= SEVERITY_RANK[blockOn]);
64
+ const verdict = blockingIssues.length > 0 ? 'FAIL' : 'PASS';
65
+ // Track MEDIUM issues as tech debt
66
+ if (storyFile) {
67
+ await this.techDebtTracker.appendToStory(result.issues, storyFile);
68
+ }
69
+ // Build final result early so reporter gets the enriched result
70
+ const finalResult = {
71
+ issues: result.issues,
72
+ iterations: result.iterations,
73
+ message: verdict === 'FAIL'
74
+ ? `${blockingIssues.length} blocking issue(s) (>= ${blockOn}) remain after ${result.iterations} iteration(s)`
75
+ : result.message,
76
+ verdict,
77
+ };
78
+ // Append review report to story file
79
+ if (this.reporter && storyFile) {
80
+ await this.reporter.appendStoryReport(storyFile, finalResult);
81
+ }
82
+ if (verdict === 'FAIL') {
83
+ this.logger.warn({
84
+ blockingCount: blockingIssues.length,
85
+ iterations: result.iterations,
86
+ storyId,
87
+ verdict,
88
+ }, `Story ${storyId} review FAILED — ${blockingIssues.length} blocking issue(s) remain`);
89
+ }
90
+ else {
91
+ this.logger.info({ iterations: result.iterations, storyId, verdict }, `Story ${storyId} review PASSED`);
92
+ }
93
+ return finalResult;
94
+ }
95
+ /**
96
+ * Review all stories and return a map of storyId → ReviewResult.
97
+ *
98
+ * Only stories with verdict PASS are considered passing. FAIL stories
99
+ * are logged with a warning including failure reasons.
100
+ *
101
+ * @param stories - Story file paths to review
102
+ * @param config - Workflow configuration
103
+ * @returns Map of story identifier to ReviewResult
104
+ */
105
+ async reviewAll(stories, config) {
106
+ const results = new Map();
107
+ if (stories.length === 0) {
108
+ this.logger.info('No stories to review');
109
+ return results;
110
+ }
111
+ this.logger.info({ storyCount: stories.length }, 'Starting review for all stories');
112
+ for (const storyFile of stories) {
113
+ const storyId = this.extractStoryId(storyFile);
114
+ const story = {
115
+ epicNumber: 0,
116
+ filePath: storyFile,
117
+ fullNumber: storyId,
118
+ number: 0,
119
+ title: storyId,
120
+ };
121
+ const result = await this.reviewStory(story, config);
122
+ results.set(storyId, result);
123
+ }
124
+ // Log summary
125
+ let passCount = 0;
126
+ let failCount = 0;
127
+ for (const [storyId, result] of results) {
128
+ if (result.verdict === 'PASS') {
129
+ passCount++;
130
+ }
131
+ else {
132
+ failCount++;
133
+ this.logger.warn({ reason: result.message, storyId }, 'Story excluded from QA — review FAILED');
134
+ }
135
+ }
136
+ this.logger.info({ failCount, passCount, totalStories: stories.length }, 'Review phase complete');
137
+ // Write session-level reports (reporter handles undefined sessionDir gracefully)
138
+ if (this.reporter) {
139
+ const sessionDir = config.sessionDir;
140
+ await this.reporter.writeSessionReports(sessionDir, results);
141
+ }
142
+ return results;
143
+ }
144
+ /**
145
+ * Extract a story identifier from a file path.
146
+ * e.g. "docs/stories/PROJ-story-1.001.md" → "PROJ-story-1.001"
147
+ */
148
+ extractStoryId(filePath) {
149
+ const filename = filePath.split('/').pop() ?? filePath;
150
+ return filename.replace(/\.md$/, '');
151
+ }
152
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Review Queue
3
+ *
4
+ * FIFO queue for coordinating pipelined review execution. Dev workers enqueue
5
+ * completed stories; review workers dequeue and process them. Supports concurrent
6
+ * consumers with async waiting when queue is empty.
7
+ *
8
+ * Lifecycle:
9
+ * Producer: dev workers → enqueue(story) on successful dev completion
10
+ * Consumer: review workers → dequeue() to process stories for review
11
+ * Close: when all dev workers finish → close() → consumers drain → terminate
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import pino from 'pino'
16
+ * import { ReviewQueue } from './review-queue.js'
17
+ *
18
+ * const logger = pino()
19
+ * const queue = new ReviewQueue(logger)
20
+ *
21
+ * // Dev worker: enqueue completed story
22
+ * queue.enqueue(story)
23
+ *
24
+ * // Review worker: dequeue story for review
25
+ * const story = await queue.dequeue()
26
+ * if (story === null) {
27
+ * // Queue is closed and empty
28
+ * return
29
+ * }
30
+ *
31
+ * // When all dev workers finish, close the queue
32
+ * queue.close()
33
+ * ```
34
+ */
35
+ import type pino from 'pino';
36
+ import type { Story } from '../../models/story.js';
37
+ /**
38
+ * FIFO queue for pipelined review coordination.
39
+ *
40
+ * Provides async waiting for consumers when queue is empty. Safe for concurrent
41
+ * access in Node.js event loop (no mutex needed due to single-threaded execution).
42
+ */
43
+ export declare class ReviewQueue {
44
+ /**
45
+ * Flag indicating no more stories will be added
46
+ */
47
+ private closed;
48
+ /**
49
+ * Structured logger instance
50
+ */
51
+ private readonly logger;
52
+ /**
53
+ * Internal FIFO queue of stories
54
+ */
55
+ private queue;
56
+ /**
57
+ * Array of waiting dequeue promises
58
+ */
59
+ private waiters;
60
+ /**
61
+ * Creates a new ReviewQueue instance
62
+ *
63
+ * @param logger - Pino logger for structured logging
64
+ */
65
+ constructor(logger: pino.Logger);
66
+ /**
67
+ * Signals that no more stories will be added to the queue.
68
+ * All waiting dequeue calls will be resolved with null.
69
+ */
70
+ close(): void;
71
+ /**
72
+ * Removes and returns the next story from the queue.
73
+ * If queue is empty and not closed, waits asynchronously for a story to be enqueued.
74
+ * If queue is closed and empty, returns null.
75
+ *
76
+ * @returns Promise that resolves to the next story, or null if queue is closed and empty
77
+ */
78
+ dequeue(): Promise<null | Story>;
79
+ /**
80
+ * Adds a story to the queue
81
+ *
82
+ * @param story - The story to enqueue
83
+ * @throws Error if queue is already closed
84
+ */
85
+ enqueue(story: Story): void;
86
+ /**
87
+ * Gets the number of pending stories in the queue
88
+ *
89
+ * @returns Number of stories waiting to be dequeued
90
+ */
91
+ getPendingCount(): number;
92
+ /**
93
+ * Checks if the queue is empty
94
+ *
95
+ * @returns true if queue has no items, false otherwise
96
+ */
97
+ isEmpty(): boolean;
98
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Review Queue
3
+ *
4
+ * FIFO queue for coordinating pipelined review execution. Dev workers enqueue
5
+ * completed stories; review workers dequeue and process them. Supports concurrent
6
+ * consumers with async waiting when queue is empty.
7
+ *
8
+ * Lifecycle:
9
+ * Producer: dev workers → enqueue(story) on successful dev completion
10
+ * Consumer: review workers → dequeue() to process stories for review
11
+ * Close: when all dev workers finish → close() → consumers drain → terminate
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import pino from 'pino'
16
+ * import { ReviewQueue } from './review-queue.js'
17
+ *
18
+ * const logger = pino()
19
+ * const queue = new ReviewQueue(logger)
20
+ *
21
+ * // Dev worker: enqueue completed story
22
+ * queue.enqueue(story)
23
+ *
24
+ * // Review worker: dequeue story for review
25
+ * const story = await queue.dequeue()
26
+ * if (story === null) {
27
+ * // Queue is closed and empty
28
+ * return
29
+ * }
30
+ *
31
+ * // When all dev workers finish, close the queue
32
+ * queue.close()
33
+ * ```
34
+ */
35
+ /**
36
+ * FIFO queue for pipelined review coordination.
37
+ *
38
+ * Provides async waiting for consumers when queue is empty. Safe for concurrent
39
+ * access in Node.js event loop (no mutex needed due to single-threaded execution).
40
+ */
41
+ export class ReviewQueue {
42
+ /**
43
+ * Flag indicating no more stories will be added
44
+ */
45
+ closed = false;
46
+ /**
47
+ * Structured logger instance
48
+ */
49
+ logger;
50
+ /**
51
+ * Internal FIFO queue of stories
52
+ */
53
+ queue = [];
54
+ /**
55
+ * Array of waiting dequeue promises
56
+ */
57
+ waiters = [];
58
+ /**
59
+ * Creates a new ReviewQueue instance
60
+ *
61
+ * @param logger - Pino logger for structured logging
62
+ */
63
+ constructor(logger) {
64
+ this.logger = logger;
65
+ this.logger.debug('ReviewQueue initialized');
66
+ }
67
+ /**
68
+ * Signals that no more stories will be added to the queue.
69
+ * All waiting dequeue calls will be resolved with null.
70
+ */
71
+ close() {
72
+ if (this.closed) {
73
+ this.logger.warn('Close called on already closed ReviewQueue');
74
+ return;
75
+ }
76
+ this.closed = true;
77
+ this.logger.info({
78
+ remainingQueueSize: this.queue.length,
79
+ waitersToNotify: this.waiters.length,
80
+ }, 'ReviewQueue closed');
81
+ // Wake up all waiting dequeue calls with null
82
+ while (this.waiters.length > 0) {
83
+ const waiter = this.waiters.shift();
84
+ if (waiter) {
85
+ waiter(null);
86
+ }
87
+ }
88
+ }
89
+ /**
90
+ * Removes and returns the next story from the queue.
91
+ * If queue is empty and not closed, waits asynchronously for a story to be enqueued.
92
+ * If queue is closed and empty, returns null.
93
+ *
94
+ * @returns Promise that resolves to the next story, or null if queue is closed and empty
95
+ */
96
+ async dequeue() {
97
+ // If queue has items, return immediately
98
+ if (this.queue.length > 0) {
99
+ const story = this.queue.shift() ?? null;
100
+ this.logger.info({
101
+ remainingQueueSize: this.queue.length,
102
+ storyNumber: story?.fullNumber,
103
+ storyTitle: story?.title,
104
+ }, 'Story dequeued from ReviewQueue');
105
+ return story;
106
+ }
107
+ // If closed and empty, return null
108
+ if (this.closed) {
109
+ this.logger.debug({
110
+ closed: this.closed,
111
+ isEmpty: true,
112
+ }, 'ReviewQueue dequeue returning null: queue closed and empty');
113
+ return null;
114
+ }
115
+ // Wait for item or close
116
+ this.logger.debug({
117
+ closed: this.closed,
118
+ isEmpty: this.isEmpty(),
119
+ waiters: this.waiters.length,
120
+ }, 'ReviewQueue dequeue waiting for story');
121
+ return new Promise((resolve) => {
122
+ this.waiters.push(resolve);
123
+ });
124
+ }
125
+ /**
126
+ * Adds a story to the queue
127
+ *
128
+ * @param story - The story to enqueue
129
+ * @throws Error if queue is already closed
130
+ */
131
+ enqueue(story) {
132
+ if (this.closed) {
133
+ const error = new Error('Cannot enqueue to closed ReviewQueue');
134
+ this.logger.error({
135
+ closed: this.closed,
136
+ storyNumber: story.fullNumber,
137
+ }, 'ReviewQueue enqueue failed: queue closed');
138
+ throw error;
139
+ }
140
+ this.queue.push(story);
141
+ this.logger.info({
142
+ queueSize: this.queue.length,
143
+ storyNumber: story.fullNumber,
144
+ storyTitle: story.title,
145
+ waiters: this.waiters.length,
146
+ }, 'Story enqueued to ReviewQueue');
147
+ // Wake up a waiting dequeue call if any
148
+ const waiter = this.waiters.shift();
149
+ if (waiter) {
150
+ const dequeuedStory = this.queue.shift() ?? null;
151
+ this.logger.debug({
152
+ remainingQueueSize: this.queue.length,
153
+ storyNumber: dequeuedStory?.fullNumber,
154
+ }, 'Woke up waiting ReviewQueue dequeue consumer');
155
+ waiter(dequeuedStory);
156
+ }
157
+ }
158
+ /**
159
+ * Gets the number of pending stories in the queue
160
+ *
161
+ * @returns Number of stories waiting to be dequeued
162
+ */
163
+ getPendingCount() {
164
+ return this.queue.length;
165
+ }
166
+ /**
167
+ * Checks if the queue is empty
168
+ *
169
+ * @returns true if queue has no items, false otherwise
170
+ */
171
+ isEmpty() {
172
+ return this.queue.length === 0;
173
+ }
174
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Review Reporter
3
+ *
4
+ * Generates review report artifacts: per-story markdown appended to story files,
5
+ * and session-level aggregate reports (summary + tech debt backlog + per-story
6
+ * review files) written to the workflow session directory.
7
+ *
8
+ * Consumed by ReviewPhaseExecutor (after each story) and the standalone
9
+ * `stories review` command.
10
+ */
11
+ import type pino from 'pino';
12
+ import type { FileManager } from '../file-system/file-manager.js';
13
+ import type { ReviewResult } from './types.js';
14
+ /**
15
+ * Generates review report markdown for stories and session directories.
16
+ *
17
+ * Follows DI pattern from WorkflowSessionScaffolder: FileManager + Logger.
18
+ */
19
+ export declare class ReviewReporter {
20
+ private readonly fileManager;
21
+ private readonly logger;
22
+ constructor(fileManager: FileManager, logger: pino.Logger);
23
+ /**
24
+ * Append a `## Code Review Results` section to a story markdown file.
25
+ * Inserts before `## Dev Agent Record` if present, otherwise appends at end.
26
+ *
27
+ * Always works regardless of session mode (AC #8).
28
+ *
29
+ * @param storyFilePath - Absolute path to the story markdown file
30
+ * @param result - ReviewResult from the review phase
31
+ */
32
+ appendStoryReport(storyFilePath: string, result: ReviewResult): Promise<void>;
33
+ /**
34
+ * Write all session-level review artifacts to the session directory.
35
+ * Creates `review/` subdirectory containing per-story files, summary, and tech debt backlog.
36
+ *
37
+ * When sessionDir is undefined/null, silently returns (AC #8 — standalone mode guard).
38
+ *
39
+ * @param sessionDir - Absolute path to the workflow session directory, or undefined
40
+ * @param results - Map of storyId → ReviewResult
41
+ */
42
+ writeSessionReports(sessionDir: string | undefined, results: Map<string, ReviewResult>): Promise<void>;
43
+ /**
44
+ * Format the per-story review report block to be appended to a story file.
45
+ *
46
+ * @param result - ReviewResult for the story
47
+ * @returns Markdown string for the review section
48
+ */
49
+ formatStoryReport(result: ReviewResult): string;
50
+ /**
51
+ * Format the session-level review summary markdown.
52
+ *
53
+ * @param results - Map of storyId → ReviewResult
54
+ * @returns Complete markdown content for review-summary.md
55
+ */
56
+ formatSessionSummary(results: Map<string, ReviewResult>): string;
57
+ /**
58
+ * Format the session-level tech debt backlog markdown.
59
+ * Aggregates all MEDIUM-severity issues across all stories, grouped by file path.
60
+ *
61
+ * @param results - Map of storyId → ReviewResult
62
+ * @returns Complete markdown content for tech-debt-backlog.md
63
+ */
64
+ formatTechDebtBacklog(results: Map<string, ReviewResult>): string;
65
+ /**
66
+ * Format an expanded per-story review file for the session review/ directory.
67
+ * More detailed than the appended story report — includes full issue details.
68
+ *
69
+ * @param storyId - Story identifier
70
+ * @param result - ReviewResult for the story
71
+ * @returns Complete markdown content for the per-story review file
72
+ */
73
+ formatStoryReviewFile(storyId: string, result: ReviewResult): string;
74
+ /**
75
+ * Group classified issues by severity.
76
+ */
77
+ private groupBySeverity;
78
+ /**
79
+ * Determine the action column text for a severity row in the findings summary table.
80
+ */
81
+ private determineSeverityAction;
82
+ /**
83
+ * Extract scanner list from a ReviewResult.
84
+ * Since ReviewResult doesn't carry scanner names directly, derive from issue sources
85
+ * or return a default.
86
+ */
87
+ private extractScannerList;
88
+ /**
89
+ * Extract the story number portion from a story ID.
90
+ * e.g., "PROJ-story-1.001" → "1.001"
91
+ * e.g., "BMAD-ENHANCED-AUTOMATED-CODE-REVIEW-story-3.006" → "3.006"
92
+ */
93
+ private extractStoryNum;
94
+ }