@auto-engineer/pipeline 1.147.0 → 1.149.0

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @auto-engineer/pipeline@1.147.0 build /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
2
+ > @auto-engineer/pipeline@1.149.0 build /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
3
3
  > tsc && tsx ../../scripts/fix-esm-imports.ts
4
4
 
5
5
  Fixed ESM imports in dist/
@@ -1,5 +1,5 @@
1
1
 
2
- > @auto-engineer/pipeline@1.146.0 test /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
2
+ > @auto-engineer/pipeline@1.148.0 test /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
3
3
  > vitest run --reporter=dot
4
4
 
5
5
 
@@ -9,6 +9,6 @@
9
9
 
10
10
   Test Files  42 passed (42)
11
11
   Tests  591 passed (591)
12
-  Start at  19:11:56
13
-  Duration  46.27s (transform 9.57s, setup 0ms, collect 20.85s, tests 37.29s, environment 25ms, prepare 30.72s)
12
+  Start at  07:22:54
13
+  Duration  42.16s (transform 8.34s, setup 0ms, collect 17.10s, tests 33.88s, environment 14ms, prepare 29.63s)
14
14
 
@@ -1,4 +1,4 @@
1
1
 
2
- > @auto-engineer/pipeline@1.146.0 type-check /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
2
+ > @auto-engineer/pipeline@1.148.0 type-check /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
3
3
  > tsc --noEmit
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # @auto-engineer/pipeline
2
2
 
3
+ ## 1.149.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`e1eebbd`](https://github.com/BeOnAuto/auto-engineer/commit/e1eebbdf4f209780e790094d2e6887c4fa809f98) Thanks [@github-actions[bot]](https://github.com/github-actions%5Bbot%5D)! - - **server-generator-apollo-emmett**: add Given state ref hints to state.ts.ejs
8
+ - **server-generator-apollo-emmett**: context-aware nonCommandField instructions
9
+ - **server-generator-apollo-emmett**: add state context instruction
10
+ - **server-generator-apollo-emmett**: extract shared template helpers
11
+ - **server-generator-apollo-emmett**: filter state refs from hasGivenEvents in decide.ts.ejs
12
+
13
+ ### Patch Changes
14
+
15
+ - [`d38c81e`](https://github.com/BeOnAuto/auto-engineer/commit/d38c81e7bb442a39626564cf4f6d8d55b60d0a38) Thanks [@SamHatoum](https://github.com/SamHatoum)! -
16
+
17
+ - Updated dependencies [[`d38c81e`](https://github.com/BeOnAuto/auto-engineer/commit/d38c81e7bb442a39626564cf4f6d8d55b60d0a38), [`e1eebbd`](https://github.com/BeOnAuto/auto-engineer/commit/e1eebbdf4f209780e790094d2e6887c4fa809f98)]:
18
+ - @auto-engineer/file-store@1.149.0
19
+ - @auto-engineer/message-bus@1.149.0
20
+
21
+ ## 1.148.0
22
+
23
+ ### Minor Changes
24
+
25
+ - [`d5ba3a0`](https://github.com/BeOnAuto/auto-engineer/commit/d5ba3a0e3fb0f6a9ad7a3a8b1815590ea77a5b42) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Added state context instruction to generated decide handlers, preventing unnecessary narrowing when Given steps contain only state references
26
+
27
+ - [`e0cdc4e`](https://github.com/BeOnAuto/auto-engineer/commit/e0cdc4e3363ad84d4bc49996a600ac75c97ccc38) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Added context-aware classification of non-command fields in generated decide.ts scaffolds, distinguishing between date-derived, state-derived, and not-yet-tested fields
28
+
29
+ - [`9195db7`](https://github.com/BeOnAuto/auto-engineer/commit/9195db78cb707d658866cee99a1c73d34fb4efde) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Extracted shared template helpers into a dedicated module for cleaner code generation
30
+
31
+ - [`abb6540`](https://github.com/BeOnAuto/auto-engineer/commit/abb6540db7196ed7935c8a8610695828f9035fc3) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Added status variant hints from Given state references to the state template, helping implementers create matching discriminated union variants
32
+
33
+ - [`9195db7`](https://github.com/BeOnAuto/auto-engineer/commit/9195db78cb707d658866cee99a1c73d34fb4efde) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Extracted shared template helper functions into a dedicated module for better code reuse across generators
34
+ - Simplified template specs by removing inline duplicate definitions in favor of the shared helpers
35
+
36
+ ### Patch Changes
37
+
38
+ - [`88fb1da`](https://github.com/BeOnAuto/auto-engineer/commit/88fb1da2b222de04dd4959d87657395ee960a6ce) Thanks [@github-actions[bot]](https://github.com/github-actions%5Bbot%5D)! - - **server-generator-apollo-emmett**: skip empty file plans in scaffold output
39
+ - **server-generator-apollo-emmett**: filter state refs from given() in decide.specs.ts.ejs
40
+ - **server-generator-apollo-emmett**: move CS Given states from events to states array
41
+ - **global**: version packages
42
+ - **server-generator-apollo-emmett**: mark G1+G2 ketchup plan complete
43
+
44
+ - [`4255f6d`](https://github.com/BeOnAuto/auto-engineer/commit/4255f6db0d128979e573244a615886482ce799b0) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Updated ketchup plan for state reference fix in decide template generator
45
+ - Marked generator bug fix milestones G1 and G2 as complete
46
+
47
+ - [`62f1ea3`](https://github.com/BeOnAuto/auto-engineer/commit/62f1ea3dd1b4275211574e3df9d9a6571ae9b27a) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Fixed scaffold generation to correctly distinguish between event and state references in decision handlers
48
+ - Prevented contradictory instructions from appearing in generated code when Given clauses contain only state references
49
+
50
+ - [`ba4f5c9`](https://github.com/BeOnAuto/auto-engineer/commit/ba4f5c9749fb1c15d444e78ca9a2689817f039cb) Thanks [@rami-hatoum](https://github.com/rami-hatoum)! - - Added implementation plan for decide.ts code generation fixes in the Apollo Emmett server generator
51
+
52
+ - Updated dependencies [[`88fb1da`](https://github.com/BeOnAuto/auto-engineer/commit/88fb1da2b222de04dd4959d87657395ee960a6ce), [`d5ba3a0`](https://github.com/BeOnAuto/auto-engineer/commit/d5ba3a0e3fb0f6a9ad7a3a8b1815590ea77a5b42), [`e0cdc4e`](https://github.com/BeOnAuto/auto-engineer/commit/e0cdc4e3363ad84d4bc49996a600ac75c97ccc38), [`4255f6d`](https://github.com/BeOnAuto/auto-engineer/commit/4255f6db0d128979e573244a615886482ce799b0), [`9195db7`](https://github.com/BeOnAuto/auto-engineer/commit/9195db78cb707d658866cee99a1c73d34fb4efde), [`abb6540`](https://github.com/BeOnAuto/auto-engineer/commit/abb6540db7196ed7935c8a8610695828f9035fc3), [`9195db7`](https://github.com/BeOnAuto/auto-engineer/commit/9195db78cb707d658866cee99a1c73d34fb4efde), [`62f1ea3`](https://github.com/BeOnAuto/auto-engineer/commit/62f1ea3dd1b4275211574e3df9d9a6571ae9b27a), [`ba4f5c9`](https://github.com/BeOnAuto/auto-engineer/commit/ba4f5c9749fb1c15d444e78ca9a2689817f039cb)]:
53
+ - @auto-engineer/file-store@1.148.0
54
+ - @auto-engineer/message-bus@1.148.0
55
+
3
56
  ## 1.147.0
4
57
 
5
58
  ### Minor Changes
package/README.md CHANGED
@@ -1,14 +1,24 @@
1
1
  # @auto-engineer/pipeline
2
2
 
3
- Event-driven SDLC pipeline orchestration system with declarative workflow definitions.
3
+ Event-sourced pipeline orchestration with declarative workflow definitions, reactive event handling, and real-time SSE monitoring.
4
4
 
5
5
  ---
6
6
 
7
7
  ## Purpose
8
8
 
9
- Without `@auto-engineer/pipeline`, you would have to manually wire event handlers, coordinate phased execution, track command completion across correlations, and implement your own SSE streaming for real-time monitoring.
9
+ Without `@auto-engineer/pipeline`, you would have to manually wire event-to-command mappings, coordinate phased execution across ordered groups, track scatter-gather completion for parallel commands, implement settled-handler logic for fan-in aggregation, and build your own SSE streaming layer for real-time pipeline visibility.
10
10
 
11
- This package provides the core infrastructure for building event-sourced pipelines. It enables declarative workflow definitions using a fluent builder API, reactive event handling, phased execution, settled handlers, and real-time monitoring via SSE.
11
+ ---
12
+
13
+ ## Key Concepts
14
+
15
+ - **Event** -- An immutable fact that has occurred (e.g. `CodeAnalyzed`, `DeploySucceeded`).
16
+ - **Command** -- An intention to perform an action (e.g. `AnalyzeCode`, `Deploy`).
17
+ - **Handler Descriptor** -- A declarative rule that maps events to commands. Five types exist: `emit`, `custom`, `run-await`, `foreach-phased`, and `settled`.
18
+ - **Pipeline** -- A named collection of handler descriptors plus a `toGraph()` method that produces a `GraphIR` for visualization.
19
+ - **PipelineRuntime** -- Indexes handler descriptors by event type and executes matching handlers when events arrive.
20
+ - **PipelineServer** -- An Express HTTP server that wires everything together: command dispatch, event routing, settled/phased bridges, SSE broadcast, and an in-memory event store with projections.
21
+ - **GraphIR** -- An intermediate representation of the pipeline as typed nodes (`event`, `command`, `settled`, `phased`, `await`) and edges, used for Mermaid rendering and UI visualization.
12
22
 
13
23
  ---
14
24
 
@@ -18,12 +28,14 @@ This package provides the core infrastructure for building event-sourced pipelin
18
28
  pnpm add @auto-engineer/pipeline
19
29
  ```
20
30
 
31
+ ---
32
+
21
33
  ## Quick Start
22
34
 
23
35
  ```typescript
24
36
  import { define, PipelineServer } from '@auto-engineer/pipeline';
25
37
 
26
- const pipeline = define('SDLC')
38
+ const pipeline = define('my-sdlc')
27
39
  .on('CodePushed')
28
40
  .emit('AnalyzeCode', (e) => ({ filePath: e.data.path }))
29
41
 
@@ -36,34 +48,25 @@ const server = new PipelineServer({ port: 3000 });
36
48
  server.registerPipeline(pipeline);
37
49
 
38
50
  await server.start();
39
- console.log(`Server running at http://localhost:${server.port}`);
51
+ console.log(`Pipeline server running on port ${server.port}`);
40
52
  ```
41
53
 
42
54
  ---
43
55
 
44
- ## Key Concepts
45
-
46
- - **Events**: Immutable facts that have occurred
47
- - **Commands**: Intentions to perform actions
48
- - **Handlers**: React to events by dispatching commands
49
- - **Pipelines**: Declarative workflows connecting events to commands
50
-
51
- ---
52
-
53
56
  ## How-to Guides
54
57
 
55
- ### Define a Simple Pipeline
58
+ ### Define a pipeline with emit handlers
56
59
 
57
60
  ```typescript
58
61
  import { define } from '@auto-engineer/pipeline';
59
62
 
60
- const pipeline = define('my-pipeline')
63
+ const pipeline = define('simple')
61
64
  .on('TriggerEvent')
62
- .emit('OutputCommand', { data: 'value' })
65
+ .emit('DoWork', { key: 'value' })
63
66
  .build();
64
67
  ```
65
68
 
66
- ### Use Conditional Handlers
69
+ ### Use conditional predicates
67
70
 
68
71
  ```typescript
69
72
  const pipeline = define('conditional')
@@ -73,21 +76,42 @@ const pipeline = define('conditional')
73
76
  .build();
74
77
  ```
75
78
 
76
- ### Use Custom Handlers
79
+ ### Use custom handlers
77
80
 
78
81
  ```typescript
79
82
  const pipeline = define('custom')
80
83
  .on('SpecialEvent')
81
84
  .handle(async (event, ctx) => {
82
- await ctx.emit('NotifyUser', { message: 'Processing complete' });
83
- })
85
+ await ctx.emit('ProcessingDone', { result: event.data.value });
86
+ }, { emits: ['ProcessingDone'] })
84
87
  .build();
85
88
  ```
86
89
 
87
- ### Use Phased Execution
90
+ ### Run commands and await completion
88
91
 
89
92
  ```typescript
90
- const pipeline = define('builder')
93
+ import { dispatch } from '@auto-engineer/pipeline';
94
+
95
+ const pipeline = define('scatter-gather')
96
+ .on('FilesDiscovered')
97
+ .run((e) => e.data.files.map((f) => dispatch('ProcessFile', { path: f })))
98
+ .awaitAll('ProcessFile', (e) => e.data.path)
99
+ .onSuccess('AllFilesProcessed', (ctx) => ({
100
+ count: ctx.results.length,
101
+ duration: ctx.duration,
102
+ }))
103
+ .onFailure('FileProcessingFailed', (ctx) => ({
104
+ failures: ctx.failures,
105
+ }))
106
+ .build();
107
+ ```
108
+
109
+ ### Use phased execution
110
+
111
+ Process items in ordered groups where each phase completes before the next begins.
112
+
113
+ ```typescript
114
+ const pipeline = define('phased')
91
115
  .on('ComponentsReady')
92
116
  .forEach((e) => e.data.components)
93
117
  .groupInto(['critical', 'normal'], (c) => c.priority)
@@ -101,7 +125,9 @@ const pipeline = define('builder')
101
125
  .build();
102
126
  ```
103
127
 
104
- ### Use Settled Handlers
128
+ ### Use settled handlers
129
+
130
+ Fire logic when all specified commands have completed.
105
131
 
106
132
  ```typescript
107
133
  const pipeline = define('aggregator')
@@ -112,22 +138,55 @@ const pipeline = define('aggregator')
112
138
  .build();
113
139
  ```
114
140
 
115
- ### Start the Pipeline Server
141
+ ### Register command handlers and start the server
116
142
 
117
143
  ```typescript
118
144
  import { PipelineServer } from '@auto-engineer/pipeline';
145
+ import type { CommandHandlerWithMetadata } from '@auto-engineer/pipeline';
146
+
147
+ const handlers: CommandHandlerWithMetadata[] = [
148
+ {
149
+ name: 'AnalyzeCode',
150
+ events: ['CodeAnalyzed'],
151
+ handle: async (cmd) => ({
152
+ type: 'CodeAnalyzed',
153
+ data: { path: cmd.data.filePath, issues: [] },
154
+ }),
155
+ },
156
+ ];
119
157
 
120
158
  const server = new PipelineServer({ port: 3000 });
121
- server.registerCommandHandlers([handler1, handler2]);
159
+ server.registerCommandHandlers(handlers);
122
160
  server.registerPipeline(pipeline);
123
-
124
161
  await server.start();
125
162
  ```
126
163
 
127
- ### Consume SSE Events
164
+ ### Configure concurrency control
165
+
166
+ ```typescript
167
+ server.registerConcurrency('ProcessFile', {
168
+ strategy: 'cancel-in-progress', // or 'queue'
169
+ groupKey: (data) => data.path,
170
+ });
171
+ ```
172
+
173
+ ### Load plugins from packages
128
174
 
129
175
  ```typescript
130
- const url = new URL('/events', 'http://localhost:5555');
176
+ import { pipelineConfig, loadPipelineConfig } from '@auto-engineer/pipeline';
177
+
178
+ const config = pipelineConfig({
179
+ plugins: ['@auto-engineer/code-analyzer', '@auto-engineer/deployer'],
180
+ pipeline: myPipeline,
181
+ });
182
+
183
+ const { handlers, pipeline } = await loadPipelineConfig(config);
184
+ ```
185
+
186
+ ### Consume SSE events
187
+
188
+ ```typescript
189
+ const url = new URL('/events', 'http://localhost:3000');
131
190
  url.searchParams.set('correlationId', 'corr-123'); // optional filter
132
191
 
133
192
  const eventSource = new EventSource(url.toString());
@@ -137,22 +196,17 @@ eventSource.onmessage = (msg) => {
137
196
  };
138
197
  ```
139
198
 
140
- ### Handle SSE Reconnection
199
+ ### Use the v2 builder API
141
200
 
142
201
  ```typescript
143
- function connectWithRetry(url: string, maxRetries = 5) {
144
- let retries = 0;
145
- function connect() {
146
- const es = new EventSource(url);
147
- es.onopen = () => { retries = 0; };
148
- es.onerror = () => {
149
- es.close();
150
- if (retries++ < maxRetries) setTimeout(connect, 3000);
151
- };
152
- return es;
153
- }
154
- return connect();
155
- }
202
+ import { defineV2, toGraphV2 } from '@auto-engineer/pipeline';
203
+
204
+ const pipeline = defineV2('my-pipeline')
205
+ .on('Start')
206
+ .emit('DoWork', { key: 'value' })
207
+ .build();
208
+
209
+ const graph = toGraphV2(pipeline);
156
210
  ```
157
211
 
158
212
  ---
@@ -162,78 +216,184 @@ function connectWithRetry(url: string, maxRetries = 5) {
162
216
  ### Package Exports
163
217
 
164
218
  ```typescript
165
- import {
166
- define,
167
- dispatch,
168
- PipelineRuntime,
169
- PipelineServer,
170
- PhasedExecutor,
171
- SettledTracker,
172
- AwaitTracker,
173
- EventCommandMapper,
174
- SSEManager,
175
- EventLogger,
176
- } from '@auto-engineer/pipeline';
177
-
178
- import type {
179
- Pipeline,
180
- PipelineBuilder,
181
- Command,
182
- Event,
183
- CommandDispatch,
184
- PipelineDescriptor,
185
- HandlerDescriptor,
186
- GraphIR,
187
- GraphNode,
188
- GraphEdge,
189
- CommandHandlerWithMetadata,
190
- } from '@auto-engineer/pipeline';
219
+ // Builder
220
+ export { define } from './builder/define';
221
+ export { defineV2, toGraphV2 } from './builder/define-v2';
222
+
223
+ // Core helpers
224
+ export { dispatch } from './core/types';
225
+
226
+ // Runtime
227
+ export { PipelineRuntime } from './runtime/pipeline-runtime';
228
+ export { EventCommandMapper } from './runtime/event-command-map';
229
+ export { AwaitTracker } from './runtime/await-tracker';
230
+
231
+ // Server
232
+ export { PipelineServer } from './server/pipeline-server';
233
+ export { SSEManager } from './server/sse-manager';
234
+
235
+ // Logging
236
+ export { EventLogger } from './logging/event-logger';
237
+
238
+ // Engine (v2)
239
+ export { createPipelineEngine } from './engine/pipeline-engine';
240
+ export { createCommandDispatcher, dispatchAndStore } from './engine/command-dispatcher';
241
+ export { createEventRouter } from './engine/event-router';
242
+ export { createWorkflowProcessor } from './engine/workflow-processor';
243
+ export { createPipelineStore } from './engine/sqlite-store';
244
+ export { createConsumer } from './engine/sqlite-consumer';
245
+ export { createAwaitWorkflow } from './engine/workflows/await-workflow';
246
+ export { createPhasedWorkflow } from './engine/workflows/phased-workflow';
247
+ export { createSettledWorkflow } from './engine/workflows/settled-workflow';
248
+
249
+ // Engine projections
250
+ export { itemStatusProjection } from './engine/projections/item-status';
251
+ export { latestRunProjection } from './engine/projections/latest-run';
252
+ export { messageLogProjection } from './engine/projections/message-log';
253
+ export { nodeStatusProjection } from './engine/projections/node-status';
254
+ export { statsProjection } from './engine/projections/stats';
255
+
256
+ // Store
257
+ export { createPipelineEventStore } from './store/pipeline-event-store';
258
+ export { PipelineReadModel } from './store/pipeline-read-model';
259
+
260
+ // Testing utilities
261
+ export {
262
+ compareEventSequence,
263
+ containsSubsequence,
264
+ findMissingEvents,
265
+ findUnexpectedEvents,
266
+ formatSnapshotDiff,
267
+ } from './testing/snapshot-compare';
268
+ ```
269
+
270
+ ### Key Types
271
+
272
+ ```typescript
273
+ interface Pipeline {
274
+ descriptor: Readonly<PipelineDescriptor>;
275
+ toGraph(): GraphIR;
276
+ }
277
+
278
+ interface PipelineDescriptor {
279
+ name: string;
280
+ version?: string;
281
+ description?: string;
282
+ keys: Map<string, KeyExtractor>;
283
+ handlers: HandlerDescriptor[];
284
+ }
285
+
286
+ type HandlerDescriptor =
287
+ | EmitHandlerDescriptor
288
+ | RunAwaitHandlerDescriptor
289
+ | ForEachPhasedDescriptor
290
+ | CustomHandlerDescriptor
291
+ | SettledHandlerDescriptor
292
+ | AcceptsDescriptor;
293
+
294
+ interface CommandDispatch<D = Record<string, unknown>> {
295
+ commandType: string;
296
+ data: D | ((event: Event) => D);
297
+ }
298
+
299
+ interface PipelineServerConfig {
300
+ port: number;
301
+ storeFileName?: string; // SQLite file for persistent event storage
302
+ }
303
+
304
+ interface CommandHandlerWithMetadata {
305
+ name: string;
306
+ alias?: string;
307
+ description?: string;
308
+ displayName?: string;
309
+ fields?: Record<string, unknown>;
310
+ examples?: unknown[];
311
+ events?: EventDefinition[];
312
+ handle: (command: Command, context?: PipelineContext) => Promise<Event | Event[]>;
313
+ }
314
+
315
+ interface PipelineContext {
316
+ emit: (type: string, data: unknown) => Promise<void>;
317
+ sendCommand: (type: string, data: unknown, correlationId?: string) => Promise<void>;
318
+ correlationId: string;
319
+ signal?: AbortSignal;
320
+ }
321
+
322
+ interface ConcurrencyConfig {
323
+ strategy: 'cancel-in-progress' | 'queue';
324
+ groupKey?: (data: unknown) => string;
325
+ }
326
+
327
+ interface GraphIR {
328
+ nodes: GraphNode[];
329
+ edges: GraphEdge[];
330
+ }
331
+
332
+ interface GraphNode {
333
+ id: string;
334
+ type: 'event' | 'command' | 'settled' | 'phased' | 'await';
335
+ label: string;
336
+ status?: 'idle' | 'running' | 'success' | 'error';
337
+ }
191
338
  ```
192
339
 
193
- ### Functions
340
+ ### `define(name: string): PipelineBuilder`
341
+
342
+ Entry point for the fluent builder API. Chain `.on()`, `.emit()`, `.run()`, `.forEach()`, `.settled()`, `.handle()`, and `.build()`.
194
343
 
195
- #### `define(name: string): PipelineBuilder`
344
+ ### `defineV2(name: string): PipelineV2Builder`
196
345
 
197
- Entry point for creating pipeline definitions.
346
+ Alternative builder that produces a `PipelineV2` with flat registration arrays. Convert to graph with `toGraphV2()`.
198
347
 
199
- #### `dispatch(commandType: string, data: unknown): CommandDispatch`
348
+ ### `dispatch(commandType: string, data: DataOrFactory): CommandDispatch`
200
349
 
201
- Helper to create command dispatch objects.
350
+ Helper to create `CommandDispatch` objects for use with `.run()`.
202
351
 
203
352
  ### PipelineServer
204
353
 
205
354
  ```typescript
206
355
  class PipelineServer {
207
- constructor(config: { port: number });
356
+ constructor(config: PipelineServerConfig);
208
357
  registerCommandHandlers(handlers: CommandHandlerWithMetadata[]): void;
209
358
  registerPipeline(pipeline: Pipeline): void;
359
+ registerConcurrency(commandType: string, config: ConcurrencyConfig): void;
360
+ registerItemKeyExtractor(commandType: string, extractor: (data: unknown) => string | undefined): void;
361
+ use(handler: express.RequestHandler): this;
210
362
  start(): Promise<void>;
211
363
  stop(): Promise<void>;
212
364
  readonly port: number;
365
+ getHttpServer(): HttpServer;
366
+ getMessageBus(): MessageBus;
367
+ getRegisteredCommands(): string[];
368
+ getPipelineNames(): string[];
213
369
  }
214
370
  ```
215
371
 
216
372
  ### Server Endpoints
217
373
 
218
374
  | Endpoint | Method | Description |
219
- |----------|--------|-------------|
220
- | `/health` | GET | Health check |
221
- | `/registry` | GET | List handlers |
222
- | `/pipeline` | GET | Pipeline graph |
223
- | `/pipeline/mermaid` | GET | Mermaid diagram |
224
- | `/pipeline/diagram` | GET | HTML diagram |
225
- | `/command` | POST | Dispatch command |
226
- | `/events` | GET | SSE stream |
227
-
228
- ### Handler Types
229
-
230
- | Type | Description |
231
- |------|-------------|
232
- | `emit` | Dispatch commands when events occur |
233
- | `custom` | Execute arbitrary async logic |
234
- | `run-await` | Dispatch and await completion |
235
- | `foreach-phased` | Process items in ordered phases |
236
- | `settled` | Fire when multiple commands complete |
375
+ |---|---|---|
376
+ | `/health` | GET | Health check with uptime |
377
+ | `/registry` | GET | List registered event and command handlers |
378
+ | `/pipeline` | GET | Pipeline graph with live node status |
379
+ | `/pipeline/mermaid` | GET | Mermaid diagram as plain text |
380
+ | `/pipeline/diagram` | GET | Self-contained HTML page with rendered diagram |
381
+ | `/command` | POST | Dispatch a command (returns `ack` with `correlationId`) |
382
+ | `/execute` | POST | Dispatch and wait for synchronous result |
383
+ | `/events` | GET | SSE stream (optional `?correlationId=` filter) |
384
+ | `/messages` | GET | Full message log |
385
+ | `/stats` | GET | Aggregate message statistics |
386
+ | `/run-stats` | GET | Per-run item/node statistics |
387
+
388
+ ### Testing Utilities
389
+
390
+ ```typescript
391
+ function compareEventSequence(expected: string[], actual: string[]): SnapshotResult;
392
+ function containsSubsequence(sequence: string[], subsequence: string[]): boolean;
393
+ function findMissingEvents(sequence: string[], required: string[]): string[];
394
+ function findUnexpectedEvents(sequence: string[], allowed: string[]): string[];
395
+ function formatSnapshotDiff(result: SnapshotResult): string;
396
+ ```
237
397
 
238
398
  ---
239
399
 
@@ -241,39 +401,108 @@ class PipelineServer {
241
401
 
242
402
  ```
243
403
  src/
244
- ├── builder/
245
- ├── core/
246
- ├── graph/
247
- ├── logging/
248
- ├── plugins/
249
- ├── projections/
250
- ├── runtime/
251
- ├── server/
252
- ├── store/
253
- └── testing/
404
+ ├── builder/ # define() and defineV2() fluent builder APIs
405
+ ├── define.ts # Primary builder with graph extraction
406
+ │ └── define-v2.ts # Simplified v2 builder
407
+ ├── config/ # Pipeline configuration and plugin loading
408
+ │ └── pipeline-config.ts
409
+ ├── core/ # Shared types and descriptor definitions
410
+ ├── descriptors.ts # Handler descriptor types
411
+ │ └── types.ts # Event, Command, CommandDispatch
412
+ ├── engine/ # v2 engine: dispatcher, router, workflows, SQLite store
413
+ │ ├── command-dispatcher.ts
414
+ │ ├── event-router.ts
415
+ │ ├── pipeline-engine.ts
416
+ │ ├── sqlite-consumer.ts
417
+ │ ├── sqlite-store.ts
418
+ │ ├── workflow-processor.ts
419
+ │ ├── projections/ # Event-driven projections (item, node, run, stats)
420
+ │ └── workflows/ # Await, phased, and settled workflow implementations
421
+ ├── graph/ # GraphIR types and filtering
422
+ │ ├── types.ts
423
+ │ └── filter-graph.ts
424
+ ├── logging/ # EventLogger for recording pipeline activity
425
+ ├── plugins/ # Dynamic plugin loading and handler adaptation
426
+ │ ├── plugin-loader.ts
427
+ │ └── handler-adapter.ts
428
+ ├── projections/ # In-memory event store projections
429
+ │ ├── await-tracker-projection.ts
430
+ │ ├── item-status-projection.ts
431
+ │ ├── latest-run-projection.ts
432
+ │ ├── message-log-projection.ts
433
+ │ ├── node-status-projection.ts
434
+ │ └── stats-projection.ts
435
+ ├── runtime/ # PipelineRuntime, AwaitTracker, EventCommandMapper
436
+ ├── server/ # PipelineServer, SSE, command gate, quiescence tracking
437
+ │ ├── pipeline-server.ts
438
+ │ ├── pipeline-server-v2.ts
439
+ │ ├── sse-manager.ts
440
+ │ ├── command-gate.ts
441
+ │ ├── quiescence-tracker.ts
442
+ │ ├── phased-bridge.ts
443
+ │ └── v2-runtime-bridge.ts
444
+ ├── store/ # In-memory event store with Emmett projections
445
+ │ ├── pipeline-event-store.ts
446
+ │ └── pipeline-read-model.ts
447
+ └── testing/ # Test helpers: mock handlers, event capture, snapshots
448
+ ├── event-capture.ts
449
+ ├── mock-handlers.ts
450
+ ├── snapshot-compare.ts
451
+ └── snapshot-sanitize.ts
254
452
  ```
255
453
 
256
- The following diagram shows the execution flow:
257
-
258
454
  ```mermaid
259
455
  flowchart TB
260
- A[Event Received] --> B[Handler Matching]
261
- B --> C[Handler Execution]
262
- C --> D{Handler Type}
263
- D -->|emit| E[Dispatch Commands]
264
- D -->|custom| F[Execute Function]
265
- D -->|phased| G[Phase Execution]
266
- D -->|settled| H[Track Completion]
456
+ subgraph Builder
457
+ define["define() / defineV2()"]
458
+ end
459
+
460
+ subgraph Core
461
+ Pipeline["Pipeline + Descriptor"]
462
+ GraphIR["GraphIR"]
463
+ end
464
+
465
+ subgraph Runtime
466
+ PR["PipelineRuntime"]
467
+ AT["AwaitTracker"]
468
+ ECM["EventCommandMapper"]
469
+ end
470
+
471
+ subgraph Server
472
+ PS["PipelineServer"]
473
+ SSE["SSEManager"]
474
+ CG["CommandGate"]
475
+ QT["QuiescenceTracker"]
476
+ end
477
+
478
+ subgraph Store
479
+ ES["EventStore + Projections"]
480
+ RM["PipelineReadModel"]
481
+ end
482
+
483
+ define --> Pipeline
484
+ Pipeline --> GraphIR
485
+ Pipeline --> PR
486
+ PS --> PR
487
+ PS --> SSE
488
+ PS --> CG
489
+ PS --> QT
490
+ PS --> ES
491
+ ES --> RM
492
+ PR --> AT
493
+ PR --> ECM
267
494
  ```
268
495
 
269
- *Flow: Events arrive, handlers match, execute based on type.*
270
-
271
496
  ### Dependencies
272
497
 
273
498
  | Package | Usage |
274
- |---------|-------|
275
- | `@auto-engineer/message-bus` | Command/event messaging |
499
+ |---|---|
500
+ | `@auto-engineer/message-bus` | Command/event messaging infrastructure |
276
501
  | `@auto-engineer/file-store` | File storage utilities |
277
- | `@event-driven-io/emmett` | Event store |
278
- | `express` | HTTP server |
279
- | `nanoid` | ID generation |
502
+ | `@event-driven-io/emmett` | In-memory event store with projections |
503
+ | `@event-driven-io/emmett-sqlite` | SQLite-backed persistent event store |
504
+ | `express` | HTTP server for REST + SSE endpoints |
505
+ | `nanoid` | Compact unique ID generation |
506
+ | `chokidar` | File system watching |
507
+ | `jose` | JWT handling |
508
+ | `get-port` | Automatic port selection |
package/package.json CHANGED
@@ -15,8 +15,8 @@
15
15
  "jose": "^5.9.6",
16
16
  "nanoid": "^5.0.0",
17
17
  "uuid": "^11.0.0",
18
- "@auto-engineer/file-store": "1.147.0",
19
- "@auto-engineer/message-bus": "1.147.0"
18
+ "@auto-engineer/file-store": "1.149.0",
19
+ "@auto-engineer/message-bus": "1.149.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/cors": "^2.8.17",
@@ -25,7 +25,7 @@
25
25
  "publishConfig": {
26
26
  "access": "public"
27
27
  },
28
- "version": "1.147.0",
28
+ "version": "1.149.0",
29
29
  "scripts": {
30
30
  "build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
31
31
  "test": "vitest run --reporter=dot",