@auto-engineer/pipeline 0.0.1

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 (270) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/LICENSE +10 -0
  3. package/claude.md +160 -0
  4. package/dist/src/builder/define.d.ts +90 -0
  5. package/dist/src/builder/define.d.ts.map +1 -0
  6. package/dist/src/builder/define.js +425 -0
  7. package/dist/src/builder/define.js.map +1 -0
  8. package/dist/src/builder/define.specs.d.ts +2 -0
  9. package/dist/src/builder/define.specs.d.ts.map +1 -0
  10. package/dist/src/builder/define.specs.js +435 -0
  11. package/dist/src/builder/define.specs.js.map +1 -0
  12. package/dist/src/config/pipeline-config.d.ts +13 -0
  13. package/dist/src/config/pipeline-config.d.ts.map +1 -0
  14. package/dist/src/config/pipeline-config.js +15 -0
  15. package/dist/src/config/pipeline-config.js.map +1 -0
  16. package/dist/src/core/descriptors.d.ts +84 -0
  17. package/dist/src/core/descriptors.d.ts.map +1 -0
  18. package/dist/src/core/descriptors.js +2 -0
  19. package/dist/src/core/descriptors.js.map +1 -0
  20. package/dist/src/core/descriptors.specs.d.ts +2 -0
  21. package/dist/src/core/descriptors.specs.d.ts.map +1 -0
  22. package/dist/src/core/descriptors.specs.js +24 -0
  23. package/dist/src/core/descriptors.specs.js.map +1 -0
  24. package/dist/src/core/types.d.ts +10 -0
  25. package/dist/src/core/types.d.ts.map +1 -0
  26. package/dist/src/core/types.js +4 -0
  27. package/dist/src/core/types.js.map +1 -0
  28. package/dist/src/core/types.specs.d.ts +2 -0
  29. package/dist/src/core/types.specs.d.ts.map +1 -0
  30. package/dist/src/core/types.specs.js +40 -0
  31. package/dist/src/core/types.specs.js.map +1 -0
  32. package/dist/src/graph/types.d.ts +17 -0
  33. package/dist/src/graph/types.d.ts.map +1 -0
  34. package/dist/src/graph/types.js +2 -0
  35. package/dist/src/graph/types.js.map +1 -0
  36. package/dist/src/graph/types.specs.d.ts +2 -0
  37. package/dist/src/graph/types.specs.d.ts.map +1 -0
  38. package/dist/src/graph/types.specs.js +148 -0
  39. package/dist/src/graph/types.specs.js.map +1 -0
  40. package/dist/src/index.d.ts +20 -0
  41. package/dist/src/index.d.ts.map +1 -0
  42. package/dist/src/index.js +12 -0
  43. package/dist/src/index.js.map +1 -0
  44. package/dist/src/logging/event-logger.d.ts +21 -0
  45. package/dist/src/logging/event-logger.d.ts.map +1 -0
  46. package/dist/src/logging/event-logger.js +31 -0
  47. package/dist/src/logging/event-logger.js.map +1 -0
  48. package/dist/src/logging/event-logger.specs.d.ts +2 -0
  49. package/dist/src/logging/event-logger.specs.d.ts.map +1 -0
  50. package/dist/src/logging/event-logger.specs.js +81 -0
  51. package/dist/src/logging/event-logger.specs.js.map +1 -0
  52. package/dist/src/plugins/handler-adapter.d.ts +5 -0
  53. package/dist/src/plugins/handler-adapter.d.ts.map +1 -0
  54. package/dist/src/plugins/handler-adapter.js +17 -0
  55. package/dist/src/plugins/handler-adapter.js.map +1 -0
  56. package/dist/src/plugins/handler-adapter.specs.d.ts +2 -0
  57. package/dist/src/plugins/handler-adapter.specs.d.ts.map +1 -0
  58. package/dist/src/plugins/handler-adapter.specs.js +129 -0
  59. package/dist/src/plugins/handler-adapter.specs.js.map +1 -0
  60. package/dist/src/plugins/plugin-loader.d.ts +25 -0
  61. package/dist/src/plugins/plugin-loader.d.ts.map +1 -0
  62. package/dist/src/plugins/plugin-loader.js +150 -0
  63. package/dist/src/plugins/plugin-loader.js.map +1 -0
  64. package/dist/src/plugins/plugin-loader.specs.d.ts +2 -0
  65. package/dist/src/plugins/plugin-loader.specs.d.ts.map +1 -0
  66. package/dist/src/plugins/plugin-loader.specs.js +246 -0
  67. package/dist/src/plugins/plugin-loader.specs.js.map +1 -0
  68. package/dist/src/runtime/await-tracker.d.ts +10 -0
  69. package/dist/src/runtime/await-tracker.d.ts.map +1 -0
  70. package/dist/src/runtime/await-tracker.js +42 -0
  71. package/dist/src/runtime/await-tracker.js.map +1 -0
  72. package/dist/src/runtime/await-tracker.specs.d.ts +2 -0
  73. package/dist/src/runtime/await-tracker.specs.d.ts.map +1 -0
  74. package/dist/src/runtime/await-tracker.specs.js +46 -0
  75. package/dist/src/runtime/await-tracker.specs.js.map +1 -0
  76. package/dist/src/runtime/context.d.ts +12 -0
  77. package/dist/src/runtime/context.d.ts.map +1 -0
  78. package/dist/src/runtime/context.js +2 -0
  79. package/dist/src/runtime/context.js.map +1 -0
  80. package/dist/src/runtime/context.specs.d.ts +2 -0
  81. package/dist/src/runtime/context.specs.d.ts.map +1 -0
  82. package/dist/src/runtime/context.specs.js +26 -0
  83. package/dist/src/runtime/context.specs.js.map +1 -0
  84. package/dist/src/runtime/event-command-map.d.ts +15 -0
  85. package/dist/src/runtime/event-command-map.d.ts.map +1 -0
  86. package/dist/src/runtime/event-command-map.js +26 -0
  87. package/dist/src/runtime/event-command-map.js.map +1 -0
  88. package/dist/src/runtime/event-command-map.specs.d.ts +2 -0
  89. package/dist/src/runtime/event-command-map.specs.d.ts.map +1 -0
  90. package/dist/src/runtime/event-command-map.specs.js +108 -0
  91. package/dist/src/runtime/event-command-map.specs.js.map +1 -0
  92. package/dist/src/runtime/phased-executor.d.ts +29 -0
  93. package/dist/src/runtime/phased-executor.d.ts.map +1 -0
  94. package/dist/src/runtime/phased-executor.js +164 -0
  95. package/dist/src/runtime/phased-executor.js.map +1 -0
  96. package/dist/src/runtime/phased-executor.specs.d.ts +2 -0
  97. package/dist/src/runtime/phased-executor.specs.d.ts.map +1 -0
  98. package/dist/src/runtime/phased-executor.specs.js +256 -0
  99. package/dist/src/runtime/phased-executor.specs.js.map +1 -0
  100. package/dist/src/runtime/pipeline-runtime.d.ts +17 -0
  101. package/dist/src/runtime/pipeline-runtime.d.ts.map +1 -0
  102. package/dist/src/runtime/pipeline-runtime.js +87 -0
  103. package/dist/src/runtime/pipeline-runtime.js.map +1 -0
  104. package/dist/src/runtime/pipeline-runtime.specs.d.ts +2 -0
  105. package/dist/src/runtime/pipeline-runtime.specs.d.ts.map +1 -0
  106. package/dist/src/runtime/pipeline-runtime.specs.js +192 -0
  107. package/dist/src/runtime/pipeline-runtime.specs.js.map +1 -0
  108. package/dist/src/runtime/settled-tracker.d.ts +42 -0
  109. package/dist/src/runtime/settled-tracker.d.ts.map +1 -0
  110. package/dist/src/runtime/settled-tracker.js +161 -0
  111. package/dist/src/runtime/settled-tracker.js.map +1 -0
  112. package/dist/src/runtime/settled-tracker.specs.d.ts +2 -0
  113. package/dist/src/runtime/settled-tracker.specs.d.ts.map +1 -0
  114. package/dist/src/runtime/settled-tracker.specs.js +361 -0
  115. package/dist/src/runtime/settled-tracker.specs.js.map +1 -0
  116. package/dist/src/server/full-orchestration.e2e.specs.d.ts +2 -0
  117. package/dist/src/server/full-orchestration.e2e.specs.d.ts.map +1 -0
  118. package/dist/src/server/full-orchestration.e2e.specs.js +561 -0
  119. package/dist/src/server/full-orchestration.e2e.specs.js.map +1 -0
  120. package/dist/src/server/pipeline-server.d.ts +59 -0
  121. package/dist/src/server/pipeline-server.d.ts.map +1 -0
  122. package/dist/src/server/pipeline-server.e2e.specs.d.ts +2 -0
  123. package/dist/src/server/pipeline-server.e2e.specs.d.ts.map +1 -0
  124. package/dist/src/server/pipeline-server.e2e.specs.js +381 -0
  125. package/dist/src/server/pipeline-server.e2e.specs.js.map +1 -0
  126. package/dist/src/server/pipeline-server.js +527 -0
  127. package/dist/src/server/pipeline-server.js.map +1 -0
  128. package/dist/src/server/pipeline-server.specs.d.ts +2 -0
  129. package/dist/src/server/pipeline-server.specs.d.ts.map +1 -0
  130. package/dist/src/server/pipeline-server.specs.js +662 -0
  131. package/dist/src/server/pipeline-server.specs.js.map +1 -0
  132. package/dist/src/server/sse-manager.d.ts +12 -0
  133. package/dist/src/server/sse-manager.d.ts.map +1 -0
  134. package/dist/src/server/sse-manager.js +63 -0
  135. package/dist/src/server/sse-manager.js.map +1 -0
  136. package/dist/src/server/sse-manager.specs.d.ts +2 -0
  137. package/dist/src/server/sse-manager.specs.d.ts.map +1 -0
  138. package/dist/src/server/sse-manager.specs.js +158 -0
  139. package/dist/src/server/sse-manager.specs.js.map +1 -0
  140. package/dist/src/testing/event-capture.d.ts +14 -0
  141. package/dist/src/testing/event-capture.d.ts.map +1 -0
  142. package/dist/src/testing/event-capture.js +55 -0
  143. package/dist/src/testing/event-capture.js.map +1 -0
  144. package/dist/src/testing/event-capture.specs.d.ts +2 -0
  145. package/dist/src/testing/event-capture.specs.d.ts.map +1 -0
  146. package/dist/src/testing/event-capture.specs.js +114 -0
  147. package/dist/src/testing/event-capture.specs.js.map +1 -0
  148. package/dist/src/testing/fixtures/kanban-full.pipeline.d.ts +7 -0
  149. package/dist/src/testing/fixtures/kanban-full.pipeline.d.ts.map +1 -0
  150. package/dist/src/testing/fixtures/kanban-full.pipeline.js +168 -0
  151. package/dist/src/testing/fixtures/kanban-full.pipeline.js.map +1 -0
  152. package/dist/src/testing/fixtures/kanban-full.pipeline.specs.d.ts +2 -0
  153. package/dist/src/testing/fixtures/kanban-full.pipeline.specs.d.ts.map +1 -0
  154. package/dist/src/testing/fixtures/kanban-full.pipeline.specs.js +263 -0
  155. package/dist/src/testing/fixtures/kanban-full.pipeline.specs.js.map +1 -0
  156. package/dist/src/testing/fixtures/kanban-todo.config.d.ts +3 -0
  157. package/dist/src/testing/fixtures/kanban-todo.config.d.ts.map +1 -0
  158. package/dist/src/testing/fixtures/kanban-todo.config.js +19 -0
  159. package/dist/src/testing/fixtures/kanban-todo.config.js.map +1 -0
  160. package/dist/src/testing/fixtures/kanban.pipeline.d.ts +5 -0
  161. package/dist/src/testing/fixtures/kanban.pipeline.d.ts.map +1 -0
  162. package/dist/src/testing/fixtures/kanban.pipeline.js +76 -0
  163. package/dist/src/testing/fixtures/kanban.pipeline.js.map +1 -0
  164. package/dist/src/testing/fixtures/kanban.pipeline.specs.d.ts +2 -0
  165. package/dist/src/testing/fixtures/kanban.pipeline.specs.d.ts.map +1 -0
  166. package/dist/src/testing/fixtures/kanban.pipeline.specs.js +29 -0
  167. package/dist/src/testing/fixtures/kanban.pipeline.specs.js.map +1 -0
  168. package/dist/src/testing/kanban-todo.e2e.specs.d.ts +2 -0
  169. package/dist/src/testing/kanban-todo.e2e.specs.d.ts.map +1 -0
  170. package/dist/src/testing/kanban-todo.e2e.specs.js +160 -0
  171. package/dist/src/testing/kanban-todo.e2e.specs.js.map +1 -0
  172. package/dist/src/testing/mock-handlers.d.ts +21 -0
  173. package/dist/src/testing/mock-handlers.d.ts.map +1 -0
  174. package/dist/src/testing/mock-handlers.js +34 -0
  175. package/dist/src/testing/mock-handlers.js.map +1 -0
  176. package/dist/src/testing/mock-handlers.specs.d.ts +2 -0
  177. package/dist/src/testing/mock-handlers.specs.d.ts.map +1 -0
  178. package/dist/src/testing/mock-handlers.specs.js +193 -0
  179. package/dist/src/testing/mock-handlers.specs.js.map +1 -0
  180. package/dist/src/testing/real-execution.e2e.specs.d.ts +2 -0
  181. package/dist/src/testing/real-execution.e2e.specs.d.ts.map +1 -0
  182. package/dist/src/testing/real-execution.e2e.specs.js +140 -0
  183. package/dist/src/testing/real-execution.e2e.specs.js.map +1 -0
  184. package/dist/src/testing/real-plugin.e2e.specs.d.ts +2 -0
  185. package/dist/src/testing/real-plugin.e2e.specs.d.ts.map +1 -0
  186. package/dist/src/testing/real-plugin.e2e.specs.js +65 -0
  187. package/dist/src/testing/real-plugin.e2e.specs.js.map +1 -0
  188. package/dist/src/testing/server-startup.e2e.specs.d.ts +2 -0
  189. package/dist/src/testing/server-startup.e2e.specs.d.ts.map +1 -0
  190. package/dist/src/testing/server-startup.e2e.specs.js +104 -0
  191. package/dist/src/testing/server-startup.e2e.specs.js.map +1 -0
  192. package/dist/src/testing/snapshot-compare.d.ts +18 -0
  193. package/dist/src/testing/snapshot-compare.d.ts.map +1 -0
  194. package/dist/src/testing/snapshot-compare.js +86 -0
  195. package/dist/src/testing/snapshot-compare.js.map +1 -0
  196. package/dist/src/testing/snapshot-compare.specs.d.ts +2 -0
  197. package/dist/src/testing/snapshot-compare.specs.d.ts.map +1 -0
  198. package/dist/src/testing/snapshot-compare.specs.js +112 -0
  199. package/dist/src/testing/snapshot-compare.specs.js.map +1 -0
  200. package/dist/src/testing/snapshot-sanitize.d.ts +8 -0
  201. package/dist/src/testing/snapshot-sanitize.d.ts.map +1 -0
  202. package/dist/src/testing/snapshot-sanitize.js +10 -0
  203. package/dist/src/testing/snapshot-sanitize.js.map +1 -0
  204. package/dist/src/testing/snapshot-sanitize.specs.d.ts +2 -0
  205. package/dist/src/testing/snapshot-sanitize.specs.d.ts.map +1 -0
  206. package/dist/src/testing/snapshot-sanitize.specs.js +104 -0
  207. package/dist/src/testing/snapshot-sanitize.specs.js.map +1 -0
  208. package/dist/tsconfig.tsbuildinfo +1 -0
  209. package/docs/testing-analysis.md +395 -0
  210. package/package.json +31 -0
  211. package/pipeline-api-new.md +1078 -0
  212. package/pomodoro-plan.md +651 -0
  213. package/scripts/run-kanban-e2e.ts +219 -0
  214. package/scripts/start-server.ts +64 -0
  215. package/snapshots/e2e-run-2025-12-22T15-52-03.json +613 -0
  216. package/snapshots/e2e-run-2025-12-22T16-51-30.json +699 -0
  217. package/src/builder/define.specs.ts +531 -0
  218. package/src/builder/define.ts +700 -0
  219. package/src/config/pipeline-config.ts +32 -0
  220. package/src/core/descriptors.specs.ts +28 -0
  221. package/src/core/descriptors.ts +99 -0
  222. package/src/core/types.specs.ts +44 -0
  223. package/src/core/types.ts +16 -0
  224. package/src/graph/types.specs.ts +176 -0
  225. package/src/graph/types.ts +19 -0
  226. package/src/index.ts +54 -0
  227. package/src/logging/event-logger.specs.ts +100 -0
  228. package/src/logging/event-logger.ts +50 -0
  229. package/src/plugins/handler-adapter.specs.ts +164 -0
  230. package/src/plugins/handler-adapter.ts +21 -0
  231. package/src/plugins/plugin-loader.specs.ts +295 -0
  232. package/src/plugins/plugin-loader.ts +202 -0
  233. package/src/runtime/await-tracker.specs.ts +52 -0
  234. package/src/runtime/await-tracker.ts +50 -0
  235. package/src/runtime/context.specs.ts +28 -0
  236. package/src/runtime/context.ts +13 -0
  237. package/src/runtime/event-command-map.specs.ts +136 -0
  238. package/src/runtime/event-command-map.ts +38 -0
  239. package/src/runtime/phased-executor.specs.ts +358 -0
  240. package/src/runtime/phased-executor.ts +224 -0
  241. package/src/runtime/pipeline-runtime.specs.ts +214 -0
  242. package/src/runtime/pipeline-runtime.ts +119 -0
  243. package/src/runtime/settled-tracker.specs.ts +448 -0
  244. package/src/runtime/settled-tracker.ts +237 -0
  245. package/src/server/full-orchestration.e2e.specs.ts +672 -0
  246. package/src/server/pipeline-server.e2e.specs.ts +505 -0
  247. package/src/server/pipeline-server.specs.ts +761 -0
  248. package/src/server/pipeline-server.ts +656 -0
  249. package/src/server/sse-manager.specs.ts +208 -0
  250. package/src/server/sse-manager.ts +79 -0
  251. package/src/testing/event-capture.specs.ts +143 -0
  252. package/src/testing/event-capture.ts +65 -0
  253. package/src/testing/fixtures/kanban-full.pipeline.specs.ts +337 -0
  254. package/src/testing/fixtures/kanban-full.pipeline.ts +225 -0
  255. package/src/testing/fixtures/kanban-todo.config.ts +19 -0
  256. package/src/testing/fixtures/kanban.pipeline.specs.ts +33 -0
  257. package/src/testing/fixtures/kanban.pipeline.ts +124 -0
  258. package/src/testing/kanban-todo.e2e.specs.ts +209 -0
  259. package/src/testing/mock-handlers.specs.ts +229 -0
  260. package/src/testing/mock-handlers.ts +58 -0
  261. package/src/testing/real-execution.e2e.specs.ts +193 -0
  262. package/src/testing/real-plugin.e2e.specs.ts +94 -0
  263. package/src/testing/server-startup.e2e.specs.ts +162 -0
  264. package/src/testing/snapshot-compare.specs.ts +136 -0
  265. package/src/testing/snapshot-compare.ts +106 -0
  266. package/src/testing/snapshot-sanitize.specs.ts +131 -0
  267. package/src/testing/snapshot-sanitize.ts +17 -0
  268. package/tsconfig.json +11 -0
  269. package/tsconfig.test.json +9 -0
  270. package/vitest.config.ts +29 -0
@@ -0,0 +1,1078 @@
1
+ # Pipeline System Architecture
2
+
3
+ > **TL;DR:** A fluent API with succinct pipeline definitions, zero manual state management, and full graph visualization support.
4
+ >
5
+ > **[Jump to the complete example →](#4-complete-example-kanban-pipeline)**
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ - [Executive Summary](#executive-summary)
12
+ - [1. The Problem](#1-the-problem)
13
+ - [What We're Building](#what-were-building)
14
+ - [Current State](#current-state)
15
+ - [Requirements](#requirements)
16
+ - [2. Design Philosophy](#2-design-philosophy)
17
+ - [The API Should Read Like a Description](#the-api-should-read-like-a-description)
18
+ - [Three Complexity Levels](#three-complexity-levels)
19
+ - [Familiar Mental Models](#familiar-mental-models)
20
+ - [3. Complete API Specification](#3-complete-api-specification)
21
+ - [3.1 Pipeline Builder](#31-pipeline-builder)
22
+ - [3.2 Trigger Builder](#32-trigger-builder)
23
+ - [3.3 Emit Chain](#33-emit-chain)
24
+ - [3.4 Run Builder (Scatter)](#34-run-builder-scatter)
25
+ - [3.5 Gather Builder (Await Results)](#35-gather-builder-await-results)
26
+ - [3.6 Failure Context (The Retry API)](#36-failure-context-the-retry-api)
27
+ - [3.7 ForEach Builder (Phased Execution)](#37-foreach-builder-phased-execution)
28
+ - [3.8 Context Types](#38-context-types)
29
+ - [3.9 Handler Context](#39-handler-context-for-handle)
30
+ - [3.10 Helper Function](#310-helper-function)
31
+ - [4. Complete Example: Kanban Pipeline](#4-complete-example-kanban-pipeline)
32
+ - [5. Side-by-Side Comparison](#5-side-by-side-comparison)
33
+ - [6. Graph Extraction](#6-graph-extraction)
34
+ - [Graph IR Structure](#graph-ir-structure)
35
+ - [Example Output](#example-output)
36
+ - [Visualization](#visualization)
37
+ - [7. Pattern Templates (Optional)](#7-pattern-templates-optional-extension)
38
+ - [8. Runtime Behavior](#8-runtime-behavior)
39
+ - [8.1 Execution Flow](#81-execution-flow)
40
+ - [8.2 State Management](#82-state-management)
41
+ - [9. Summary](#10-summary)
42
+
43
+ ---
44
+
45
+ ## Executive Summary
46
+
47
+ This document specifies a fluent API for defining event-driven pipelines that orchestrate AI-powered code generation workflows. The API is designed to:
48
+
49
+ 1. **Read like English** — Pipeline definitions describe _what happens_, not _how to wire it_
50
+ 2. **Handle real complexity** — Scatter-gather-retry and phased execution are first-class primitives
51
+ 3. **Enable visualization** — Static graph extraction without running the pipeline
52
+ 4. **Run anywhere** — Same definition works locally and on Cloudflare
53
+
54
+ ---
55
+
56
+ ## 1. The Problem
57
+
58
+ ### What We're Building
59
+
60
+ The **Pipeline System** orchestrates dozens of AI-powered plugins into coherent workflows. A pipeline configuration defines:
61
+
62
+ - Which events trigger which commands
63
+ - How to handle failures and retries
64
+ - How work flows through phases
65
+ - When to run things in parallel vs. sequentially
66
+
67
+ ### Current State
68
+
69
+ Today, pipeline configs are imperative TypeScript with:
70
+
71
+ ```typescript
72
+ // Scattered mutable state
73
+ const sliceRetryState = new Map<string, number>()
74
+ let clientComponents = []
75
+ const processedComponents = new Set()
76
+ const failedComponents = new Set()
77
+ const dispatchedPhases = new Set()
78
+
79
+ // Implicit event relationships
80
+ on('SliceImplemented', (e) => dispatch('CheckTests', {...}))
81
+ on('SliceImplemented', (e) => dispatch('CheckTypes', {...}))
82
+ on('SliceImplemented', (e) => dispatch('CheckLint', {...}))
83
+
84
+ // Complex aggregation with unclear semantics
85
+ on.settled(['CheckTests', 'CheckTypes', 'CheckLint'],
86
+ dispatch(['ImplementSlice'], (events, send) => {
87
+ const failures = findCheckFailures(events)
88
+ // ... 30 more lines of retry logic
89
+ })
90
+ )
91
+ ```
92
+
93
+ **Problems:**
94
+
95
+ - Hard to understand the flow
96
+ - Impossible to visualize without execution
97
+ - Easy to introduce bugs in state management
98
+ - Boilerplate for common patterns (retry, phases)
99
+
100
+ ### Requirements
101
+
102
+ | ID | Requirement |
103
+ | --- | --------------------------------------------------- |
104
+ | R1 | **Easy to write** — New pipeline in <30 mins |
105
+ | R2 | **Plugin compatible** — Commands in, events out |
106
+ | R3 | **Runs locally** — Single-process, no cloud needed |
107
+ | R4 | **Runs on Cloudflare** — Workers, DO, D1, Queues |
108
+ | R5 | **Visualizable** — Static graph extraction |
109
+ | R6 | **Status queryable** — Current state at any time |
110
+ | R7 | **Full history** — Every event stored for debugging |
111
+
112
+ ---
113
+
114
+ ## 2. Design Philosophy
115
+
116
+ ### The API Should Read Like a Description
117
+
118
+ **Bad:** Assembly instructions
119
+
120
+ ```typescript
121
+ .scatter([...]).gatherBy(...).retryUntilSuccess({...})
122
+ ```
123
+
124
+ **Good:** A description of what happens
125
+
126
+ ```typescript
127
+ .run([...]).awaitAll({ key: ... }).onFailure(ctx => ctx.retry(...))
128
+ ```
129
+
130
+ ### Three Complexity Levels
131
+
132
+ | Level | Use Case | Example |
133
+ | -------------- | --------------- | --------------------------------------- |
134
+ | **Simple** | Event → Command | `.on('A').emit('B', {...})` |
135
+ | **Structured** | Common patterns | `.run([...]).awaitAll().onFailure(...)` |
136
+ | **Custom** | Unique logic | `.handle(ctx => { ... })` |
137
+
138
+ ### Familiar Mental Models
139
+
140
+ | Pattern | Inspired By |
141
+ | ------------------------------ | ------------------------ |
142
+ | `.forEach(...).groupInto(...)` | JavaScript array methods |
143
+ | `.run([...]).awaitAll()` | Promise.all |
144
+ | `.when(predicate)` | Stream filtering |
145
+ | `.onFailure(...)` | Error handlers |
146
+
147
+ ---
148
+
149
+ ## 3. Complete API Specification
150
+
151
+ ### 3.1 Pipeline Builder
152
+
153
+ ```typescript
154
+ function define(name: string): PipelineBuilder;
155
+
156
+ interface PipelineBuilder {
157
+ // ─────────────────────────────────────────────────────────────────────────
158
+ // METADATA
159
+ // ─────────────────────────────────────────────────────────────────────────
160
+
161
+ version(v: string): this;
162
+ description(d: string): this;
163
+
164
+ // ─────────────────────────────────────────────────────────────────────────
165
+ // STATE (optional, for custom handlers)
166
+ // ─────────────────────────────────────────────────────────────────────────
167
+
168
+ withState<S>(initializers: StateInitializers<S>): PipelineBuilder<S>;
169
+
170
+ // ─────────────────────────────────────────────────────────────────────────
171
+ // NAMED DEFINITIONS
172
+ // ─────────────────────────────────────────────────────────────────────────
173
+
174
+ /** Define a reusable correlation key extractor */
175
+ key(name: string, extractor: (event: Event) => string): this;
176
+
177
+ // ─────────────────────────────────────────────────────────────────────────
178
+ // EVENT HANDLERS
179
+ // ─────────────────────────────────────────────────────────────────────────
180
+
181
+ /** Start a handler chain for an event type */
182
+ on<E extends EventType>(eventType: E): TriggerBuilder<E>;
183
+
184
+ // ─────────────────────────────────────────────────────────────────────────
185
+ // TERMINAL
186
+ // ─────────────────────────────────────────────────────────────────────────
187
+
188
+ build(): Pipeline;
189
+ }
190
+ ```
191
+
192
+ ### 3.2 Trigger Builder
193
+
194
+ After `.on('EventType')`, you can filter, emit, or define complex patterns.
195
+
196
+ ```typescript
197
+ interface TriggerBuilder<E> {
198
+ // ─────────────────────────────────────────────────────────────────────────
199
+ // FILTERING
200
+ // ─────────────────────────────────────────────────────────────────────────
201
+
202
+ /** Only proceed if predicate returns true */
203
+ when(predicate: (event: E) => boolean): this;
204
+
205
+ // ─────────────────────────────────────────────────────────────────────────
206
+ // SIMPLE EMIT
207
+ // One or more commands in parallel
208
+ // ─────────────────────────────────────────────────────────────────────────
209
+
210
+ /** Emit a command (multiple .emit() calls = parallel execution) */
211
+ emit<C extends CommandType>(commandType: C, data: CommandData<C> | ((event: E) => CommandData<C>)): EmitChain<E>;
212
+
213
+ // ─────────────────────────────────────────────────────────────────────────
214
+ // SCATTER-GATHER PATTERN
215
+ // Run multiple commands, wait for all, handle results
216
+ // ─────────────────────────────────────────────────────────────────────────
217
+
218
+ /** Run multiple commands in parallel */
219
+ run(commands: CommandSpec[] | ((event: E) => CommandSpec[])): RunBuilder<E>;
220
+
221
+ // ─────────────────────────────────────────────────────────────────────────
222
+ // PHASED EXECUTION PATTERN
223
+ // Process items in sequential groups
224
+ // ─────────────────────────────────────────────────────────────────────────
225
+
226
+ /** Iterate over a collection from the event */
227
+ forEach<T>(selector: (event: E) => T[]): ForEachBuilder<E, T>;
228
+
229
+ // ─────────────────────────────────────────────────────────────────────────
230
+ // CUSTOM HANDLER
231
+ // Full imperative access for unique cases
232
+ // ─────────────────────────────────────────────────────────────────────────
233
+
234
+ /** Custom handler with full context access */
235
+ handle(handler: (event: E, ctx: HandlerContext) => void, meta?: { emits?: string[] }): ChainTerminal;
236
+ }
237
+ ```
238
+
239
+ ### 3.3 Emit Chain
240
+
241
+ Multiple `.emit()` calls create parallel commands.
242
+
243
+ ```typescript
244
+ interface EmitChain<E> {
245
+ /** Add another parallel command */
246
+ emit<C extends CommandType>(commandType: C, data: CommandData<C> | ((event: E) => CommandData<C>)): this;
247
+
248
+ /** Start a new event handler */
249
+ on<E2 extends EventType>(eventType: E2): TriggerBuilder<E2>;
250
+
251
+ /** End the pipeline definition */
252
+ build(): Pipeline;
253
+ }
254
+ ```
255
+
256
+ **Example: Parallel dispatch**
257
+
258
+ ```typescript
259
+ .on('ServerGenerated')
260
+ .emit('GenerateIA', { modelPath: '...' })
261
+ .emit('StartServer', { serverDirectory: '...' })
262
+ // Both commands run in parallel
263
+ ```
264
+
265
+ ### 3.4 Run Builder (Scatter)
266
+
267
+ After `.run([...])`, define how to gather and handle results.
268
+
269
+ ```typescript
270
+ interface RunBuilder<E> {
271
+ /** Wait for all commands to complete, grouped by key */
272
+ awaitAll(config: {
273
+ /** Correlation key (name or extractor function) */
274
+ key: string | ((event: Event) => string);
275
+ /** Timeout in milliseconds */
276
+ timeout?: number;
277
+ }): GatherBuilder<E>;
278
+
279
+ /** Don't wait — fire and forget */
280
+ done(): ChainTerminal;
281
+ }
282
+ ```
283
+
284
+ ### 3.5 Gather Builder (Await Results)
285
+
286
+ After `.awaitAll()`, handle success or failure.
287
+
288
+ ```typescript
289
+ interface GatherBuilder<E> {
290
+ /** Handle when any command fails */
291
+ onFailure(handler: (ctx: FailureContext) => void): GatherComplete<E>;
292
+
293
+ /** Handle when all commands succeed */
294
+ onSuccess(handler: (ctx: SuccessContext) => void): GatherComplete<E>;
295
+
296
+ /** Handle all completions (custom logic) */
297
+ onComplete(handler: (ctx: CompleteContext) => void): GatherComplete<E>;
298
+ }
299
+
300
+ interface GatherComplete<E> {
301
+ /** Add success handler (if failure was defined first) */
302
+ onSuccess(handler: (ctx: SuccessContext) => void): this;
303
+
304
+ /** Add failure handler (if success was defined first) */
305
+ onFailure(handler: (ctx: FailureContext) => void): this;
306
+
307
+ /** Start a new event handler */
308
+ on<E2 extends EventType>(eventType: E2): TriggerBuilder<E2>;
309
+
310
+ /** End the pipeline definition */
311
+ build(): Pipeline;
312
+ }
313
+ ```
314
+
315
+ ### 3.6 Failure Context (The Retry API)
316
+
317
+ The failure handler receives a context with retry capabilities.
318
+
319
+ ```typescript
320
+ interface FailureContext {
321
+ // ─────────────────────────────────────────────────────────────────────────
322
+ // CORRELATION INFO
323
+ // ─────────────────────────────────────────────────────────────────────────
324
+
325
+ /** The correlation key for this group */
326
+ key: string;
327
+
328
+ /** Current attempt number (1-based) */
329
+ attempt: number;
330
+
331
+ // ─────────────────────────────────────────────────────────────────────────
332
+ // FAILURE INFO
333
+ // ─────────────────────────────────────────────────────────────────────────
334
+
335
+ /** All failure events */
336
+ failures: Event[];
337
+
338
+ /** Concatenated error text from all failures */
339
+ errorText: string;
340
+
341
+ /** All events (success and failure) */
342
+ all: Event[];
343
+
344
+ /** Events grouped by command type */
345
+ byCommand: Record<string, Event[]>;
346
+
347
+ // ─────────────────────────────────────────────────────────────────────────
348
+ // RETRY ACTION
349
+ // ─────────────────────────────────────────────────────────────────────────
350
+
351
+ /** Retry a command with new data */
352
+ retry<C extends CommandType>(
353
+ commandType: C,
354
+ config: {
355
+ /** Maximum retry attempts */
356
+ maxAttempts: number;
357
+ /** Command data */
358
+ data: CommandData<C>;
359
+ /** Backoff strategy */
360
+ backoff?: 'none' | 'linear' | 'exponential';
361
+ /** Base delay in ms (default: 1000) */
362
+ backoffMs?: number;
363
+ },
364
+ ): void;
365
+
366
+ // ─────────────────────────────────────────────────────────────────────────
367
+ // EMIT (for non-retry actions)
368
+ // ─────────────────────────────────────────────────────────────────────────
369
+
370
+ /** Emit a command (for notifications, etc.) */
371
+ emit<C extends CommandType>(commandType: C, data: CommandData<C>): void;
372
+ }
373
+
374
+ interface SuccessContext {
375
+ key: string;
376
+ attempt: number;
377
+ successes: Event[];
378
+ all: Event[];
379
+ byCommand: Record<string, Event[]>;
380
+ emit<C extends CommandType>(commandType: C, data: CommandData<C>): void;
381
+ }
382
+ ```
383
+
384
+ ### 3.7 ForEach Builder (Phased Execution)
385
+
386
+ For processing collections in sequential phases.
387
+
388
+ ```typescript
389
+ interface ForEachBuilder<E, T> {
390
+ /** Group items into sequential phases */
391
+ groupInto<P extends string>(phases: readonly P[], classifier: (item: T) => P): PhasedBuilder<E, T, P>;
392
+
393
+ /** Process all items in parallel (no phases) */
394
+ emit(builder: (item: T, ctx: ItemContext<E>) => CommandSpec): ItemTrackingBuilder<E, T>;
395
+ }
396
+
397
+ interface PhasedBuilder<E, T, P> {
398
+ /** How to run each phase */
399
+ runSequentially(config?: {
400
+ /** Stop if any item in a phase fails (default: true) */
401
+ stopOnFailure?: boolean;
402
+ }): PhasedEmitBuilder<E, T, P>;
403
+ }
404
+
405
+ interface PhasedEmitBuilder<E, T, P> {
406
+ /** What command to emit for each item */
407
+ emit(builder: (item: T, phase: P, ctx: ItemContext<E>) => CommandSpec): PhasedTrackingBuilder<E, T, P>;
408
+ }
409
+
410
+ interface PhasedTrackingBuilder<E, T, P> {
411
+ /** How to track item completion */
412
+ completeWhen(config: {
413
+ /** Event type indicating success */
414
+ success: string;
415
+ /** Event type indicating failure */
416
+ failure: string;
417
+ /** Extract item key from completion event */
418
+ key: (event: Event) => string;
419
+ }): PhasedHooksBuilder<E, T, P>;
420
+ }
421
+
422
+ interface PhasedHooksBuilder<E, T, P> {
423
+ /** Run before the first phase starts */
424
+ beforeFirstGroup(handler: (ctx: PhaseHookContext<E>) => void): this;
425
+
426
+ /** Run before a specific phase starts */
427
+ beforeGroup(phase: P, handler: (ctx: PhaseHookContext<E>) => void): this;
428
+
429
+ /** Run after a specific phase completes */
430
+ afterGroup(phase: P, handler: (ctx: PhaseCompleteContext<E, P>) => void): this;
431
+
432
+ /** Run when a phase fails (only if stopOnFailure is true) */
433
+ onGroupFailed(phase: P, handler: (ctx: PhaseFailedContext<E, P>) => void): this;
434
+
435
+ /** Run after all phases complete */
436
+ afterAll(handler: (ctx: AllCompleteContext<E>) => void): this;
437
+
438
+ /** Start a new event handler */
439
+ on<E2 extends EventType>(eventType: E2): TriggerBuilder<E2>;
440
+
441
+ /** End the pipeline definition */
442
+ build(): Pipeline;
443
+ }
444
+ ```
445
+
446
+ ### 3.8 Context Types
447
+
448
+ ```typescript
449
+ interface ItemContext<E> {
450
+ event: E;
451
+ index: number;
452
+ }
453
+
454
+ interface PhaseHookContext<E> {
455
+ event: E;
456
+ emit<C extends CommandType>(commandType: C, data: CommandData<C>): void;
457
+ }
458
+
459
+ interface PhaseCompleteContext<E, P> {
460
+ event: E;
461
+ phase: P;
462
+ completed: string[]; // Item keys that completed
463
+ emit<C extends CommandType>(commandType: C, data: CommandData<C>): void;
464
+ }
465
+
466
+ interface PhaseFailedContext<E, P> {
467
+ event: E;
468
+ phase: P;
469
+ failed: string[]; // Item keys that failed
470
+ completed: string[]; // Item keys that completed
471
+ emit<C extends CommandType>(commandType: C, data: CommandData<C>): void;
472
+ }
473
+
474
+ interface AllCompleteContext<E> {
475
+ event: E;
476
+ phases: { phase: string; completed: string[] }[];
477
+ emit<C extends CommandType>(commandType: C, data: CommandData<C>): void;
478
+ }
479
+ ```
480
+
481
+ ### 3.9 Handler Context (for `.handle()`)
482
+
483
+ ```typescript
484
+ interface HandlerContext {
485
+ /** Emit a command */
486
+ emit<C extends CommandType>(commandType: C, data: CommandData<C>): void;
487
+
488
+ /** Run state (if declared with .withState()) */
489
+ state: S;
490
+
491
+ /** Run metadata */
492
+ runId: string;
493
+ eventId: string;
494
+ timestamp: Date;
495
+ }
496
+ ```
497
+
498
+ ### 3.10 Helper Function
499
+
500
+ ```typescript
501
+ /** Create a command specification */
502
+ function cmd<C extends CommandType>(type: C, data: CommandData<C> | ((event: Event) => CommandData<C>)): CommandSpec;
503
+ ```
504
+
505
+ ---
506
+
507
+ ## 4. Complete Example: Kanban Pipeline
508
+
509
+ ```typescript
510
+ import { define, cmd } from '@auto-engineer/pipeline';
511
+
512
+ const pipeline = define('kanban-pipeline')
513
+ .version('1.0.0')
514
+ .description('Full-stack Kanban app generation from schema')
515
+
516
+ // Define a reusable correlation key
517
+ .key('bySlice', (e) => e.data.slicePath ?? e.data.targetDirectory ?? '')
518
+
519
+ // ═══════════════════════════════════════════════════════════════════════════
520
+ // PHASE 1: Schema → Server Generation
521
+ // ═══════════════════════════════════════════════════════════════════════════
522
+
523
+ .on('SchemaExported')
524
+ .emit('GenerateServer', {
525
+ modelPath: './.context/schema.json',
526
+ destination: '.',
527
+ })
528
+
529
+ // ═══════════════════════════════════════════════════════════════════════════
530
+ // PHASE 1b: Implement Each Slice
531
+ // ═══════════════════════════════════════════════════════════════════════════
532
+
533
+ .on('SliceGenerated')
534
+ .emit('ImplementSlice', (e) => ({
535
+ slicePath: e.data.slicePath,
536
+ context: {
537
+ attemptNumber: 0,
538
+ previousOutputs: 'errors',
539
+ },
540
+ aiOptions: { maxTokens: 2000 },
541
+ }))
542
+
543
+ // ═══════════════════════════════════════════════════════════════════════════
544
+ // PHASE 1c: Check & Retry Loop
545
+ // "Run all checks. If any fail, retry the slice implementation."
546
+ // ═══════════════════════════════════════════════════════════════════════════
547
+
548
+ .on('SliceImplemented')
549
+ .run((e) => [
550
+ cmd('CheckTests', { targetDirectory: e.data.slicePath, scope: 'slice' }),
551
+ cmd('CheckTypes', { targetDirectory: e.data.slicePath, scope: 'slice' }),
552
+ cmd('CheckLint', { targetDirectory: e.data.slicePath, scope: 'slice', fix: true }),
553
+ ])
554
+ .awaitAll({ key: 'bySlice', timeout: 300_000 })
555
+ .onFailure((ctx) => {
556
+ ctx.retry('ImplementSlice', {
557
+ maxAttempts: 5,
558
+ backoff: 'exponential',
559
+ backoffMs: 1000,
560
+ data: {
561
+ slicePath: ctx.key,
562
+ context: {
563
+ attemptNumber: ctx.attempt,
564
+ previousOutputs: ctx.errorText,
565
+ },
566
+ aiOptions: { maxTokens: 2000 },
567
+ },
568
+ });
569
+ })
570
+
571
+ // ═══════════════════════════════════════════════════════════════════════════
572
+ // PHASE 2: Server Generated → IA + Dev Server (Parallel)
573
+ // ═══════════════════════════════════════════════════════════════════════════
574
+
575
+ .on('ServerGenerated')
576
+ .emit('GenerateIA', {
577
+ modelPath: './.context/schema.json',
578
+ outputDir: './.context',
579
+ })
580
+ .emit('StartServer', {
581
+ serverDirectory: './server',
582
+ })
583
+
584
+ // ═══════════════════════════════════════════════════════════════════════════
585
+ // PHASE 3: IA Generated → Client Generation
586
+ // ═══════════════════════════════════════════════════════════════════════════
587
+
588
+ .on('IAGenerated')
589
+ .emit('GenerateClient', {
590
+ targetDir: './client',
591
+ iaSchemaPath: './.context/auto-ia-scheme.json',
592
+ gqlSchemaPath: './.context/schema.graphql',
593
+ figmaVariablesPath: './.context/figma-file.json',
594
+ })
595
+
596
+ // ═══════════════════════════════════════════════════════════════════════════
597
+ // PHASE 4a: Client Generated — Fallback for malformed data
598
+ // ═══════════════════════════════════════════════════════════════════════════
599
+
600
+ .on('ClientGenerated')
601
+ .when((e) => !e.data?.components?.length)
602
+ .emit('ImplementComponent', {
603
+ projectDir: './client',
604
+ iaSchemeDir: './.context',
605
+ designSystemPath: './.context/design-system.md',
606
+ componentType: 'molecule',
607
+ filePath: 'client/src/components/molecules/Example.tsx',
608
+ componentName: 'Example.tsx',
609
+ aiOptions: { maxTokens: 3000 },
610
+ })
611
+ .emit('StartClient', { clientDirectory: './client' })
612
+
613
+ // ═══════════════════════════════════════════════════════════════════════════
614
+ // PHASE 4b: Client Generated — Phased Component Implementation
615
+ // "For each component, group into phases, run sequentially."
616
+ // ═══════════════════════════════════════════════════════════════════════════
617
+
618
+ .on('ClientGenerated')
619
+ .when((e) => e.data?.components?.length > 0)
620
+ .forEach((e) => e.data.components)
621
+ .groupInto(['molecule', 'organism', 'page'], (c) => c.type)
622
+ .runSequentially({ stopOnFailure: true })
623
+ .emit((component, phase, ctx) =>
624
+ cmd('ImplementComponent', {
625
+ projectDir: ctx.event.data.targetDir,
626
+ iaSchemeDir: './.context',
627
+ designSystemPath: './.context/design-system.md',
628
+ componentType: phase,
629
+ filePath: component.filePath,
630
+ componentName: component.filePath.split('/').pop()?.replace('.tsx', '') ?? 'Unknown',
631
+ aiOptions: { maxTokens: 3000 },
632
+ }),
633
+ )
634
+ .completeWhen({
635
+ success: 'ComponentImplemented',
636
+ failure: 'ComponentImplementationFailed',
637
+ key: (e) => e.data.filePath,
638
+ })
639
+ .beforeFirstGroup((ctx) => {
640
+ ctx.emit('StartClient', { clientDirectory: './client' });
641
+ })
642
+
643
+ // ═══════════════════════════════════════════════════════════════════════════
644
+ // PHASE 5: Client Checks → Project-Level Fix
645
+ // ═══════════════════════════════════════════════════════════════════════════
646
+
647
+ .on('ClientChecked')
648
+ .when((e) => e.data.tsErrors > 0 || e.data.buildErrors > 0 || e.data.consoleErrors > 0)
649
+ .emit('ImplementClient', (e) => ({
650
+ projectDir: './client',
651
+ iaSchemeDir: './.context',
652
+ designSystemPath: './.context/design-system.md',
653
+ failures: [
654
+ ...(e.data.tsErrorDetails ?? []),
655
+ ...(e.data.buildErrorDetails ?? []),
656
+ ...(e.data.consoleErrorDetails ?? []),
657
+ ],
658
+ }))
659
+
660
+ .build();
661
+ ```
662
+
663
+ ---
664
+
665
+ ## 5. Side-by-Side Comparison
666
+
667
+ ### Original (Scatter-Gather-Retry): ~50 lines
668
+
669
+ ```typescript
670
+ // Module state
671
+ const sliceRetryState = new Map<string, number>()
672
+ const MAX_RETRIES = 4
673
+
674
+ // Three separate handlers
675
+ on('SliceImplemented', (e) => dispatch('CheckTests', {...}))
676
+ on('SliceImplemented', (e) => dispatch('CheckTypes', {...}))
677
+ on('SliceImplemented', (e) => dispatch('CheckLint', {...}))
678
+
679
+ // Complex aggregation
680
+ on.settled(['CheckTests', 'CheckTypes', 'CheckLint'],
681
+ dispatch(['ImplementSlice'], (events, send) => {
682
+ const failures = findCheckFailures(events)
683
+ const slicePath = getSlicePath(failures, events)
684
+
685
+ if (!hasAnyFailures(failures)) {
686
+ sliceRetryState.delete(slicePath)
687
+ return { persist: false }
688
+ }
689
+
690
+ const currentAttempt = sliceRetryState.get(slicePath) ?? 0
691
+ if (currentAttempt >= MAX_RETRIES) {
692
+ sliceRetryState.delete(slicePath)
693
+ return { persist: false }
694
+ }
695
+
696
+ sliceRetryState.set(slicePath, currentAttempt + 1)
697
+ send({
698
+ type: 'ImplementSlice',
699
+ data: {
700
+ slicePath,
701
+ context: {
702
+ attemptNumber: currentAttempt + 1,
703
+ previousOutputs: collectErrorMessages(failures),
704
+ },
705
+ },
706
+ })
707
+ return { persist: true }
708
+ })
709
+ )
710
+
711
+ // Plus 4 helper functions (~30 lines)
712
+ function findCheckFailures(events) {...}
713
+ function hasAnyFailures(failures) {...}
714
+ function getSlicePath(failures, events) {...}
715
+ function collectErrorMessages(failures) {...}
716
+ ```
717
+
718
+ ### New: 14 lines
719
+
720
+ ```typescript
721
+ .on('SliceImplemented')
722
+ .run(e => [
723
+ cmd('CheckTests', { targetDirectory: e.data.slicePath, scope: 'slice' }),
724
+ cmd('CheckTypes', { targetDirectory: e.data.slicePath, scope: 'slice' }),
725
+ cmd('CheckLint', { targetDirectory: e.data.slicePath, scope: 'slice', fix: true }),
726
+ ])
727
+ .awaitAll({ key: 'bySlice', timeout: 300_000 })
728
+ .onFailure(ctx => {
729
+ ctx.retry('ImplementSlice', {
730
+ maxAttempts: 5,
731
+ backoff: 'exponential',
732
+ data: {
733
+ slicePath: ctx.key,
734
+ context: { attemptNumber: ctx.attempt, previousOutputs: ctx.errorText },
735
+ },
736
+ })
737
+ })
738
+ ```
739
+
740
+ ### Original (Phased Execution): ~70 lines
741
+
742
+ ```typescript
743
+ // Module state
744
+ let clientComponents = []
745
+ let clientTargetDir = ''
746
+ const processedComponents = new Set()
747
+ const dispatchedPhases = new Set()
748
+ const failedComponents = new Set()
749
+ const componentPhaseOrder = ['molecule', 'organism', 'page']
750
+
751
+ // Handler
752
+ on('ClientGenerated', (e) => {
753
+ clientComponents = e.data.components
754
+ clientTargetDir = e.data.targetDir
755
+ processedComponents.clear()
756
+ dispatchedPhases.clear()
757
+ failedComponents.clear()
758
+ dispatchedPhases.add('molecule')
759
+
760
+ const molecules = clientComponents.filter(c => c.type === 'molecule')
761
+ const commands = molecules.map(c => dispatch('ImplementComponent', {...}))
762
+ return dispatch.parallel([...commands, dispatch('StartClient', {...})])
763
+ })
764
+
765
+ on('ComponentImplemented', (e) => {
766
+ processedComponents.add(e.data.filePath)
767
+ return tryAdvanceToNextPhase()
768
+ })
769
+
770
+ on('ComponentImplementationFailed', (e) => {
771
+ failedComponents.add(e.data.filePath)
772
+ return tryAdvanceToNextPhase()
773
+ })
774
+
775
+ // Plus 4 helper functions (~40 lines)
776
+ function getComponentsOfType(type) {...}
777
+ function areAllProcessed(type) {...}
778
+ function dispatchComponentsOfType(type) {...}
779
+ function tryAdvanceToNextPhase() {...}
780
+ ```
781
+
782
+ ### New: 18 lines
783
+
784
+ ```typescript
785
+ .on('ClientGenerated')
786
+ .when(e => e.data?.components?.length > 0)
787
+ .forEach(e => e.data.components)
788
+ .groupInto(['molecule', 'organism', 'page'], c => c.type)
789
+ .runSequentially({ stopOnFailure: true })
790
+ .emit((component, phase, ctx) => cmd('ImplementComponent', {
791
+ projectDir: ctx.event.data.targetDir,
792
+ componentType: phase,
793
+ filePath: component.filePath,
794
+ componentName: component.filePath.split('/').pop()?.replace('.tsx', ''),
795
+ aiOptions: { maxTokens: 3000 },
796
+ }))
797
+ .completeWhen({
798
+ success: 'ComponentImplemented',
799
+ failure: 'ComponentImplementationFailed',
800
+ key: e => e.data.filePath,
801
+ })
802
+ .beforeFirstGroup(ctx => {
803
+ ctx.emit('StartClient', { clientDirectory: './client' })
804
+ })
805
+ ```
806
+
807
+ ### Summary
808
+
809
+ | Metric | Original | New |
810
+ | ---------------------- | ---------- | --------- |
811
+ | Scatter-Gather-Retry | ~80 lines | 14 lines |
812
+ | Phased Execution | ~110 lines | 18 lines |
813
+ | Module state variables | 7 | 0 |
814
+ | Helper functions | 8 | 0 |
815
+ | Total | ~220 lines | ~60 lines |
816
+
817
+ ---
818
+
819
+ ## 6. Graph Extraction
820
+
821
+ Every fluent construct produces a graph node:
822
+
823
+ ```typescript
824
+ const graph = pipeline.toGraph();
825
+ ```
826
+
827
+ ### Graph IR Structure
828
+
829
+ ```typescript
830
+ interface GraphIR {
831
+ nodes: GraphNode[];
832
+ edges: GraphEdge[];
833
+ }
834
+
835
+ interface GraphNode {
836
+ id: string;
837
+ type: 'trigger' | 'emit' | 'run' | 'await' | 'retry' | 'forEach' | 'phase' | 'track' | 'handler';
838
+ label: string;
839
+ config: Record<string, unknown>;
840
+ }
841
+
842
+ interface GraphEdge {
843
+ from: string;
844
+ to: string;
845
+ type: 'triggers' | 'produces' | 'onSuccess' | 'onFailure' | 'retries' | 'nextPhase';
846
+ label?: string;
847
+ }
848
+ ```
849
+
850
+ ### Example Output
851
+
852
+ ```json
853
+ {
854
+ "nodes": [
855
+ { "id": "t1", "type": "trigger", "label": "SliceImplemented" },
856
+ {
857
+ "id": "r1",
858
+ "type": "run",
859
+ "label": "Run Checks",
860
+ "config": { "commands": ["CheckTests", "CheckTypes", "CheckLint"] }
861
+ },
862
+ { "id": "a1", "type": "await", "label": "Await All", "config": { "key": "bySlice", "timeout": 300000 } },
863
+ {
864
+ "id": "y1",
865
+ "type": "retry",
866
+ "label": "Retry ImplementSlice",
867
+ "config": { "command": "ImplementSlice", "maxAttempts": 5 }
868
+ },
869
+
870
+ { "id": "t2", "type": "trigger", "label": "ClientGenerated" },
871
+ { "id": "f1", "type": "forEach", "label": "For Each Component" },
872
+ { "id": "p1", "type": "phase", "label": "Phase: molecule" },
873
+ { "id": "p2", "type": "phase", "label": "Phase: organism" },
874
+ { "id": "p3", "type": "phase", "label": "Phase: page" },
875
+ { "id": "k1", "type": "track", "label": "Track Completion" }
876
+ ],
877
+ "edges": [
878
+ { "from": "t1", "to": "r1", "type": "triggers" },
879
+ { "from": "r1", "to": "a1", "type": "produces" },
880
+ { "from": "a1", "to": "y1", "type": "onFailure" },
881
+ { "from": "y1", "to": "t1", "type": "retries", "label": "ImplementSlice" },
882
+
883
+ { "from": "t2", "to": "f1", "type": "triggers" },
884
+ { "from": "f1", "to": "p1", "type": "produces" },
885
+ { "from": "p1", "to": "k1", "type": "produces" },
886
+ { "from": "k1", "to": "p2", "type": "nextPhase" },
887
+ { "from": "p2", "to": "k1", "type": "produces" },
888
+ { "from": "k1", "to": "p3", "type": "nextPhase" }
889
+ ]
890
+ }
891
+ ```
892
+
893
+ ### Visualization
894
+
895
+ ```
896
+ ┌──────────────────────────────────────────────────────────────────┐
897
+ │ Scatter-Gather-Retry │
898
+ │ │
899
+ │ ┌─────────────────┐ │
900
+ │ │SliceImplemented │ │
901
+ │ └────────┬────────┘ │
902
+ │ │ │
903
+ │ ▼ │
904
+ │ ┌─────────────────┐ │
905
+ │ │ Run Checks │ ─────┬─────┬─────┐ │
906
+ │ └────────┬────────┘ │ │ │ │
907
+ │ │ ▼ ▼ ▼ │
908
+ │ │ Tests Types Lint │
909
+ │ │ │ │ │ │
910
+ │ │ └─────┴─────┘ │
911
+ │ ▼ │ │
912
+ │ ┌─────────────────┐ │ │
913
+ │ │ Await All │◄───────────┘ │
914
+ │ │ (by slice) │ │
915
+ │ └────────┬────────┘ │
916
+ │ │ │
917
+ │ ┌─────┴─────┐ │
918
+ │ ▼ ▼ │
919
+ │ [Success] [Failure] │
920
+ │ │ │ │
921
+ │ │ ▼ │
922
+ │ │ ┌─────────────┐ │
923
+ │ │ │ Retry │──────────┐ │
924
+ │ │ │ImplementSlice│ │ │
925
+ │ │ └─────────────┘ │ │
926
+ │ │ ▲ │ │
927
+ │ │ └─────────────────┘ │
928
+ │ ▼ (loop) │
929
+ │ [ Done ] │
930
+ └──────────────────────────────────────────────────────────────────┘
931
+
932
+ ┌──────────────────────────────────────────────────────────────────┐
933
+ │ Phased Execution │
934
+ │ │
935
+ │ ┌─────────────────┐ │
936
+ │ │ ClientGenerated │ │
937
+ │ └────────┬────────┘ │
938
+ │ │ │
939
+ │ ▼ │
940
+ │ ┌─────────────────┐ │
941
+ │ │ For Each │ │
942
+ │ │ Component │ │
943
+ │ └────────┬────────┘ │
944
+ │ │ │
945
+ │ ┌────────┴────────────────────────────────────────┐ │
946
+ │ │ PHASES │ │
947
+ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
948
+ │ │ │ molecule │──▶│ organism │──▶│ page │ │ │
949
+ │ │ │ (N items)│ │ (N items)│ │ (N items)│ │ │
950
+ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
951
+ │ │ │ │ │ │ │
952
+ │ │ ▼ ▼ ▼ │ │
953
+ │ │ [Track] [Track] [Track] │ │
954
+ │ │ success? success? success? │ │
955
+ │ │ │ │ │ │ │
956
+ │ │ ────┴──────────────┴──────────────┴─── │ │
957
+ │ │ │ stopOnFailure = true │ │ │
958
+ │ │ ▼ ▼ │ │
959
+ │ │ [Continue] [HALT] │ │
960
+ │ └─────────────────────────────────────────────────┘ │
961
+ └──────────────────────────────────────────────────────────────────┘
962
+ ```
963
+
964
+ ---
965
+
966
+ ## 7. Pattern Templates (Optional Extension)
967
+
968
+ For maximum brevity, provide pre-built patterns:
969
+
970
+ ```typescript
971
+ import { define, cmd, patterns } from '@auto-engineer/pipeline';
972
+
973
+ const pipeline = define('kanban-pipeline')
974
+ .on('SliceImplemented')
975
+ .use(
976
+ patterns.checkAndRetry({
977
+ checks: (e) => [
978
+ cmd('CheckTests', { target: e.data.slicePath }),
979
+ cmd('CheckTypes', { target: e.data.slicePath }),
980
+ cmd('CheckLint', { target: e.data.slicePath }),
981
+ ],
982
+ key: (e) => e.data.targetDirectory,
983
+ retryCommand: 'ImplementSlice',
984
+ maxAttempts: 5,
985
+ retryData: (ctx) => ({
986
+ slicePath: ctx.key,
987
+ context: { attempt: ctx.attempt, errors: ctx.errorText },
988
+ }),
989
+ }),
990
+ )
991
+
992
+ .on('ClientGenerated')
993
+ .when((e) => e.data?.components?.length > 0)
994
+ .use(
995
+ patterns.phased({
996
+ items: (e) => e.data.components,
997
+ phases: ['molecule', 'organism', 'page'],
998
+ phaseOf: (c) => c.type,
999
+ emit: (c, phase, ctx) =>
1000
+ cmd('ImplementComponent', {
1001
+ filePath: c.filePath,
1002
+ projectDir: ctx.event.data.targetDir,
1003
+ }),
1004
+ track: {
1005
+ success: 'ComponentImplemented',
1006
+ failure: 'ComponentImplementationFailed',
1007
+ key: (e) => e.data.filePath,
1008
+ },
1009
+ stopOnFailure: true,
1010
+ beforeFirstPhase: (ctx) => ctx.emit('StartClient', {}),
1011
+ }),
1012
+ )
1013
+
1014
+ .build();
1015
+ ```
1016
+
1017
+ ---
1018
+
1019
+ ## 8. Runtime Behavior
1020
+
1021
+ ### 8.1 Execution Flow
1022
+
1023
+ ```
1024
+ 1. Event arrives (e.g., SliceImplemented)
1025
+ 2. Find matching .on() handlers
1026
+ 3. For each handler:
1027
+ a. Evaluate .when() predicate
1028
+ b. If passes, execute the chain:
1029
+ - .emit() → queue command(s)
1030
+ - .run() → queue multiple commands
1031
+ - .awaitAll() → register barrier
1032
+ - .forEach() → expand items, register phase tracking
1033
+ c. Execute queued commands via plugins
1034
+ d. Plugins emit completion events
1035
+ 4. Barrier evaluation:
1036
+ - .awaitAll() checks if all commands for key completed
1037
+ - If complete: invoke .onSuccess() or .onFailure()
1038
+ - .onFailure() may call ctx.retry() → queue retry command
1039
+ 5. Phase tracking:
1040
+ - Track item completion events
1041
+ - When phase complete: check stopOnFailure, advance to next
1042
+ 6. Loop until no more events to process
1043
+ ```
1044
+
1045
+ ### 8.2 State Management
1046
+
1047
+ The runtime manages all state internally:
1048
+
1049
+ | State | Managed By | User Visible? |
1050
+ | -------------------- | -------------------------------- | ----------------- |
1051
+ | Retry attempt counts | `.awaitAll().onFailure()` | Via `ctx.attempt` |
1052
+ | Correlation groups | `.awaitAll({ key: ... })` | Via `ctx.key` |
1053
+ | Phase progress | `.groupInto().runSequentially()` | Via phase hooks |
1054
+ | Item completion | `.completeWhen()` | Via phase hooks |
1055
+
1056
+ No module-level state needed in user code.
1057
+
1058
+ ---
1059
+
1060
+ ## 9. Summary
1061
+
1062
+ The Pipeline API provides:
1063
+
1064
+ | Level | API | Use Case |
1065
+ | -------------- | ------------------------------------------ | ----------------- |
1066
+ | Simple | `.on().emit()` | Event → Command |
1067
+ | Parallel | `.emit().emit()` | Multiple commands |
1068
+ | Scatter-Gather | `.run().awaitAll().onFailure()` | Check & retry |
1069
+ | Phased | `.forEach().groupInto().runSequentially()` | Sequential phases |
1070
+ | Custom | `.handle()` | Unique logic |
1071
+
1072
+ **Key benefits:**
1073
+
1074
+ - **70% less code** than original
1075
+ - **Zero manual state** management
1076
+ - **Reads like English** — `.run().awaitAll().onFailure()`
1077
+ - **Static graph extraction** for visualization
1078
+ - **Runs anywhere** — local and cloud