@renseiai/agentfactory 0.8.7 → 0.8.9

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 (276) hide show
  1. package/dist/src/config/index.d.ts +1 -1
  2. package/dist/src/config/index.d.ts.map +1 -1
  3. package/dist/src/config/index.js +1 -1
  4. package/dist/src/config/repository-config.d.ts +37 -0
  5. package/dist/src/config/repository-config.d.ts.map +1 -1
  6. package/dist/src/config/repository-config.js +47 -0
  7. package/dist/src/config/repository-config.test.js +140 -1
  8. package/dist/src/governor/decision-engine.d.ts +3 -0
  9. package/dist/src/governor/decision-engine.d.ts.map +1 -1
  10. package/dist/src/governor/decision-engine.js +11 -0
  11. package/dist/src/governor/decision-engine.test.js +33 -0
  12. package/dist/src/governor/event-types.d.ts +18 -1
  13. package/dist/src/governor/event-types.d.ts.map +1 -1
  14. package/dist/src/governor/event-types.js +4 -0
  15. package/dist/src/governor/governor-types.d.ts +1 -1
  16. package/dist/src/governor/governor-types.d.ts.map +1 -1
  17. package/dist/src/governor/governor.d.ts +17 -1
  18. package/dist/src/governor/governor.d.ts.map +1 -1
  19. package/dist/src/governor/governor.js +112 -1
  20. package/dist/src/governor/governor.test.js +155 -0
  21. package/dist/src/index.d.ts +1 -0
  22. package/dist/src/index.d.ts.map +1 -1
  23. package/dist/src/index.js +1 -0
  24. package/dist/src/merge-queue/adapters/github-native.d.ts +22 -0
  25. package/dist/src/merge-queue/adapters/github-native.d.ts.map +1 -0
  26. package/dist/src/merge-queue/adapters/github-native.js +243 -0
  27. package/dist/src/merge-queue/adapters/github-native.test.d.ts +2 -0
  28. package/dist/src/merge-queue/adapters/github-native.test.d.ts.map +1 -0
  29. package/dist/src/merge-queue/adapters/github-native.test.js +384 -0
  30. package/dist/src/merge-queue/index.d.ts +18 -0
  31. package/dist/src/merge-queue/index.d.ts.map +1 -0
  32. package/dist/src/merge-queue/index.js +28 -0
  33. package/dist/src/merge-queue/merge-queue.integration.test.d.ts +2 -0
  34. package/dist/src/merge-queue/merge-queue.integration.test.d.ts.map +1 -0
  35. package/dist/src/merge-queue/merge-queue.integration.test.js +128 -0
  36. package/dist/src/merge-queue/types.d.ts +48 -0
  37. package/dist/src/merge-queue/types.d.ts.map +1 -0
  38. package/dist/src/merge-queue/types.js +8 -0
  39. package/dist/src/orchestrator/artifact-tracker.d.ts +93 -0
  40. package/dist/src/orchestrator/artifact-tracker.d.ts.map +1 -0
  41. package/dist/src/orchestrator/artifact-tracker.js +235 -0
  42. package/dist/src/orchestrator/artifact-tracker.test.d.ts +2 -0
  43. package/dist/src/orchestrator/artifact-tracker.test.d.ts.map +1 -0
  44. package/dist/src/orchestrator/artifact-tracker.test.js +189 -0
  45. package/dist/src/orchestrator/context-manager.d.ts +72 -0
  46. package/dist/src/orchestrator/context-manager.d.ts.map +1 -0
  47. package/dist/src/orchestrator/context-manager.js +120 -0
  48. package/dist/src/orchestrator/context-manager.test.d.ts +2 -0
  49. package/dist/src/orchestrator/context-manager.test.d.ts.map +1 -0
  50. package/dist/src/orchestrator/context-manager.test.js +137 -0
  51. package/dist/src/orchestrator/index.d.ts +8 -2
  52. package/dist/src/orchestrator/index.d.ts.map +1 -1
  53. package/dist/src/orchestrator/index.js +8 -1
  54. package/dist/src/orchestrator/issue-tracker-client.d.ts +4 -0
  55. package/dist/src/orchestrator/issue-tracker-client.d.ts.map +1 -1
  56. package/dist/src/orchestrator/orchestrator.d.ts +12 -0
  57. package/dist/src/orchestrator/orchestrator.d.ts.map +1 -1
  58. package/dist/src/orchestrator/orchestrator.js +282 -2
  59. package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -1
  60. package/dist/src/orchestrator/parse-work-result.js +6 -0
  61. package/dist/src/orchestrator/parse-work-result.test.js +19 -0
  62. package/dist/src/orchestrator/state-recovery.d.ts +21 -2
  63. package/dist/src/orchestrator/state-recovery.d.ts.map +1 -1
  64. package/dist/src/orchestrator/state-recovery.js +54 -2
  65. package/dist/src/orchestrator/state-recovery.test.js +106 -2
  66. package/dist/src/orchestrator/state-types.d.ts +62 -0
  67. package/dist/src/orchestrator/state-types.d.ts.map +1 -1
  68. package/dist/src/orchestrator/state-types.js +5 -1
  69. package/dist/src/orchestrator/summary-builder.d.ts +47 -0
  70. package/dist/src/orchestrator/summary-builder.d.ts.map +1 -0
  71. package/dist/src/orchestrator/summary-builder.js +240 -0
  72. package/dist/src/orchestrator/summary-builder.test.d.ts +2 -0
  73. package/dist/src/orchestrator/summary-builder.test.d.ts.map +1 -0
  74. package/dist/src/orchestrator/summary-builder.test.js +236 -0
  75. package/dist/src/orchestrator/types.d.ts +2 -0
  76. package/dist/src/orchestrator/types.d.ts.map +1 -1
  77. package/dist/src/orchestrator/work-types.d.ts +1 -1
  78. package/dist/src/orchestrator/work-types.d.ts.map +1 -1
  79. package/dist/src/providers/index.d.ts +64 -1
  80. package/dist/src/providers/index.d.ts.map +1 -1
  81. package/dist/src/providers/index.js +132 -1
  82. package/dist/src/providers/index.test.js +340 -2
  83. package/dist/src/routing/index.d.ts +7 -0
  84. package/dist/src/routing/index.d.ts.map +1 -0
  85. package/dist/src/routing/index.js +6 -0
  86. package/dist/src/routing/observation-recorder.d.ts +19 -0
  87. package/dist/src/routing/observation-recorder.d.ts.map +1 -0
  88. package/dist/src/routing/observation-recorder.js +73 -0
  89. package/dist/src/routing/observation-recorder.test.d.ts +2 -0
  90. package/dist/src/routing/observation-recorder.test.d.ts.map +1 -0
  91. package/dist/src/routing/observation-recorder.test.js +322 -0
  92. package/dist/src/routing/observation-store.d.ts +40 -0
  93. package/dist/src/routing/observation-store.d.ts.map +1 -0
  94. package/dist/src/routing/observation-store.js +1 -0
  95. package/dist/src/routing/observation-store.test.d.ts +2 -0
  96. package/dist/src/routing/observation-store.test.d.ts.map +1 -0
  97. package/dist/src/routing/observation-store.test.js +138 -0
  98. package/dist/src/routing/posterior-store.d.ts +12 -0
  99. package/dist/src/routing/posterior-store.d.ts.map +1 -0
  100. package/dist/src/routing/posterior-store.js +13 -0
  101. package/dist/src/routing/posterior-store.test.d.ts +2 -0
  102. package/dist/src/routing/posterior-store.test.d.ts.map +1 -0
  103. package/dist/src/routing/posterior-store.test.js +37 -0
  104. package/dist/src/routing/reward.d.ts +16 -0
  105. package/dist/src/routing/reward.d.ts.map +1 -0
  106. package/dist/src/routing/reward.js +29 -0
  107. package/dist/src/routing/reward.test.d.ts +2 -0
  108. package/dist/src/routing/reward.test.d.ts.map +1 -0
  109. package/dist/src/routing/reward.test.js +210 -0
  110. package/dist/src/routing/routing-engine.d.ts +20 -0
  111. package/dist/src/routing/routing-engine.d.ts.map +1 -0
  112. package/dist/src/routing/routing-engine.js +113 -0
  113. package/dist/src/routing/routing-engine.test.d.ts +2 -0
  114. package/dist/src/routing/routing-engine.test.d.ts.map +1 -0
  115. package/dist/src/routing/routing-engine.test.js +310 -0
  116. package/dist/src/routing/types.d.ts +157 -0
  117. package/dist/src/routing/types.d.ts.map +1 -0
  118. package/dist/src/routing/types.js +68 -0
  119. package/dist/src/routing/types.test.d.ts +2 -0
  120. package/dist/src/routing/types.test.d.ts.map +1 -0
  121. package/dist/src/routing/types.test.js +184 -0
  122. package/dist/src/templates/registry.test.js +2 -2
  123. package/dist/src/templates/types.d.ts +5 -0
  124. package/dist/src/templates/types.d.ts.map +1 -1
  125. package/dist/src/templates/types.js +3 -0
  126. package/dist/src/workflow/agent-cancellation.d.ts +37 -0
  127. package/dist/src/workflow/agent-cancellation.d.ts.map +1 -0
  128. package/dist/src/workflow/agent-cancellation.js +41 -0
  129. package/dist/src/workflow/agent-cancellation.test.d.ts +2 -0
  130. package/dist/src/workflow/agent-cancellation.test.d.ts.map +1 -0
  131. package/dist/src/workflow/agent-cancellation.test.js +86 -0
  132. package/dist/src/workflow/branching-router.d.ts +38 -0
  133. package/dist/src/workflow/branching-router.d.ts.map +1 -0
  134. package/dist/src/workflow/branching-router.js +52 -0
  135. package/dist/src/workflow/branching-router.test.d.ts +2 -0
  136. package/dist/src/workflow/branching-router.test.d.ts.map +1 -0
  137. package/dist/src/workflow/branching-router.test.js +209 -0
  138. package/dist/src/workflow/concurrency-semaphore.d.ts +21 -0
  139. package/dist/src/workflow/concurrency-semaphore.d.ts.map +1 -0
  140. package/dist/src/workflow/concurrency-semaphore.js +46 -0
  141. package/dist/src/workflow/concurrency-semaphore.test.d.ts +2 -0
  142. package/dist/src/workflow/concurrency-semaphore.test.d.ts.map +1 -0
  143. package/dist/src/workflow/concurrency-semaphore.test.js +183 -0
  144. package/dist/src/workflow/duration.d.ts +28 -0
  145. package/dist/src/workflow/duration.d.ts.map +1 -0
  146. package/dist/src/workflow/duration.js +57 -0
  147. package/dist/src/workflow/duration.test.d.ts +2 -0
  148. package/dist/src/workflow/duration.test.d.ts.map +1 -0
  149. package/dist/src/workflow/duration.test.js +74 -0
  150. package/dist/src/workflow/expression/ast.d.ts +53 -0
  151. package/dist/src/workflow/expression/ast.d.ts.map +1 -0
  152. package/dist/src/workflow/expression/ast.js +8 -0
  153. package/dist/src/workflow/expression/context.d.ts +40 -0
  154. package/dist/src/workflow/expression/context.d.ts.map +1 -0
  155. package/dist/src/workflow/expression/context.js +37 -0
  156. package/dist/src/workflow/expression/evaluator.d.ts +28 -0
  157. package/dist/src/workflow/expression/evaluator.d.ts.map +1 -0
  158. package/dist/src/workflow/expression/evaluator.js +165 -0
  159. package/dist/src/workflow/expression/evaluator.test.d.ts +2 -0
  160. package/dist/src/workflow/expression/evaluator.test.d.ts.map +1 -0
  161. package/dist/src/workflow/expression/evaluator.test.js +792 -0
  162. package/dist/src/workflow/expression/expression.test.d.ts +2 -0
  163. package/dist/src/workflow/expression/expression.test.d.ts.map +1 -0
  164. package/dist/src/workflow/expression/expression.test.js +516 -0
  165. package/dist/src/workflow/expression/helpers.d.ts +21 -0
  166. package/dist/src/workflow/expression/helpers.d.ts.map +1 -0
  167. package/dist/src/workflow/expression/helpers.js +56 -0
  168. package/dist/src/workflow/expression/index.d.ts +55 -0
  169. package/dist/src/workflow/expression/index.d.ts.map +1 -0
  170. package/dist/src/workflow/expression/index.js +71 -0
  171. package/dist/src/workflow/expression/lexer.d.ts +37 -0
  172. package/dist/src/workflow/expression/lexer.d.ts.map +1 -0
  173. package/dist/src/workflow/expression/lexer.js +166 -0
  174. package/dist/src/workflow/expression/parser.d.ts +23 -0
  175. package/dist/src/workflow/expression/parser.d.ts.map +1 -0
  176. package/dist/src/workflow/expression/parser.js +181 -0
  177. package/dist/src/workflow/gate-state.d.ts +115 -0
  178. package/dist/src/workflow/gate-state.d.ts.map +1 -0
  179. package/dist/src/workflow/gate-state.js +185 -0
  180. package/dist/src/workflow/gate-state.test.d.ts +2 -0
  181. package/dist/src/workflow/gate-state.test.d.ts.map +1 -0
  182. package/dist/src/workflow/gate-state.test.js +251 -0
  183. package/dist/src/workflow/gates/gate-evaluator.d.ts +119 -0
  184. package/dist/src/workflow/gates/gate-evaluator.d.ts.map +1 -0
  185. package/dist/src/workflow/gates/gate-evaluator.js +243 -0
  186. package/dist/src/workflow/gates/gate-evaluator.test.d.ts +2 -0
  187. package/dist/src/workflow/gates/gate-evaluator.test.d.ts.map +1 -0
  188. package/dist/src/workflow/gates/gate-evaluator.test.js +240 -0
  189. package/dist/src/workflow/gates/signal-gate.d.ts +114 -0
  190. package/dist/src/workflow/gates/signal-gate.d.ts.map +1 -0
  191. package/dist/src/workflow/gates/signal-gate.js +216 -0
  192. package/dist/src/workflow/gates/signal-gate.test.d.ts +2 -0
  193. package/dist/src/workflow/gates/signal-gate.test.d.ts.map +1 -0
  194. package/dist/src/workflow/gates/signal-gate.test.js +199 -0
  195. package/dist/src/workflow/gates/timeout-engine.d.ts +96 -0
  196. package/dist/src/workflow/gates/timeout-engine.d.ts.map +1 -0
  197. package/dist/src/workflow/gates/timeout-engine.js +162 -0
  198. package/dist/src/workflow/gates/timeout-engine.test.d.ts +2 -0
  199. package/dist/src/workflow/gates/timeout-engine.test.d.ts.map +1 -0
  200. package/dist/src/workflow/gates/timeout-engine.test.js +186 -0
  201. package/dist/src/workflow/gates/timer-gate.d.ts +125 -0
  202. package/dist/src/workflow/gates/timer-gate.d.ts.map +1 -0
  203. package/dist/src/workflow/gates/timer-gate.js +381 -0
  204. package/dist/src/workflow/gates/timer-gate.test.d.ts +2 -0
  205. package/dist/src/workflow/gates/timer-gate.test.d.ts.map +1 -0
  206. package/dist/src/workflow/gates/timer-gate.test.js +211 -0
  207. package/dist/src/workflow/gates/webhook-gate.d.ts +132 -0
  208. package/dist/src/workflow/gates/webhook-gate.d.ts.map +1 -0
  209. package/dist/src/workflow/gates/webhook-gate.js +216 -0
  210. package/dist/src/workflow/gates/webhook-gate.test.d.ts +2 -0
  211. package/dist/src/workflow/gates/webhook-gate.test.d.ts.map +1 -0
  212. package/dist/src/workflow/gates/webhook-gate.test.js +182 -0
  213. package/dist/src/workflow/index.d.ts +31 -3
  214. package/dist/src/workflow/index.d.ts.map +1 -1
  215. package/dist/src/workflow/index.js +20 -1
  216. package/dist/src/workflow/parallelism-executor.d.ts +25 -0
  217. package/dist/src/workflow/parallelism-executor.d.ts.map +1 -0
  218. package/dist/src/workflow/parallelism-executor.js +53 -0
  219. package/dist/src/workflow/parallelism-executor.test.d.ts +2 -0
  220. package/dist/src/workflow/parallelism-executor.test.d.ts.map +1 -0
  221. package/dist/src/workflow/parallelism-executor.test.js +191 -0
  222. package/dist/src/workflow/parallelism-types.d.ts +80 -0
  223. package/dist/src/workflow/parallelism-types.d.ts.map +1 -0
  224. package/dist/src/workflow/parallelism-types.js +8 -0
  225. package/dist/src/workflow/phase-context-injector.d.ts +29 -0
  226. package/dist/src/workflow/phase-context-injector.d.ts.map +1 -0
  227. package/dist/src/workflow/phase-context-injector.js +43 -0
  228. package/dist/src/workflow/phase-context-injector.test.d.ts +2 -0
  229. package/dist/src/workflow/phase-context-injector.test.d.ts.map +1 -0
  230. package/dist/src/workflow/phase-context-injector.test.js +123 -0
  231. package/dist/src/workflow/phase-output-collector.d.ts +39 -0
  232. package/dist/src/workflow/phase-output-collector.d.ts.map +1 -0
  233. package/dist/src/workflow/phase-output-collector.js +141 -0
  234. package/dist/src/workflow/phase-output-collector.test.d.ts +2 -0
  235. package/dist/src/workflow/phase-output-collector.test.d.ts.map +1 -0
  236. package/dist/src/workflow/phase-output-collector.test.js +179 -0
  237. package/dist/src/workflow/retry-resolver.d.ts +51 -0
  238. package/dist/src/workflow/retry-resolver.d.ts.map +1 -0
  239. package/dist/src/workflow/retry-resolver.js +70 -0
  240. package/dist/src/workflow/retry-resolver.test.d.ts +2 -0
  241. package/dist/src/workflow/retry-resolver.test.d.ts.map +1 -0
  242. package/dist/src/workflow/retry-resolver.test.js +149 -0
  243. package/dist/src/workflow/strategies/fan-in-strategy.d.ts +21 -0
  244. package/dist/src/workflow/strategies/fan-in-strategy.d.ts.map +1 -0
  245. package/dist/src/workflow/strategies/fan-in-strategy.js +92 -0
  246. package/dist/src/workflow/strategies/fan-in-strategy.test.d.ts +2 -0
  247. package/dist/src/workflow/strategies/fan-in-strategy.test.d.ts.map +1 -0
  248. package/dist/src/workflow/strategies/fan-in-strategy.test.js +182 -0
  249. package/dist/src/workflow/strategies/fan-out-strategy.d.ts +16 -0
  250. package/dist/src/workflow/strategies/fan-out-strategy.d.ts.map +1 -0
  251. package/dist/src/workflow/strategies/fan-out-strategy.js +47 -0
  252. package/dist/src/workflow/strategies/fan-out-strategy.test.d.ts +2 -0
  253. package/dist/src/workflow/strategies/fan-out-strategy.test.d.ts.map +1 -0
  254. package/dist/src/workflow/strategies/fan-out-strategy.test.js +97 -0
  255. package/dist/src/workflow/strategies/index.d.ts +4 -0
  256. package/dist/src/workflow/strategies/index.d.ts.map +1 -0
  257. package/dist/src/workflow/strategies/index.js +3 -0
  258. package/dist/src/workflow/strategies/race-strategy.d.ts +19 -0
  259. package/dist/src/workflow/strategies/race-strategy.d.ts.map +1 -0
  260. package/dist/src/workflow/strategies/race-strategy.js +92 -0
  261. package/dist/src/workflow/strategies/race-strategy.test.d.ts +2 -0
  262. package/dist/src/workflow/strategies/race-strategy.test.d.ts.map +1 -0
  263. package/dist/src/workflow/strategies/race-strategy.test.js +318 -0
  264. package/dist/src/workflow/transition-engine.d.ts +3 -1
  265. package/dist/src/workflow/transition-engine.d.ts.map +1 -1
  266. package/dist/src/workflow/transition-engine.js +26 -7
  267. package/dist/src/workflow/transition-engine.test.js +215 -11
  268. package/dist/src/workflow/workflow-registry.d.ts +46 -1
  269. package/dist/src/workflow/workflow-registry.d.ts.map +1 -1
  270. package/dist/src/workflow/workflow-registry.js +74 -0
  271. package/dist/src/workflow/workflow-registry.test.js +54 -0
  272. package/dist/src/workflow/workflow-types.d.ts +330 -12
  273. package/dist/src/workflow/workflow-types.d.ts.map +1 -1
  274. package/dist/src/workflow/workflow-types.js +100 -5
  275. package/dist/src/workflow/workflow-types.test.js +293 -2
  276. package/package.json +2 -2
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Webhook Gate Executor
3
+ *
4
+ * Pure logic for webhook gate evaluation, token generation, and callback URL
5
+ * management. Webhook gates pause workflow execution until an external HTTP
6
+ * callback is received, enabling integration with external approval systems,
7
+ * CI/CD pipelines, and other services.
8
+ *
9
+ * This module handles the evaluation and state management logic only.
10
+ * The actual HTTP endpoint registration happens in the server layer (SUP-1299).
11
+ */
12
+ import type { GateState } from '../gate-state.js';
13
+ import type { GateDefinition, WorkflowDefinition } from '../workflow-types.js';
14
+ /**
15
+ * Trigger configuration for a webhook gate.
16
+ * Defines the base endpoint path for webhook callbacks.
17
+ */
18
+ export interface WebhookGateTrigger {
19
+ /** Base path for webhook callbacks (e.g., "/api/gates") */
20
+ endpoint: string;
21
+ }
22
+ /**
23
+ * Result of evaluating a webhook gate's current status.
24
+ */
25
+ export interface WebhookGateResult {
26
+ /** Whether the gate condition has been satisfied */
27
+ satisfied: boolean;
28
+ /** The callback URL for an active webhook gate */
29
+ callbackUrl?: string;
30
+ /** Whether the gate has timed out */
31
+ timedOut?: boolean;
32
+ }
33
+ /**
34
+ * Activation data for a webhook gate, including the authentication token,
35
+ * callback URL, and optional expiration timestamp.
36
+ */
37
+ export interface WebhookGateActivation {
38
+ /** Cryptographically random token for webhook authentication */
39
+ token: string;
40
+ /** Full callback URL including token query parameter */
41
+ callbackUrl: string;
42
+ /** When the gate activation expires, epoch ms */
43
+ expiresAt?: number;
44
+ }
45
+ /**
46
+ * Generate a cryptographically random token for webhook authentication.
47
+ *
48
+ * Uses Node.js `crypto.randomBytes()` to generate a 32-byte hex token.
49
+ * This token is stored in gate state and verified on callback receipt
50
+ * to ensure only authorized callers can satisfy the gate.
51
+ *
52
+ * @returns A 64-character hex string token
53
+ */
54
+ export declare function generateWebhookToken(): string;
55
+ /**
56
+ * Build the callback URL for an activated webhook gate.
57
+ *
58
+ * The URL follows the format:
59
+ * `{baseUrl}/api/gates/{issueId}/{gateName}?token={token}`
60
+ *
61
+ * @param baseUrl - The base URL of the server (e.g., "https://api.example.com")
62
+ * @param issueId - The issue identifier this gate is associated with
63
+ * @param gateName - The unique gate name from the gate definition
64
+ * @param token - The authentication token for this gate activation
65
+ * @returns The fully-qualified callback URL
66
+ */
67
+ export declare function buildCallbackUrl(baseUrl: string, issueId: string, gateName: string, token: string): string;
68
+ /**
69
+ * Validate that a webhook callback's token matches the expected token.
70
+ *
71
+ * Uses timing-safe comparison via `crypto.timingSafeEqual` to prevent
72
+ * timing attacks that could leak token information through response times.
73
+ *
74
+ * @param token - The token received in the webhook callback
75
+ * @param expectedToken - The expected token stored in gate state
76
+ * @returns `true` if the tokens match, `false` otherwise
77
+ */
78
+ export declare function validateWebhookCallback(token: string, expectedToken: string): boolean;
79
+ /**
80
+ * Pure function to evaluate a webhook gate's current status based on its
81
+ * definition and persisted state.
82
+ *
83
+ * Evaluation logic:
84
+ * - If gate state is `satisfied` -> return `{ satisfied: true }`
85
+ * - If gate state is `timed-out` -> return `{ satisfied: false, timedOut: true }`
86
+ * - If gate state is `active` and has a timeout deadline that has passed ->
87
+ * return `{ satisfied: false, timedOut: true }`
88
+ * - If gate state is `active` -> return `{ satisfied: false, callbackUrl }`
89
+ * where callbackUrl is reconstructed from state's signalSource if available
90
+ * - If gate state is `null` (not yet activated) -> return `{ satisfied: false }`
91
+ *
92
+ * @param gate - The gate definition from the workflow
93
+ * @param gateState - The persisted gate state, or null if the gate has not been activated
94
+ * @returns The evaluated webhook gate result
95
+ */
96
+ export declare function evaluateWebhookGate(gate: GateDefinition, gateState: GateState | null): WebhookGateResult;
97
+ /**
98
+ * Type guard to check if a gate trigger configuration is a webhook trigger.
99
+ *
100
+ * A valid webhook trigger must have an `endpoint` property of type string.
101
+ *
102
+ * @param trigger - The trigger configuration to check
103
+ * @returns `true` if the trigger is a WebhookGateTrigger
104
+ */
105
+ export declare function isWebhookGateTrigger(trigger: Record<string, unknown>): trigger is Record<string, unknown> & WebhookGateTrigger;
106
+ /**
107
+ * Get all webhook gates that apply to a given workflow phase.
108
+ *
109
+ * Filters the workflow's gate definitions to return only those that:
110
+ * 1. Have type `webhook`
111
+ * 2. Either have no `appliesTo` restriction, or include the specified phase
112
+ *
113
+ * @param workflow - The workflow definition containing gate configurations
114
+ * @param phase - The phase name to filter gates for
115
+ * @returns Array of gate definitions that are webhook type and apply to the phase
116
+ */
117
+ export declare function getApplicableWebhookGates(workflow: WorkflowDefinition, phase: string): GateDefinition[];
118
+ /**
119
+ * Creates the activation data for a webhook gate including a cryptographically
120
+ * random token, callback URL, and optional expiration timestamp.
121
+ *
122
+ * This function generates all the data needed to activate a webhook gate,
123
+ * but does not persist any state. The caller is responsible for storing the
124
+ * activation data (token in gate state, URL communicated to external system).
125
+ *
126
+ * @param issueId - The issue identifier this gate is associated with
127
+ * @param gateDef - The gate definition from the workflow
128
+ * @param baseUrl - The base URL of the server for building callback URLs
129
+ * @returns The webhook gate activation data
130
+ */
131
+ export declare function createWebhookGateActivation(issueId: string, gateDef: GateDefinition, baseUrl: string): WebhookGateActivation;
132
+ //# sourceMappingURL=webhook-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-gate.d.ts","sourceRoot":"","sources":["../../../../src/workflow/gates/webhook-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAa9E;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,SAAS,EAAE,OAAO,CAAA;IAClB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAMR;AAMD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAeT;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,SAAS,GAAG,IAAI,GAC1B,iBAAiB,CAoCnB;AAMD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAOzD;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,kBAAkB,EAC5B,KAAK,EAAE,MAAM,GACZ,cAAc,EAAE,CAiBlB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,GACd,qBAAqB,CAuBvB"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Webhook Gate Executor
3
+ *
4
+ * Pure logic for webhook gate evaluation, token generation, and callback URL
5
+ * management. Webhook gates pause workflow execution until an external HTTP
6
+ * callback is received, enabling integration with external approval systems,
7
+ * CI/CD pipelines, and other services.
8
+ *
9
+ * This module handles the evaluation and state management logic only.
10
+ * The actual HTTP endpoint registration happens in the server layer (SUP-1299).
11
+ */
12
+ import { randomBytes, timingSafeEqual } from 'node:crypto';
13
+ import { parseDuration } from '../gate-state.js';
14
+ const log = {
15
+ info: (msg, data) => console.log(`[webhook-gate] ${msg}`, data ? JSON.stringify(data) : ''),
16
+ warn: (msg, data) => console.warn(`[webhook-gate] ${msg}`, data ? JSON.stringify(data) : ''),
17
+ error: (msg, data) => console.error(`[webhook-gate] ${msg}`, data ? JSON.stringify(data) : ''),
18
+ debug: (_msg, _data) => { },
19
+ };
20
+ // ============================================
21
+ // Token Generation
22
+ // ============================================
23
+ /**
24
+ * Generate a cryptographically random token for webhook authentication.
25
+ *
26
+ * Uses Node.js `crypto.randomBytes()` to generate a 32-byte hex token.
27
+ * This token is stored in gate state and verified on callback receipt
28
+ * to ensure only authorized callers can satisfy the gate.
29
+ *
30
+ * @returns A 64-character hex string token
31
+ */
32
+ export function generateWebhookToken() {
33
+ return randomBytes(32).toString('hex');
34
+ }
35
+ // ============================================
36
+ // Callback URL
37
+ // ============================================
38
+ /**
39
+ * Build the callback URL for an activated webhook gate.
40
+ *
41
+ * The URL follows the format:
42
+ * `{baseUrl}/api/gates/{issueId}/{gateName}?token={token}`
43
+ *
44
+ * @param baseUrl - The base URL of the server (e.g., "https://api.example.com")
45
+ * @param issueId - The issue identifier this gate is associated with
46
+ * @param gateName - The unique gate name from the gate definition
47
+ * @param token - The authentication token for this gate activation
48
+ * @returns The fully-qualified callback URL
49
+ */
50
+ export function buildCallbackUrl(baseUrl, issueId, gateName, token) {
51
+ const normalizedBase = baseUrl.replace(/\/+$/, '');
52
+ const encodedIssueId = encodeURIComponent(issueId);
53
+ const encodedGateName = encodeURIComponent(gateName);
54
+ const encodedToken = encodeURIComponent(token);
55
+ return `${normalizedBase}/api/gates/${encodedIssueId}/${encodedGateName}?token=${encodedToken}`;
56
+ }
57
+ // ============================================
58
+ // Token Validation
59
+ // ============================================
60
+ /**
61
+ * Validate that a webhook callback's token matches the expected token.
62
+ *
63
+ * Uses timing-safe comparison via `crypto.timingSafeEqual` to prevent
64
+ * timing attacks that could leak token information through response times.
65
+ *
66
+ * @param token - The token received in the webhook callback
67
+ * @param expectedToken - The expected token stored in gate state
68
+ * @returns `true` if the tokens match, `false` otherwise
69
+ */
70
+ export function validateWebhookCallback(token, expectedToken) {
71
+ if (!token || !expectedToken) {
72
+ log.warn('Token validation failed: empty token provided');
73
+ return false;
74
+ }
75
+ const tokenBuffer = Buffer.from(token, 'utf8');
76
+ const expectedBuffer = Buffer.from(expectedToken, 'utf8');
77
+ // timingSafeEqual requires buffers of equal length
78
+ if (tokenBuffer.length !== expectedBuffer.length) {
79
+ return false;
80
+ }
81
+ return timingSafeEqual(tokenBuffer, expectedBuffer);
82
+ }
83
+ // ============================================
84
+ // Gate Evaluation
85
+ // ============================================
86
+ /**
87
+ * Pure function to evaluate a webhook gate's current status based on its
88
+ * definition and persisted state.
89
+ *
90
+ * Evaluation logic:
91
+ * - If gate state is `satisfied` -> return `{ satisfied: true }`
92
+ * - If gate state is `timed-out` -> return `{ satisfied: false, timedOut: true }`
93
+ * - If gate state is `active` and has a timeout deadline that has passed ->
94
+ * return `{ satisfied: false, timedOut: true }`
95
+ * - If gate state is `active` -> return `{ satisfied: false, callbackUrl }`
96
+ * where callbackUrl is reconstructed from state's signalSource if available
97
+ * - If gate state is `null` (not yet activated) -> return `{ satisfied: false }`
98
+ *
99
+ * @param gate - The gate definition from the workflow
100
+ * @param gateState - The persisted gate state, or null if the gate has not been activated
101
+ * @returns The evaluated webhook gate result
102
+ */
103
+ export function evaluateWebhookGate(gate, gateState) {
104
+ if (!gateState) {
105
+ log.debug('Webhook gate not yet activated', { gateName: gate.name });
106
+ return { satisfied: false };
107
+ }
108
+ if (gateState.status === 'satisfied') {
109
+ log.debug('Webhook gate satisfied', { gateName: gate.name });
110
+ return { satisfied: true };
111
+ }
112
+ if (gateState.status === 'timed-out') {
113
+ log.debug('Webhook gate timed out', { gateName: gate.name });
114
+ return { satisfied: false, timedOut: true };
115
+ }
116
+ if (gateState.status === 'active') {
117
+ // Check if the gate has exceeded its timeout deadline
118
+ if (gateState.timeoutDeadline && Date.now() > gateState.timeoutDeadline) {
119
+ log.info('Webhook gate timeout deadline exceeded', {
120
+ gateName: gate.name,
121
+ issueId: gateState.issueId,
122
+ timeoutDeadline: gateState.timeoutDeadline,
123
+ });
124
+ return { satisfied: false, timedOut: true };
125
+ }
126
+ // Gate is active and waiting for callback
127
+ return {
128
+ satisfied: false,
129
+ callbackUrl: gateState.signalSource,
130
+ };
131
+ }
132
+ // Pending or unknown status
133
+ return { satisfied: false };
134
+ }
135
+ // ============================================
136
+ // Type Guards
137
+ // ============================================
138
+ /**
139
+ * Type guard to check if a gate trigger configuration is a webhook trigger.
140
+ *
141
+ * A valid webhook trigger must have an `endpoint` property of type string.
142
+ *
143
+ * @param trigger - The trigger configuration to check
144
+ * @returns `true` if the trigger is a WebhookGateTrigger
145
+ */
146
+ export function isWebhookGateTrigger(trigger) {
147
+ return (typeof trigger === 'object' &&
148
+ trigger !== null &&
149
+ typeof trigger.endpoint === 'string' &&
150
+ trigger.endpoint.length > 0);
151
+ }
152
+ // ============================================
153
+ // Gate Filtering
154
+ // ============================================
155
+ /**
156
+ * Get all webhook gates that apply to a given workflow phase.
157
+ *
158
+ * Filters the workflow's gate definitions to return only those that:
159
+ * 1. Have type `webhook`
160
+ * 2. Either have no `appliesTo` restriction, or include the specified phase
161
+ *
162
+ * @param workflow - The workflow definition containing gate configurations
163
+ * @param phase - The phase name to filter gates for
164
+ * @returns Array of gate definitions that are webhook type and apply to the phase
165
+ */
166
+ export function getApplicableWebhookGates(workflow, phase) {
167
+ if (!workflow.gates || workflow.gates.length === 0) {
168
+ return [];
169
+ }
170
+ return workflow.gates.filter((gate) => {
171
+ if (gate.type !== 'webhook') {
172
+ return false;
173
+ }
174
+ // If no appliesTo is specified, the gate applies to all phases
175
+ if (!gate.appliesTo || gate.appliesTo.length === 0) {
176
+ return true;
177
+ }
178
+ return gate.appliesTo.includes(phase);
179
+ });
180
+ }
181
+ // ============================================
182
+ // Gate Activation
183
+ // ============================================
184
+ /**
185
+ * Creates the activation data for a webhook gate including a cryptographically
186
+ * random token, callback URL, and optional expiration timestamp.
187
+ *
188
+ * This function generates all the data needed to activate a webhook gate,
189
+ * but does not persist any state. The caller is responsible for storing the
190
+ * activation data (token in gate state, URL communicated to external system).
191
+ *
192
+ * @param issueId - The issue identifier this gate is associated with
193
+ * @param gateDef - The gate definition from the workflow
194
+ * @param baseUrl - The base URL of the server for building callback URLs
195
+ * @returns The webhook gate activation data
196
+ */
197
+ export function createWebhookGateActivation(issueId, gateDef, baseUrl) {
198
+ const token = generateWebhookToken();
199
+ const callbackUrl = buildCallbackUrl(baseUrl, issueId, gateDef.name, token);
200
+ const activation = {
201
+ token,
202
+ callbackUrl,
203
+ };
204
+ // Compute expiration from gate timeout if configured
205
+ if (gateDef.timeout) {
206
+ const durationMs = parseDuration(gateDef.timeout.duration);
207
+ activation.expiresAt = Date.now() + durationMs;
208
+ }
209
+ log.info('Webhook gate activation created', {
210
+ issueId,
211
+ gateName: gateDef.name,
212
+ callbackUrl,
213
+ expiresAt: activation.expiresAt,
214
+ });
215
+ return activation;
216
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=webhook-gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-gate.test.d.ts","sourceRoot":"","sources":["../../../../src/workflow/gates/webhook-gate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,182 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { generateWebhookToken, buildCallbackUrl, validateWebhookCallback, evaluateWebhookGate, createWebhookGateActivation, } from './webhook-gate.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Helpers
5
+ // ---------------------------------------------------------------------------
6
+ function makeGateDefinition(overrides = {}) {
7
+ return {
8
+ name: 'test-webhook',
9
+ type: 'webhook',
10
+ trigger: { endpoint: '/api/gates' },
11
+ ...overrides,
12
+ };
13
+ }
14
+ function makeGateState(overrides = {}) {
15
+ return {
16
+ issueId: 'issue-1',
17
+ gateName: 'test-webhook',
18
+ gateType: 'webhook',
19
+ status: 'active',
20
+ activatedAt: Date.now(),
21
+ ...overrides,
22
+ };
23
+ }
24
+ // ---------------------------------------------------------------------------
25
+ // generateWebhookToken
26
+ // ---------------------------------------------------------------------------
27
+ describe('generateWebhookToken', () => {
28
+ it('returns a 64-character hex string', () => {
29
+ const token = generateWebhookToken();
30
+ expect(token).toHaveLength(64);
31
+ expect(token).toMatch(/^[a-f0-9]{64}$/);
32
+ });
33
+ it('generates unique tokens', () => {
34
+ const token1 = generateWebhookToken();
35
+ const token2 = generateWebhookToken();
36
+ expect(token1).not.toBe(token2);
37
+ });
38
+ });
39
+ // ---------------------------------------------------------------------------
40
+ // buildCallbackUrl
41
+ // ---------------------------------------------------------------------------
42
+ describe('buildCallbackUrl', () => {
43
+ it('builds correct URL format', () => {
44
+ const url = buildCallbackUrl('https://api.example.com', 'issue-1', 'my-gate', 'abc123');
45
+ expect(url).toBe('https://api.example.com/api/gates/issue-1/my-gate?token=abc123');
46
+ });
47
+ it('URI-encodes special characters in issueId', () => {
48
+ const url = buildCallbackUrl('https://api.example.com', 'issue/1', 'gate', 'token');
49
+ expect(url).toContain('issue%2F1');
50
+ });
51
+ it('URI-encodes special characters in gateName', () => {
52
+ const url = buildCallbackUrl('https://api.example.com', 'issue-1', 'my gate', 'token');
53
+ expect(url).toContain('my%20gate');
54
+ });
55
+ it('normalizes trailing slashes on base URL', () => {
56
+ const url = buildCallbackUrl('https://api.example.com/', 'issue-1', 'gate', 'token');
57
+ expect(url).toBe('https://api.example.com/api/gates/issue-1/gate?token=token');
58
+ });
59
+ it('normalizes multiple trailing slashes', () => {
60
+ const url = buildCallbackUrl('https://api.example.com///', 'issue-1', 'gate', 'token');
61
+ expect(url).toBe('https://api.example.com/api/gates/issue-1/gate?token=token');
62
+ });
63
+ });
64
+ // ---------------------------------------------------------------------------
65
+ // validateWebhookCallback
66
+ // ---------------------------------------------------------------------------
67
+ describe('validateWebhookCallback', () => {
68
+ it('returns true for matching tokens', () => {
69
+ const token = 'test-webhook-token-value';
70
+ expect(validateWebhookCallback(token, token)).toBe(true);
71
+ });
72
+ it('returns false for mismatched tokens', () => {
73
+ expect(validateWebhookCallback('token-a', 'token-b')).toBe(false);
74
+ });
75
+ it('returns false for empty token', () => {
76
+ expect(validateWebhookCallback('', 'expected')).toBe(false);
77
+ });
78
+ it('returns false for empty expected token', () => {
79
+ expect(validateWebhookCallback('token', '')).toBe(false);
80
+ });
81
+ it('returns false for different length tokens', () => {
82
+ expect(validateWebhookCallback('short', 'a-much-longer-token')).toBe(false);
83
+ });
84
+ });
85
+ // ---------------------------------------------------------------------------
86
+ // evaluateWebhookGate
87
+ // ---------------------------------------------------------------------------
88
+ describe('evaluateWebhookGate', () => {
89
+ beforeEach(() => {
90
+ vi.useFakeTimers();
91
+ vi.setSystemTime(new Date('2025-06-01T12:00:00Z'));
92
+ });
93
+ afterEach(() => {
94
+ vi.useRealTimers();
95
+ });
96
+ it('returns not satisfied for null state', () => {
97
+ const gate = makeGateDefinition();
98
+ const result = evaluateWebhookGate(gate, null);
99
+ expect(result.satisfied).toBe(false);
100
+ expect(result.callbackUrl).toBeUndefined();
101
+ expect(result.timedOut).toBeUndefined();
102
+ });
103
+ it('returns satisfied for satisfied state', () => {
104
+ const gate = makeGateDefinition();
105
+ const state = makeGateState({ status: 'satisfied', satisfiedAt: Date.now() });
106
+ const result = evaluateWebhookGate(gate, state);
107
+ expect(result.satisfied).toBe(true);
108
+ });
109
+ it('returns timedOut for timed-out state', () => {
110
+ const gate = makeGateDefinition();
111
+ const state = makeGateState({ status: 'timed-out', timedOutAt: Date.now() });
112
+ const result = evaluateWebhookGate(gate, state);
113
+ expect(result.satisfied).toBe(false);
114
+ expect(result.timedOut).toBe(true);
115
+ });
116
+ it('returns callbackUrl for active state', () => {
117
+ const gate = makeGateDefinition();
118
+ const state = makeGateState({
119
+ status: 'active',
120
+ signalSource: 'https://api.example.com/api/gates/issue-1/test-webhook?token=abc',
121
+ });
122
+ const result = evaluateWebhookGate(gate, state);
123
+ expect(result.satisfied).toBe(false);
124
+ expect(result.callbackUrl).toBe(state.signalSource);
125
+ });
126
+ it('returns timedOut when active gate has expired deadline', () => {
127
+ const gate = makeGateDefinition();
128
+ const state = makeGateState({
129
+ status: 'active',
130
+ timeoutDeadline: Date.now() - 1000, // deadline in the past
131
+ });
132
+ const result = evaluateWebhookGate(gate, state);
133
+ expect(result.satisfied).toBe(false);
134
+ expect(result.timedOut).toBe(true);
135
+ });
136
+ it('returns not timed out when active gate has future deadline', () => {
137
+ const gate = makeGateDefinition();
138
+ const state = makeGateState({
139
+ status: 'active',
140
+ timeoutDeadline: Date.now() + 60_000, // deadline in the future
141
+ });
142
+ const result = evaluateWebhookGate(gate, state);
143
+ expect(result.satisfied).toBe(false);
144
+ expect(result.timedOut).toBeUndefined();
145
+ });
146
+ });
147
+ // ---------------------------------------------------------------------------
148
+ // createWebhookGateActivation
149
+ // ---------------------------------------------------------------------------
150
+ describe('createWebhookGateActivation', () => {
151
+ beforeEach(() => {
152
+ vi.useFakeTimers();
153
+ vi.setSystemTime(new Date('2025-06-01T12:00:00Z'));
154
+ });
155
+ afterEach(() => {
156
+ vi.useRealTimers();
157
+ });
158
+ it('generates a token', () => {
159
+ const gate = makeGateDefinition();
160
+ const activation = createWebhookGateActivation('issue-1', gate, 'https://api.example.com');
161
+ expect(activation.token).toHaveLength(64);
162
+ expect(activation.token).toMatch(/^[a-f0-9]{64}$/);
163
+ });
164
+ it('builds a callback URL with the generated token', () => {
165
+ const gate = makeGateDefinition({ name: 'review-gate' });
166
+ const activation = createWebhookGateActivation('issue-1', gate, 'https://api.example.com');
167
+ expect(activation.callbackUrl).toContain('https://api.example.com/api/gates/issue-1/review-gate');
168
+ expect(activation.callbackUrl).toContain(`token=${activation.token}`);
169
+ });
170
+ it('computes expiresAt from timeout duration', () => {
171
+ const gate = makeGateDefinition({
172
+ timeout: { duration: '4h', action: 'fail' },
173
+ });
174
+ const activation = createWebhookGateActivation('issue-1', gate, 'https://api.example.com');
175
+ expect(activation.expiresAt).toBe(Date.now() + 14_400_000);
176
+ });
177
+ it('does not set expiresAt when no timeout configured', () => {
178
+ const gate = makeGateDefinition();
179
+ const activation = createWebhookGateActivation('issue-1', gate, 'https://api.example.com');
180
+ expect(activation.expiresAt).toBeUndefined();
181
+ });
182
+ });
@@ -4,11 +4,39 @@
4
4
  * Declarative workflow graph definitions using YAML (v1.1 schema extension).
5
5
  * Defines phases, transitions, escalation ladder, gates, and parallelism.
6
6
  */
7
- export type { EscalationStrategy, PhaseDefinition, TransitionDefinition, EscalationLadderRung, EscalationConfig, GateDefinition, ParallelismGroupDefinition, WorkflowDefinition, } from './workflow-types.js';
8
- export { PhaseDefinitionSchema, TransitionDefinitionSchema, EscalationLadderRungSchema, EscalationConfigSchema, GateDefinitionSchema, ParallelismGroupDefinitionSchema, WorkflowDefinitionSchema, validateWorkflowDefinition, } from './workflow-types.js';
7
+ export type { EscalationStrategy, PhaseDefinition, PhaseOutputDeclaration, PhaseInputDeclaration, TransitionDefinition, EscalationLadderRung, EscalationConfig, GateDefinition, ParallelismGroupDefinition, WorkflowDefinition, BranchingDefinition, TemplateRetryConfig, TemplateTimeoutConfig, } from './workflow-types.js';
8
+ export { PhaseDefinitionSchema, PhaseOutputDeclarationSchema, PhaseInputDeclarationSchema, TransitionDefinitionSchema, EscalationLadderRungSchema, EscalationConfigSchema, GateDefinitionSchema, ParallelismGroupDefinitionSchema, WorkflowDefinitionSchema, BranchingDefinitionSchema, TemplateRetryConfigSchema, TemplateTimeoutConfigSchema, validateWorkflowDefinition, } from './workflow-types.js';
9
9
  export { loadWorkflowDefinitionFile, getBuiltinWorkflowDir, getBuiltinWorkflowPath, } from './workflow-loader.js';
10
- export type { WorkflowRegistryConfig } from './workflow-registry.js';
10
+ export type { WorkflowRegistryConfig, WorkflowStoreSource } from './workflow-registry.js';
11
11
  export { WorkflowRegistry } from './workflow-registry.js';
12
12
  export type { TransitionContext, TransitionResult } from './transition-engine.js';
13
13
  export { evaluateTransitions } from './transition-engine.js';
14
+ export type { BranchingResult } from './branching-router.js';
15
+ export { evaluateBranching } from './branching-router.js';
16
+ export { parseDuration, DurationParseError } from './duration.js';
17
+ export type { ResolvedRetryConfig, ResolvedTimeoutConfig } from './retry-resolver.js';
18
+ export { resolveRetryConfig, resolveTimeoutConfig } from './retry-resolver.js';
19
+ export type { EvaluationContext } from './expression/index.js';
20
+ export { buildEvaluationContext, evaluateCondition } from './expression/index.js';
21
+ export type { GateState, GateStorage } from './gate-state.js';
22
+ export { InMemoryGateStorage, initGateStorage, activateGate, satisfyGate, timeoutGate, } from './gate-state.js';
23
+ export { parseDuration as parseGateDuration } from './gate-state.js';
24
+ export type { SignalGateTrigger, SignalGateResult } from './gates/signal-gate.js';
25
+ export { isSignalGateTrigger, evaluateSignalGate, getApplicableSignalGates, createImplicitHoldGate, createImplicitResumeGate, IMPLICIT_HOLD_GATE_NAME, IMPLICIT_RESUME_GATE_NAME, } from './gates/signal-gate.js';
26
+ export type { WebhookGateTrigger, WebhookGateResult, WebhookGateActivation } from './gates/webhook-gate.js';
27
+ export { generateWebhookToken, buildCallbackUrl, validateWebhookCallback, evaluateWebhookGate, isWebhookGateTrigger, getApplicableWebhookGates, createWebhookGateActivation, } from './gates/webhook-gate.js';
28
+ export type { TimeoutCheckResult, TimedOutGate, TimeoutResolution } from './gates/timeout-engine.js';
29
+ export { checkGateTimeout, checkAllGateTimeouts, resolveTimeoutAction, processGateTimeouts, } from './gates/timeout-engine.js';
30
+ export type { TimerGateTrigger, TimerGateResult } from './gates/timer-gate.js';
31
+ export { evaluateTimerGate, computeNextCronFireTime, isTimerGateTrigger, getApplicableTimerGates, parseCronField, parseCronExpression, } from './gates/timer-gate.js';
32
+ export type { GateEvaluationOptions, GateEvaluationResult } from './gates/gate-evaluator.js';
33
+ export { evaluateGatesForPhase, activateGatesForPhase, clearGatesForIssue, getApplicableGates, } from './gates/gate-evaluator.js';
34
+ export { PhaseOutputCollector } from './phase-output-collector.js';
35
+ export { PhaseContextInjector } from './phase-context-injector.js';
36
+ export type { ParallelTask, ParallelTaskResult, ParallelTaskError, ParallelismResult, ParallelismStrategy, ParallelismStrategyOptions, } from './parallelism-types.js';
37
+ export { ConcurrencySemaphore } from './concurrency-semaphore.js';
38
+ export { ParallelismExecutor } from './parallelism-executor.js';
39
+ export type { AgentCancellation } from './agent-cancellation.js';
40
+ export { InMemoryAgentCancellation } from './agent-cancellation.js';
41
+ export { FanOutStrategy, FanInStrategy, RaceStrategy } from './strategies/index.js';
14
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/workflow/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,oBAAoB,EACpB,gCAAgC,EAChC,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/workflow/index.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,26 @@
4
4
  * Declarative workflow graph definitions using YAML (v1.1 schema extension).
5
5
  * Defines phases, transitions, escalation ladder, gates, and parallelism.
6
6
  */
7
- export { PhaseDefinitionSchema, TransitionDefinitionSchema, EscalationLadderRungSchema, EscalationConfigSchema, GateDefinitionSchema, ParallelismGroupDefinitionSchema, WorkflowDefinitionSchema, validateWorkflowDefinition, } from './workflow-types.js';
7
+ export { PhaseDefinitionSchema, PhaseOutputDeclarationSchema, PhaseInputDeclarationSchema, TransitionDefinitionSchema, EscalationLadderRungSchema, EscalationConfigSchema, GateDefinitionSchema, ParallelismGroupDefinitionSchema, WorkflowDefinitionSchema, BranchingDefinitionSchema, TemplateRetryConfigSchema, TemplateTimeoutConfigSchema, validateWorkflowDefinition, } from './workflow-types.js';
8
8
  export { loadWorkflowDefinitionFile, getBuiltinWorkflowDir, getBuiltinWorkflowPath, } from './workflow-loader.js';
9
9
  export { WorkflowRegistry } from './workflow-registry.js';
10
10
  export { evaluateTransitions } from './transition-engine.js';
11
+ export { evaluateBranching } from './branching-router.js';
12
+ // Duration parser
13
+ export { parseDuration, DurationParseError } from './duration.js';
14
+ export { resolveRetryConfig, resolveTimeoutConfig } from './retry-resolver.js';
15
+ export { buildEvaluationContext, evaluateCondition } from './expression/index.js';
16
+ export { InMemoryGateStorage, initGateStorage, activateGate, satisfyGate, timeoutGate, } from './gate-state.js';
17
+ export { parseDuration as parseGateDuration } from './gate-state.js';
18
+ export { isSignalGateTrigger, evaluateSignalGate, getApplicableSignalGates, createImplicitHoldGate, createImplicitResumeGate, IMPLICIT_HOLD_GATE_NAME, IMPLICIT_RESUME_GATE_NAME, } from './gates/signal-gate.js';
19
+ export { generateWebhookToken, buildCallbackUrl, validateWebhookCallback, evaluateWebhookGate, isWebhookGateTrigger, getApplicableWebhookGates, createWebhookGateActivation, } from './gates/webhook-gate.js';
20
+ export { checkGateTimeout, checkAllGateTimeouts, resolveTimeoutAction, processGateTimeouts, } from './gates/timeout-engine.js';
21
+ export { evaluateTimerGate, computeNextCronFireTime, isTimerGateTrigger, getApplicableTimerGates, parseCronField, parseCronExpression, } from './gates/timer-gate.js';
22
+ export { evaluateGatesForPhase, activateGatesForPhase, clearGatesForIssue, getApplicableGates, } from './gates/gate-evaluator.js';
23
+ // Phase output/input handling
24
+ export { PhaseOutputCollector } from './phase-output-collector.js';
25
+ export { PhaseContextInjector } from './phase-context-injector.js';
26
+ export { ConcurrencySemaphore } from './concurrency-semaphore.js';
27
+ export { ParallelismExecutor } from './parallelism-executor.js';
28
+ export { InMemoryAgentCancellation } from './agent-cancellation.js';
29
+ export { FanOutStrategy, FanInStrategy, RaceStrategy } from './strategies/index.js';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ParallelismExecutor
3
+ *
4
+ * Orchestrates parallel task execution using strategy pattern.
5
+ * Each parallelism group in the workflow definition is executed
6
+ * through its configured strategy with concurrency limiting.
7
+ */
8
+ import type { ParallelismGroupDefinition } from './workflow-types.js';
9
+ import type { ParallelTask, ParallelTaskResult, ParallelismResult, ParallelismStrategy } from './parallelism-types.js';
10
+ export declare class ParallelismExecutor {
11
+ private readonly strategies;
12
+ /**
13
+ * Register a strategy implementation for a strategy name.
14
+ */
15
+ registerStrategy(name: string, strategy: ParallelismStrategy): void;
16
+ /**
17
+ * Get a registered strategy by name.
18
+ */
19
+ getStrategy(name: string): ParallelismStrategy | undefined;
20
+ /**
21
+ * Execute a parallelism group with the configured strategy.
22
+ */
23
+ execute(group: ParallelismGroupDefinition, tasks: ParallelTask[], dispatch: (task: ParallelTask) => Promise<ParallelTaskResult>): Promise<ParallelismResult>;
24
+ }
25
+ //# sourceMappingURL=parallelism-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallelism-executor.d.ts","sourceRoot":"","sources":["../../../src/workflow/parallelism-executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EAEpB,MAAM,wBAAwB,CAAA;AAG/B,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8C;IAEzE;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAInE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI1D;;OAEG;IACG,OAAO,CACX,KAAK,EAAE,0BAA0B,EACjC,KAAK,EAAE,YAAY,EAAE,EACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,kBAAkB,CAAC,GAC5D,OAAO,CAAC,iBAAiB,CAAC;CA8B9B"}