@hyperdrive.bot/bmad-workflow 1.0.16 → 1.0.18

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.
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Workflow Callbacks
3
+ *
4
+ * Interfaces for lifecycle event callbacks that consumers can register
5
+ * to observe workflow execution without coupling to orchestration internals.
6
+ *
7
+ * Callbacks are fire-and-forget (synchronous but non-blocking) and errors
8
+ * in callbacks do not interrupt workflow execution.
9
+ */
10
+ /**
11
+ * Context for phase lifecycle events
12
+ *
13
+ * Provided when a workflow phase (epic, story, dev, qa) starts or completes.
14
+ */
15
+ export interface PhaseContext {
16
+ /**
17
+ * Phase name: 'epic' | 'story' | 'dev' | 'qa'
18
+ */
19
+ phaseName: string;
20
+ /**
21
+ * Phase start timestamp (epoch ms)
22
+ */
23
+ startTime: number;
24
+ /**
25
+ * Phase end timestamp (epoch ms, only in onPhaseComplete)
26
+ */
27
+ endTime?: number;
28
+ /**
29
+ * Phase duration in milliseconds (only in onPhaseComplete)
30
+ */
31
+ duration?: number;
32
+ /**
33
+ * Total items to process in this phase
34
+ */
35
+ itemCount: number;
36
+ /**
37
+ * Number of successfully processed items (only in onPhaseComplete)
38
+ */
39
+ successCount?: number;
40
+ /**
41
+ * Number of failed items (only in onPhaseComplete)
42
+ */
43
+ failureCount?: number;
44
+ /**
45
+ * Whether the phase was skipped
46
+ */
47
+ skipped?: boolean;
48
+ /**
49
+ * Additional metadata specific to the phase
50
+ */
51
+ metadata?: Record<string, unknown>;
52
+ }
53
+ /**
54
+ * Context for layer/batch lifecycle events
55
+ *
56
+ * Provided when a batch of items starts or completes processing.
57
+ * Layers represent groups of items processed in parallel.
58
+ */
59
+ export interface LayerContext {
60
+ /**
61
+ * Phase this layer belongs to
62
+ */
63
+ phaseName: string;
64
+ /**
65
+ * Zero-based layer index within the phase
66
+ */
67
+ layerIndex: number;
68
+ /**
69
+ * Total number of layers in the phase
70
+ */
71
+ totalLayers: number;
72
+ /**
73
+ * Number of items (spawns) in this layer
74
+ */
75
+ spawnCount: number;
76
+ /**
77
+ * Whether items in this layer are processed in parallel
78
+ */
79
+ parallel: boolean;
80
+ /**
81
+ * Layer start timestamp (epoch ms)
82
+ */
83
+ startTime: number;
84
+ /**
85
+ * Layer end timestamp (epoch ms, only in onLayerComplete)
86
+ */
87
+ endTime?: number;
88
+ /**
89
+ * Layer duration in milliseconds (only in onLayerComplete)
90
+ */
91
+ duration?: number;
92
+ /**
93
+ * Number of successful spawns (only in onLayerComplete)
94
+ */
95
+ successCount?: number;
96
+ /**
97
+ * Number of failed spawns (only in onLayerComplete)
98
+ */
99
+ failureCount?: number;
100
+ }
101
+ /**
102
+ * Context for spawn (agent execution) lifecycle events
103
+ *
104
+ * Provided when an individual agent execution starts, completes, or produces output.
105
+ */
106
+ export interface SpawnContext {
107
+ /**
108
+ * Unique identifier for this spawn
109
+ */
110
+ spawnId: string;
111
+ /**
112
+ * Phase this spawn belongs to
113
+ */
114
+ phaseName: string;
115
+ /**
116
+ * Type of agent being spawned: 'architect' | 'sm' | 'dev' | 'qa'
117
+ */
118
+ agentType: string;
119
+ /**
120
+ * Item identifier (epic number, story number, etc.)
121
+ */
122
+ itemId: string;
123
+ /**
124
+ * Item title or description
125
+ */
126
+ itemTitle?: string;
127
+ /**
128
+ * Output file path (if applicable)
129
+ */
130
+ outputPath?: string;
131
+ /**
132
+ * The prompt sent to the agent
133
+ */
134
+ prompt?: string;
135
+ /**
136
+ * Spawn start timestamp (epoch ms)
137
+ */
138
+ startTime: number;
139
+ /**
140
+ * Spawn end timestamp (epoch ms, only in onSpawnComplete)
141
+ */
142
+ endTime?: number;
143
+ /**
144
+ * Spawn duration in milliseconds (only in onSpawnComplete)
145
+ */
146
+ duration?: number;
147
+ /**
148
+ * Whether the spawn succeeded (only in onSpawnComplete)
149
+ */
150
+ success?: boolean;
151
+ /**
152
+ * Agent output text (only in onSpawnComplete or onSpawnOutput)
153
+ */
154
+ output?: string;
155
+ /**
156
+ * Error message if spawn failed (only in onSpawnComplete)
157
+ */
158
+ error?: string;
159
+ /**
160
+ * Worker ID for pipelined execution
161
+ */
162
+ workerId?: number;
163
+ /**
164
+ * Additional metadata
165
+ */
166
+ metadata?: Record<string, unknown>;
167
+ }
168
+ /**
169
+ * Context for error events
170
+ *
171
+ * Provided when an error occurs during workflow execution.
172
+ */
173
+ export interface ErrorContext {
174
+ /**
175
+ * Error message
176
+ */
177
+ message: string;
178
+ /**
179
+ * Phase where the error occurred (if applicable)
180
+ */
181
+ phaseName?: string;
182
+ /**
183
+ * Spawn ID where the error occurred (if applicable)
184
+ */
185
+ spawnId?: string;
186
+ /**
187
+ * Item identifier related to the error (if applicable)
188
+ */
189
+ itemId?: string;
190
+ /**
191
+ * Error stack trace (if available)
192
+ */
193
+ stack?: string;
194
+ /**
195
+ * Original error object
196
+ */
197
+ error?: Error;
198
+ /**
199
+ * Timestamp when error occurred (epoch ms)
200
+ */
201
+ timestamp: number;
202
+ /**
203
+ * Whether the error is recoverable (workflow can continue)
204
+ */
205
+ recoverable: boolean;
206
+ /**
207
+ * Additional context about the error
208
+ */
209
+ metadata?: Record<string, unknown>;
210
+ }
211
+ /**
212
+ * Workflow lifecycle callbacks
213
+ *
214
+ * Optional callback functions that consumers can register to observe
215
+ * workflow execution events. All callbacks are wrapped in try-catch
216
+ * to prevent errors from interrupting workflow execution.
217
+ */
218
+ export interface WorkflowCallbacks {
219
+ /**
220
+ * Called when a phase starts execution
221
+ */
222
+ onPhaseStart?: (context: PhaseContext) => void;
223
+ /**
224
+ * Called when a phase completes execution
225
+ */
226
+ onPhaseComplete?: (context: PhaseContext) => void;
227
+ /**
228
+ * Called when a batch/layer starts processing
229
+ */
230
+ onLayerStart?: (context: LayerContext) => void;
231
+ /**
232
+ * Called when a batch/layer completes processing
233
+ */
234
+ onLayerComplete?: (context: LayerContext) => void;
235
+ /**
236
+ * Called when an agent spawn starts
237
+ */
238
+ onSpawnStart?: (context: SpawnContext) => void;
239
+ /**
240
+ * Called when an agent spawn completes
241
+ */
242
+ onSpawnComplete?: (context: SpawnContext) => void;
243
+ /**
244
+ * Called when an agent produces streaming output
245
+ */
246
+ onSpawnOutput?: (context: SpawnContext, output: string) => void;
247
+ /**
248
+ * Called when an error occurs
249
+ */
250
+ onError?: (context: ErrorContext) => void;
251
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Workflow Callbacks
3
+ *
4
+ * Interfaces for lifecycle event callbacks that consumers can register
5
+ * to observe workflow execution without coupling to orchestration internals.
6
+ *
7
+ * Callbacks are fire-and-forget (synchronous but non-blocking) and errors
8
+ * in callbacks do not interrupt workflow execution.
9
+ */
10
+ export {};
@@ -0,0 +1,165 @@
1
+ /**
2
+ * WorkflowReporter
3
+ *
4
+ * Real-time progress visualization for multi-layer parallel workflow execution
5
+ * using listr2. Implements the WorkflowCallbacks interface to observe workflow
6
+ * lifecycle events without coupling to orchestration internals.
7
+ *
8
+ * Features:
9
+ * - Top-level phase task groups with emoji-annotated titles
10
+ * - Nested concurrent task groups for parallel spawn layers
11
+ * - Live status updates for spawn transitions (queued → running → completed/failed)
12
+ * - Collapsible layer summaries on completion
13
+ */
14
+ import type { WorkflowCallbacks } from '../models/workflow-callbacks.js';
15
+ /**
16
+ * Configuration options for WorkflowReporter
17
+ */
18
+ export interface WorkflowReporterOptions {
19
+ /**
20
+ * Maximum terminal width for output formatting (default: 80)
21
+ */
22
+ maxWidth?: number;
23
+ /**
24
+ * Disable color output
25
+ */
26
+ noColor?: boolean;
27
+ /**
28
+ * Force non-TTY mode (use simple renderer)
29
+ * When true or when process.stdout.isTTY is false, disables spinners
30
+ * and uses plain-text output without ANSI escape codes
31
+ */
32
+ nonTTY?: boolean;
33
+ /**
34
+ * Enable verbose output mode (show spawn output inline in real-time)
35
+ * When enabled, spawn outputs are streamed with visual delimiters
36
+ */
37
+ verbose?: boolean;
38
+ }
39
+ /**
40
+ * Summary data for the final dashboard display
41
+ */
42
+ export interface DashboardSummary {
43
+ /** Number of failed spawns */
44
+ failedCount: number;
45
+ /** Number of successful spawns */
46
+ passedCount: number;
47
+ /** Per-phase breakdown */
48
+ phases: Array<{
49
+ duration: number;
50
+ failed: number;
51
+ name: string;
52
+ passed: number;
53
+ }>;
54
+ /** Absolute path to the session report file */
55
+ sessionReportPath?: string;
56
+ /** Total duration in milliseconds */
57
+ totalDuration: number;
58
+ /** Total number of spawns across all phases */
59
+ totalSpawns: number;
60
+ }
61
+ /**
62
+ * WorkflowReporter provides real-time structured progress visualization
63
+ * of multi-layer parallel execution using listr2.
64
+ *
65
+ * Usage:
66
+ * ```typescript
67
+ * const reporter = new WorkflowReporter({ verbose: false })
68
+ * orchestrator.setCallbacks(reporter.getCallbacks())
69
+ * // ... workflow execution ...
70
+ * reporter.dispose()
71
+ * ```
72
+ */
73
+ export declare class WorkflowReporter {
74
+ private currentPhaseIndex;
75
+ private currentPhaseName;
76
+ private disposed;
77
+ private readonly options;
78
+ private phaseOrder;
79
+ private phases;
80
+ private listrInstance;
81
+ private listrPromise;
82
+ private phaseTransitionChain;
83
+ private phaseTaskResolver;
84
+ private phaseTaskOutput;
85
+ private phaseTaskTitle;
86
+ private currentTaskPhase;
87
+ private pendingTitle;
88
+ private pendingOutput;
89
+ private tickerInterval;
90
+ private tickerFrame;
91
+ private static readonly SPINNER_FRAMES;
92
+ constructor(options?: WorkflowReporterOptions);
93
+ /**
94
+ * Display final boxed dashboard with workflow summary (AC: #4)
95
+ */
96
+ displayFinalDashboard(summary: DashboardSummary): void;
97
+ /**
98
+ * Dispose of resources and clean up listr2 instance
99
+ */
100
+ dispose(): void;
101
+ /**
102
+ * Get the workflow callbacks interface for registering with orchestrator
103
+ */
104
+ getCallbacks(): WorkflowCallbacks;
105
+ /**
106
+ * Get the configured max width for output formatting
107
+ */
108
+ getMaxWidth(): number;
109
+ /**
110
+ * Check if reporter has been disposed
111
+ */
112
+ isDisposed(): boolean;
113
+ /**
114
+ * Check if reporter is in TTY mode
115
+ */
116
+ isTTYMode(): boolean;
117
+ /**
118
+ * Check if reporter is in verbose mode
119
+ */
120
+ isVerboseMode(): boolean;
121
+ /**
122
+ * Wait for all listr2 tasks to complete (called after orchestrator finishes)
123
+ */
124
+ waitForCompletion(): Promise<void>;
125
+ /**
126
+ * Clean up the current listr2 instance — resolve pending tasks and wait for
127
+ * the renderer to finish so the next phase gets a clean terminal.
128
+ */
129
+ private cleanupCurrentListr;
130
+ /**
131
+ * Create a new listr2 instance for a phase. The phase gets a single top-level
132
+ * task with a spinner. Spawn progress is piped as task output (shown below the
133
+ * spinner line). The task resolves when handlePhaseComplete fires.
134
+ *
135
+ * Phase transitions are chained: old instance is fully cleaned up before the
136
+ * new one starts rendering, preventing two renderers fighting over stdout.
137
+ */
138
+ private createPhaseListr;
139
+ /**
140
+ * Display a phase banner. In verbose mode, shows a full formatBox banner.
141
+ * In non-verbose TTY mode, the listr2 spinner is the only display (no banner).
142
+ * In non-TTY mode, shows a plain-text header.
143
+ */
144
+ private displayPhaseBanner;
145
+ private displayPlainTextDashboard;
146
+ private displayRichDashboard;
147
+ private handlePhaseStart;
148
+ private handlePhaseComplete;
149
+ private handleLayerStart;
150
+ private handleLayerComplete;
151
+ private handleSpawnStart;
152
+ /**
153
+ * Live-tick the phase title — rotates through running spawns with elapsed time.
154
+ * Called every 2s by the ticker interval AND once immediately on spawn start.
155
+ */
156
+ private stopTicker;
157
+ /**
158
+ * Build and render all spawn lines with per-item spinners + elapsed time.
159
+ * Called every second by the ticker interval AND once on spawn start/complete.
160
+ */
161
+ private tickSpawns;
162
+ private handleSpawnComplete;
163
+ private handleSpawnOutput;
164
+ private handleError;
165
+ }