@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,92 @@
1
+ /**
2
+ * Fan-in parallelism strategy.
3
+ *
4
+ * Dispatches N agents in parallel and waits for results.
5
+ *
6
+ * When `waitForAll` is true (default): waits for ALL tasks to settle
7
+ * using Promise.allSettled() semantics.
8
+ *
9
+ * When `waitForAll` is false: resolves on the first successful result,
10
+ * but still waits for all remaining tasks to complete for full result
11
+ * collection.
12
+ *
13
+ * NOTE: Concurrency limiting (maxConcurrent) is handled by the
14
+ * ConcurrencySemaphore in the ParallelismExecutor — this strategy
15
+ * simply calls `options.dispatch()` for each task.
16
+ */
17
+ export class FanInStrategy {
18
+ async execute(tasks, options) {
19
+ const completed = [];
20
+ const failed = [];
21
+ const outputs = {};
22
+ const waitForAll = options.waitForAll !== false; // default true
23
+ // Dispatch all tasks, wrapping each result
24
+ const taskPromises = tasks.map((task) => options.dispatch(task).then((result) => ({ status: 'fulfilled', value: result }), (error) => ({ status: 'rejected', reason: error, task })));
25
+ if (waitForAll) {
26
+ // Wait for all tasks to settle
27
+ const results = await Promise.allSettled(taskPromises);
28
+ for (const result of results) {
29
+ if (result.status === 'fulfilled') {
30
+ const settled = result.value;
31
+ if (settled.status === 'fulfilled') {
32
+ completed.push(settled.value);
33
+ if (settled.value.outputs) {
34
+ outputs[settled.value.issueId] = settled.value.outputs;
35
+ }
36
+ }
37
+ else {
38
+ const errMsg = settled.reason instanceof Error
39
+ ? settled.reason.message
40
+ : String(settled.reason);
41
+ failed.push({
42
+ id: settled.task.id,
43
+ issueId: settled.task.issueId,
44
+ error: errMsg,
45
+ });
46
+ }
47
+ }
48
+ }
49
+ }
50
+ else {
51
+ // Wait for first success, then collect remaining
52
+ let firstSuccessResolve = null;
53
+ const firstSuccessPromise = new Promise((resolve) => {
54
+ firstSuccessResolve = resolve;
55
+ });
56
+ let pendingCount = taskPromises.length;
57
+ let hasSuccess = false;
58
+ const wrappedPromises = taskPromises.map(async (promise) => {
59
+ const result = await promise;
60
+ if (result.status === 'fulfilled') {
61
+ completed.push(result.value);
62
+ if (result.value.outputs) {
63
+ outputs[result.value.issueId] = result.value.outputs;
64
+ }
65
+ if (!hasSuccess && result.value.success) {
66
+ hasSuccess = true;
67
+ firstSuccessResolve?.(result.value);
68
+ }
69
+ }
70
+ else {
71
+ const errMsg = result.reason instanceof Error
72
+ ? result.reason.message
73
+ : String(result.reason);
74
+ failed.push({
75
+ id: result.task.id,
76
+ issueId: result.task.issueId,
77
+ error: errMsg,
78
+ });
79
+ }
80
+ pendingCount--;
81
+ if (pendingCount === 0 && !hasSuccess) {
82
+ firstSuccessResolve?.(null);
83
+ }
84
+ });
85
+ // Wait for first success or all to complete
86
+ await firstSuccessPromise;
87
+ // Still wait for all remaining to finish
88
+ await Promise.allSettled(wrappedPromises);
89
+ }
90
+ return { strategy: 'fan-in', completed, cancelled: [], failed, outputs };
91
+ }
92
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fan-in-strategy.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fan-in-strategy.test.d.ts","sourceRoot":"","sources":["../../../../src/workflow/strategies/fan-in-strategy.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,182 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { FanInStrategy } from './fan-in-strategy.js';
3
+ /** Helper: create sample tasks */
4
+ function createTasks(count) {
5
+ return Array.from({ length: count }, (_, i) => ({
6
+ id: `task-${i + 1}`,
7
+ issueId: `SUP-${100 + i + 1}`,
8
+ phaseName: 'development',
9
+ }));
10
+ }
11
+ /** Helper: create a dispatch that returns success */
12
+ function createSuccessDispatch() {
13
+ return async (task) => ({
14
+ id: task.id,
15
+ issueId: task.issueId,
16
+ success: true,
17
+ durationMs: 10,
18
+ });
19
+ }
20
+ /** Helper: create options with a dispatch function */
21
+ function createOptions(dispatch, overrides = {}) {
22
+ return { dispatch, ...overrides };
23
+ }
24
+ describe('FanInStrategy', () => {
25
+ describe('waitForAll=true', () => {
26
+ it('waits for all tasks to complete', async () => {
27
+ const strategy = new FanInStrategy();
28
+ const tasks = createTasks(3);
29
+ const completionOrder = [];
30
+ const dispatch = async (task) => {
31
+ // Stagger completion times
32
+ const delay = task.id === 'task-1' ? 30 : task.id === 'task-2' ? 10 : 20;
33
+ await new Promise((resolve) => setTimeout(resolve, delay));
34
+ completionOrder.push(task.id);
35
+ return { id: task.id, issueId: task.issueId, success: true };
36
+ };
37
+ const result = await strategy.execute(tasks, createOptions(dispatch, { waitForAll: true }));
38
+ // All three tasks should be completed
39
+ expect(result.completed).toHaveLength(3);
40
+ // The result should include all task IDs
41
+ const completedIds = result.completed.map((r) => r.id).sort();
42
+ expect(completedIds).toEqual(['task-1', 'task-2', 'task-3']);
43
+ });
44
+ it('handles mix of success and failure', async () => {
45
+ const strategy = new FanInStrategy();
46
+ const tasks = createTasks(4);
47
+ const dispatch = async (task) => {
48
+ if (task.id === 'task-2' || task.id === 'task-4') {
49
+ throw new Error(`failed: ${task.id}`);
50
+ }
51
+ return { id: task.id, issueId: task.issueId, success: true };
52
+ };
53
+ const result = await strategy.execute(tasks, createOptions(dispatch, { waitForAll: true }));
54
+ expect(result.completed).toHaveLength(2);
55
+ expect(result.failed).toHaveLength(2);
56
+ const completedIds = result.completed.map((r) => r.id).sort();
57
+ expect(completedIds).toEqual(['task-1', 'task-3']);
58
+ const failedIds = result.failed.map((r) => r.id).sort();
59
+ expect(failedIds).toEqual(['task-2', 'task-4']);
60
+ expect(result.failed.find((f) => f.id === 'task-2')?.error).toBe('failed: task-2');
61
+ });
62
+ });
63
+ describe('waitForAll=false', () => {
64
+ it('resolves after first success', async () => {
65
+ const strategy = new FanInStrategy();
66
+ const tasks = createTasks(3);
67
+ const dispatch = async (task) => {
68
+ // task-2 completes first with success
69
+ const delay = task.id === 'task-1' ? 50 : task.id === 'task-2' ? 10 : 50;
70
+ await new Promise((resolve) => setTimeout(resolve, delay));
71
+ return { id: task.id, issueId: task.issueId, success: true };
72
+ };
73
+ const result = await strategy.execute(tasks, createOptions(dispatch, { waitForAll: false }));
74
+ // All tasks should still be collected (we wait for remaining after first success)
75
+ expect(result.completed).toHaveLength(3);
76
+ expect(result.strategy).toBe('fan-in');
77
+ });
78
+ it('all fail returns failure result', async () => {
79
+ const strategy = new FanInStrategy();
80
+ const tasks = createTasks(3);
81
+ const dispatch = async (task) => {
82
+ throw new Error(`failed: ${task.id}`);
83
+ };
84
+ const result = await strategy.execute(tasks, createOptions(dispatch, { waitForAll: false }));
85
+ expect(result.completed).toHaveLength(0);
86
+ expect(result.failed).toHaveLength(3);
87
+ });
88
+ });
89
+ it('collects outputs from completed tasks', async () => {
90
+ const strategy = new FanInStrategy();
91
+ const tasks = createTasks(2);
92
+ const dispatch = async (task) => ({
93
+ id: task.id,
94
+ issueId: task.issueId,
95
+ success: true,
96
+ outputs: { artifact: `build-${task.id}` },
97
+ });
98
+ const result = await strategy.execute(tasks, createOptions(dispatch));
99
+ expect(result.outputs['SUP-101']).toEqual({ artifact: 'build-task-1' });
100
+ expect(result.outputs['SUP-102']).toEqual({ artifact: 'build-task-2' });
101
+ });
102
+ it('maxConcurrent=2 with 5 tasks verifies queuing behavior', async () => {
103
+ // Note: The actual concurrency limiting is done by the ParallelismExecutor's
104
+ // semaphore wrapping the dispatch function. This test verifies that the
105
+ // strategy works correctly with a dispatch that simulates semaphore behavior.
106
+ const strategy = new FanInStrategy();
107
+ const tasks = createTasks(5);
108
+ let peakConcurrent = 0;
109
+ let currentConcurrent = 0;
110
+ const taskOrder = [];
111
+ // Simulate the semaphore-wrapped dispatch behavior
112
+ const maxConcurrent = 2;
113
+ let activeSlots = 0;
114
+ const waitQueue = [];
115
+ const dispatch = async (task) => {
116
+ // Simulate semaphore acquire
117
+ if (activeSlots >= maxConcurrent) {
118
+ await new Promise((resolve) => waitQueue.push(resolve));
119
+ }
120
+ activeSlots++;
121
+ currentConcurrent++;
122
+ peakConcurrent = Math.max(peakConcurrent, currentConcurrent);
123
+ taskOrder.push(`start:${task.id}`);
124
+ await new Promise((resolve) => setTimeout(resolve, 10));
125
+ taskOrder.push(`end:${task.id}`);
126
+ currentConcurrent--;
127
+ activeSlots--;
128
+ // Simulate semaphore release
129
+ if (waitQueue.length > 0) {
130
+ const next = waitQueue.shift();
131
+ next();
132
+ }
133
+ return { id: task.id, issueId: task.issueId, success: true };
134
+ };
135
+ const result = await strategy.execute(tasks, createOptions(dispatch, { maxConcurrent: 2 }));
136
+ expect(result.completed).toHaveLength(5);
137
+ expect(peakConcurrent).toBeLessThanOrEqual(2);
138
+ // Verify at no point more than 2 tasks are active
139
+ let active = 0;
140
+ for (const entry of taskOrder) {
141
+ if (entry.startsWith('start:'))
142
+ active++;
143
+ if (entry.startsWith('end:'))
144
+ active--;
145
+ expect(active).toBeLessThanOrEqual(2);
146
+ }
147
+ });
148
+ it('returns empty result for empty task list', async () => {
149
+ const strategy = new FanInStrategy();
150
+ const dispatch = createSuccessDispatch();
151
+ const result = await strategy.execute([], createOptions(dispatch));
152
+ expect(result.completed).toEqual([]);
153
+ expect(result.failed).toEqual([]);
154
+ expect(result.cancelled).toEqual([]);
155
+ expect(result.outputs).toEqual({});
156
+ });
157
+ it('sets strategy to fan-in', async () => {
158
+ const strategy = new FanInStrategy();
159
+ const tasks = createTasks(1);
160
+ const dispatch = createSuccessDispatch();
161
+ const result = await strategy.execute(tasks, createOptions(dispatch));
162
+ expect(result.strategy).toBe('fan-in');
163
+ });
164
+ it('defaults to waitForAll=true when not specified', async () => {
165
+ const strategy = new FanInStrategy();
166
+ const tasks = createTasks(3);
167
+ const completionOrder = [];
168
+ const dispatch = async (task) => {
169
+ // Stagger completion: task-3 finishes first, task-1 last
170
+ const delay = task.id === 'task-1' ? 30 : task.id === 'task-2' ? 20 : 10;
171
+ await new Promise((resolve) => setTimeout(resolve, delay));
172
+ completionOrder.push(task.id);
173
+ return { id: task.id, issueId: task.issueId, success: true };
174
+ };
175
+ // Do NOT pass waitForAll — it should default to true
176
+ const result = await strategy.execute(tasks, createOptions(dispatch));
177
+ // All three should complete since default is waitForAll=true
178
+ expect(result.completed).toHaveLength(3);
179
+ const completedIds = result.completed.map((r) => r.id).sort();
180
+ expect(completedIds).toEqual(['task-1', 'task-2', 'task-3']);
181
+ });
182
+ });
@@ -0,0 +1,16 @@
1
+ import type { ParallelTask, ParallelismResult, ParallelismStrategy, ParallelismStrategyOptions } from '../parallelism-types.js';
2
+ /**
3
+ * Fan-out parallelism strategy.
4
+ *
5
+ * Dispatches N agents in parallel without waiting for completion.
6
+ * All dispatches are initiated concurrently and results are collected
7
+ * from whatever settles during the dispatch window.
8
+ *
9
+ * NOTE: Concurrency limiting (maxConcurrent) is handled by the
10
+ * ConcurrencySemaphore in the ParallelismExecutor — this strategy
11
+ * simply calls `options.dispatch()` for each task.
12
+ */
13
+ export declare class FanOutStrategy implements ParallelismStrategy {
14
+ execute(tasks: ParallelTask[], options: ParallelismStrategyOptions): Promise<ParallelismResult>;
15
+ }
16
+ //# sourceMappingURL=fan-out-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fan-out-strategy.d.ts","sourceRoot":"","sources":["../../../../src/workflow/strategies/fan-out-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAGZ,iBAAiB,EACjB,mBAAmB,EACnB,0BAA0B,EAC3B,MAAM,yBAAyB,CAAA;AAEhC;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,YAAW,mBAAmB;IAClD,OAAO,CACX,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,iBAAiB,CAAC;CA2C9B"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Fan-out parallelism strategy.
3
+ *
4
+ * Dispatches N agents in parallel without waiting for completion.
5
+ * All dispatches are initiated concurrently and results are collected
6
+ * from whatever settles during the dispatch window.
7
+ *
8
+ * NOTE: Concurrency limiting (maxConcurrent) is handled by the
9
+ * ConcurrencySemaphore in the ParallelismExecutor — this strategy
10
+ * simply calls `options.dispatch()` for each task.
11
+ */
12
+ export class FanOutStrategy {
13
+ async execute(tasks, options) {
14
+ const completed = [];
15
+ const failed = [];
16
+ const outputs = {};
17
+ // Fire all dispatches concurrently but don't wait for them
18
+ // Use Promise.allSettled with a short window to catch immediate failures
19
+ const dispatchPromises = tasks.map((task) => options.dispatch(task).then((result) => ({ status: 'fulfilled', value: result, task }), (error) => ({ status: 'rejected', reason: error, task })));
20
+ // Wait for all dispatches to settle — since we already wrapped each
21
+ // promise, Promise.allSettled here will always return 'fulfilled' results
22
+ // containing our inner status objects.
23
+ const results = await Promise.allSettled(dispatchPromises);
24
+ for (const result of results) {
25
+ if (result.status === 'fulfilled') {
26
+ const settled = result.value;
27
+ if (settled.status === 'fulfilled') {
28
+ completed.push(settled.value);
29
+ if (settled.value.outputs) {
30
+ outputs[settled.value.issueId] = settled.value.outputs;
31
+ }
32
+ }
33
+ else {
34
+ const errMsg = settled.reason instanceof Error
35
+ ? settled.reason.message
36
+ : String(settled.reason);
37
+ failed.push({
38
+ id: settled.task.id,
39
+ issueId: settled.task.issueId,
40
+ error: errMsg,
41
+ });
42
+ }
43
+ }
44
+ }
45
+ return { strategy: 'fan-out', completed, cancelled: [], failed, outputs };
46
+ }
47
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fan-out-strategy.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fan-out-strategy.test.d.ts","sourceRoot":"","sources":["../../../../src/workflow/strategies/fan-out-strategy.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { FanOutStrategy } from './fan-out-strategy.js';
3
+ /** Helper: create sample tasks */
4
+ function createTasks(count) {
5
+ return Array.from({ length: count }, (_, i) => ({
6
+ id: `task-${i + 1}`,
7
+ issueId: `SUP-${100 + i + 1}`,
8
+ phaseName: 'development',
9
+ }));
10
+ }
11
+ /** Helper: create a dispatch that returns success */
12
+ function createSuccessDispatch() {
13
+ return async (task) => ({
14
+ id: task.id,
15
+ issueId: task.issueId,
16
+ success: true,
17
+ durationMs: 10,
18
+ });
19
+ }
20
+ /** Helper: create options with a dispatch function */
21
+ function createOptions(dispatch, overrides = {}) {
22
+ return { dispatch, ...overrides };
23
+ }
24
+ describe('FanOutStrategy', () => {
25
+ it('dispatches all tasks and returns results', async () => {
26
+ const strategy = new FanOutStrategy();
27
+ const tasks = createTasks(3);
28
+ const dispatched = [];
29
+ const dispatch = async (task) => {
30
+ dispatched.push(task.id);
31
+ return { id: task.id, issueId: task.issueId, success: true };
32
+ };
33
+ const result = await strategy.execute(tasks, createOptions(dispatch));
34
+ expect(dispatched).toEqual(['task-1', 'task-2', 'task-3']);
35
+ expect(result.completed).toHaveLength(3);
36
+ expect(result.completed[0].issueId).toBe('SUP-101');
37
+ expect(result.completed[1].issueId).toBe('SUP-102');
38
+ expect(result.completed[2].issueId).toBe('SUP-103');
39
+ });
40
+ it('handles dispatch failures gracefully', async () => {
41
+ const strategy = new FanOutStrategy();
42
+ const tasks = createTasks(3);
43
+ const dispatch = async (task) => {
44
+ if (task.id === 'task-2') {
45
+ throw new Error('dispatch failed for task-2');
46
+ }
47
+ return { id: task.id, issueId: task.issueId, success: true };
48
+ };
49
+ const result = await strategy.execute(tasks, createOptions(dispatch));
50
+ expect(result.completed).toHaveLength(2);
51
+ expect(result.failed).toHaveLength(1);
52
+ expect(result.failed[0].id).toBe('task-2');
53
+ expect(result.failed[0].issueId).toBe('SUP-102');
54
+ expect(result.failed[0].error).toBe('dispatch failed for task-2');
55
+ });
56
+ it('collects outputs from successful tasks', async () => {
57
+ const strategy = new FanOutStrategy();
58
+ const tasks = createTasks(2);
59
+ const dispatch = async (task) => ({
60
+ id: task.id,
61
+ issueId: task.issueId,
62
+ success: true,
63
+ outputs: { artifact: `build-${task.id}` },
64
+ });
65
+ const result = await strategy.execute(tasks, createOptions(dispatch));
66
+ expect(result.outputs['SUP-101']).toEqual({ artifact: 'build-task-1' });
67
+ expect(result.outputs['SUP-102']).toEqual({ artifact: 'build-task-2' });
68
+ });
69
+ it('returns empty result for empty task list', async () => {
70
+ const strategy = new FanOutStrategy();
71
+ const dispatch = createSuccessDispatch();
72
+ const result = await strategy.execute([], createOptions(dispatch));
73
+ expect(result.completed).toEqual([]);
74
+ expect(result.failed).toEqual([]);
75
+ expect(result.cancelled).toEqual([]);
76
+ expect(result.outputs).toEqual({});
77
+ });
78
+ it('sets strategy to fan-out', async () => {
79
+ const strategy = new FanOutStrategy();
80
+ const tasks = createTasks(1);
81
+ const dispatch = createSuccessDispatch();
82
+ const result = await strategy.execute(tasks, createOptions(dispatch));
83
+ expect(result.strategy).toBe('fan-out');
84
+ });
85
+ it('cancelled array is always empty', async () => {
86
+ const strategy = new FanOutStrategy();
87
+ const tasks = createTasks(3);
88
+ const dispatch = async (task) => {
89
+ if (task.id === 'task-2') {
90
+ throw new Error('failed');
91
+ }
92
+ return { id: task.id, issueId: task.issueId, success: true };
93
+ };
94
+ const result = await strategy.execute(tasks, createOptions(dispatch));
95
+ expect(result.cancelled).toEqual([]);
96
+ });
97
+ });
@@ -0,0 +1,4 @@
1
+ export { FanOutStrategy } from './fan-out-strategy.js';
2
+ export { FanInStrategy } from './fan-in-strategy.js';
3
+ export { RaceStrategy } from './race-strategy.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/workflow/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { FanOutStrategy } from './fan-out-strategy.js';
2
+ export { FanInStrategy } from './fan-in-strategy.js';
3
+ export { RaceStrategy } from './race-strategy.js';
@@ -0,0 +1,19 @@
1
+ import type { ParallelTask, ParallelismResult, ParallelismStrategy, ParallelismStrategyOptions } from '../parallelism-types.js';
2
+ import { InMemoryAgentCancellation } from '../agent-cancellation.js';
3
+ /**
4
+ * Race parallelism strategy.
5
+ *
6
+ * Dispatches N agents in parallel. The first successful completion wins,
7
+ * and cancellation is signaled for all remaining tasks.
8
+ *
9
+ * NOTE: Concurrency limiting (maxConcurrent) is handled by the
10
+ * ConcurrencySemaphore in the ParallelismExecutor — this strategy
11
+ * simply calls `options.dispatch()` for each task.
12
+ */
13
+ export declare class RaceStrategy implements ParallelismStrategy {
14
+ private readonly cancellation;
15
+ private readonly cancellationTimeoutMs;
16
+ constructor(cancellation?: InMemoryAgentCancellation, cancellationTimeoutMs?: number);
17
+ execute(tasks: ParallelTask[], options: ParallelismStrategyOptions): Promise<ParallelismResult>;
18
+ }
19
+ //# sourceMappingURL=race-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race-strategy.d.ts","sourceRoot":"","sources":["../../../../src/workflow/strategies/race-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAGZ,iBAAiB,EACjB,mBAAmB,EACnB,0BAA0B,EAC3B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AAEpE;;;;;;;;;GASG;AACH,qBAAa,YAAa,YAAW,mBAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2B;IACxD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;gBAElC,YAAY,CAAC,EAAE,yBAAyB,EAAE,qBAAqB,CAAC,EAAE,MAAM;IAK9E,OAAO,CACX,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,iBAAiB,CAAC;CA4F9B"}
@@ -0,0 +1,92 @@
1
+ import { InMemoryAgentCancellation } from '../agent-cancellation.js';
2
+ /**
3
+ * Race parallelism strategy.
4
+ *
5
+ * Dispatches N agents in parallel. The first successful completion wins,
6
+ * and cancellation is signaled for all remaining tasks.
7
+ *
8
+ * NOTE: Concurrency limiting (maxConcurrent) is handled by the
9
+ * ConcurrencySemaphore in the ParallelismExecutor — this strategy
10
+ * simply calls `options.dispatch()` for each task.
11
+ */
12
+ export class RaceStrategy {
13
+ cancellation;
14
+ cancellationTimeoutMs;
15
+ constructor(cancellation, cancellationTimeoutMs) {
16
+ this.cancellation = cancellation ?? new InMemoryAgentCancellation();
17
+ this.cancellationTimeoutMs = cancellationTimeoutMs ?? 30_000;
18
+ }
19
+ async execute(tasks, options) {
20
+ if (tasks.length === 0) {
21
+ return { strategy: 'race', completed: [], cancelled: [], failed: [], outputs: {} };
22
+ }
23
+ const completed = [];
24
+ const failed = [];
25
+ const outputs = {};
26
+ let winner = null;
27
+ const taskPromises = tasks.map((task) => options.dispatch(task).then((result) => ({ status: 'fulfilled', value: result, task }), (error) => ({ status: 'rejected', reason: error, task })));
28
+ // Use a winner-detection approach: wrap each promise to detect the
29
+ // first successful result, signal cancellation, then wait for all to settle.
30
+ let resolveWinner = null;
31
+ const winnerPromise = new Promise((resolve) => {
32
+ resolveWinner = resolve;
33
+ });
34
+ let settledCount = 0;
35
+ const totalTasks = tasks.length;
36
+ const wrappedPromises = taskPromises.map(async (promise) => {
37
+ const settled = await promise;
38
+ settledCount++;
39
+ if (settled.status === 'fulfilled') {
40
+ completed.push(settled.value);
41
+ if (settled.value.success && !winner) {
42
+ // First successful completion — this is the winner
43
+ winner = settled.value;
44
+ if (settled.value.outputs) {
45
+ outputs[settled.value.issueId] = settled.value.outputs;
46
+ }
47
+ // Signal cancellation for all other tasks
48
+ for (const task of tasks) {
49
+ if (task.id !== settled.task.id) {
50
+ await this.cancellation.cancel(task.id);
51
+ }
52
+ }
53
+ resolveWinner?.(settled.value);
54
+ }
55
+ else if (settled.value.outputs && settled.value.success) {
56
+ outputs[settled.value.issueId] = settled.value.outputs;
57
+ }
58
+ }
59
+ else {
60
+ const errMsg = settled.reason instanceof Error
61
+ ? settled.reason.message
62
+ : String(settled.reason);
63
+ failed.push({
64
+ id: settled.task.id,
65
+ issueId: settled.task.issueId,
66
+ error: errMsg,
67
+ });
68
+ }
69
+ // If all tasks settled and no winner, resolve
70
+ if (settledCount === totalTasks && !winner) {
71
+ resolveWinner?.(null);
72
+ }
73
+ });
74
+ // Wait for the winner or all to fail
75
+ await winnerPromise;
76
+ // Wait for remaining tasks to settle, with a timeout to prevent hanging
77
+ // if agents never check isCancelled() and never complete
78
+ await Promise.race([
79
+ Promise.allSettled(wrappedPromises),
80
+ new Promise((resolve) => setTimeout(resolve, this.cancellationTimeoutMs)),
81
+ ]);
82
+ // Build cancelled list (all tasks that were cancelled, excluding winner and failed)
83
+ const cancelledIds = this.cancellation.getCancelledIds();
84
+ return {
85
+ strategy: 'race',
86
+ completed,
87
+ cancelled: cancelledIds,
88
+ failed,
89
+ outputs,
90
+ };
91
+ }
92
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=race-strategy.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race-strategy.test.d.ts","sourceRoot":"","sources":["../../../../src/workflow/strategies/race-strategy.test.ts"],"names":[],"mappings":""}