@holoscript/engine 6.0.3 → 6.0.4

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 (192) hide show
  1. package/dist/AutoMesher-CK47F6AV.js +17 -0
  2. package/dist/GPUBuffers-2LHBCD7X.js +9 -0
  3. package/dist/WebGPUContext-TNEUYU2Y.js +11 -0
  4. package/dist/animation/index.cjs +38 -38
  5. package/dist/animation/index.d.cts +1 -1
  6. package/dist/animation/index.d.ts +1 -1
  7. package/dist/animation/index.js +1 -1
  8. package/dist/audio/index.cjs +16 -6
  9. package/dist/audio/index.d.cts +1 -1
  10. package/dist/audio/index.d.ts +1 -1
  11. package/dist/audio/index.js +1 -1
  12. package/dist/camera/index.cjs +23 -23
  13. package/dist/camera/index.d.cts +1 -1
  14. package/dist/camera/index.d.ts +1 -1
  15. package/dist/camera/index.js +1 -1
  16. package/dist/character/index.cjs +6 -4
  17. package/dist/character/index.js +1 -1
  18. package/dist/choreography/index.cjs +1194 -0
  19. package/dist/choreography/index.d.cts +687 -0
  20. package/dist/choreography/index.d.ts +687 -0
  21. package/dist/choreography/index.js +1156 -0
  22. package/dist/chunk-2CSNRI2N.js +217 -0
  23. package/dist/chunk-33T2WINR.js +266 -0
  24. package/dist/chunk-35R73OFM.js +1257 -0
  25. package/dist/chunk-4MMDSUNP.js +1256 -0
  26. package/dist/chunk-5V6HOU72.js +319 -0
  27. package/dist/chunk-6QOP6PYF.js +1038 -0
  28. package/dist/chunk-7KMJVHIL.js +8944 -0
  29. package/dist/chunk-7VPUC62U.js +1106 -0
  30. package/dist/chunk-A2Y6RCAT.js +1878 -0
  31. package/dist/chunk-AHM42MK6.js +8944 -0
  32. package/dist/chunk-BL7IDTHE.js +218 -0
  33. package/dist/chunk-CITOMSWL.js +10462 -0
  34. package/dist/chunk-CXDPKW2K.js +8944 -0
  35. package/dist/chunk-CXZPLD4S.js +223 -0
  36. package/dist/chunk-CZYJE7IH.js +5169 -0
  37. package/dist/chunk-D2OP7YC7.js +6325 -0
  38. package/dist/chunk-EDRVQHUU.js +1544 -0
  39. package/dist/chunk-EJSLOOW2.js +3589 -0
  40. package/dist/chunk-F53SFGW5.js +1878 -0
  41. package/dist/chunk-HCFPELPY.js +919 -0
  42. package/dist/chunk-HNEE36PY.js +93 -0
  43. package/dist/chunk-HYXNV36F.js +1256 -0
  44. package/dist/chunk-IB7KHVFY.js +821 -0
  45. package/dist/chunk-IBBO7YYG.js +690 -0
  46. package/dist/chunk-ILIBGINU.js +5470 -0
  47. package/dist/chunk-IS4MHLKN.js +5479 -0
  48. package/dist/chunk-JT2PFKWD.js +5479 -0
  49. package/dist/chunk-K4CUB4NY.js +1038 -0
  50. package/dist/chunk-KATDQXRJ.js +10462 -0
  51. package/dist/chunk-KBQE6ZFJ.js +8944 -0
  52. package/dist/chunk-KBVD5K7E.js +560 -0
  53. package/dist/chunk-KCDPVQRY.js +4088 -0
  54. package/dist/chunk-KN4QJPKN.js +8944 -0
  55. package/dist/chunk-KWJ3ROSI.js +8944 -0
  56. package/dist/chunk-L45VF6DD.js +919 -0
  57. package/dist/chunk-LY4T37YK.js +307 -0
  58. package/dist/chunk-MDN5WZXA.js +1544 -0
  59. package/dist/chunk-MGCDP6VU.js +928 -0
  60. package/dist/chunk-NCX7X6G2.js +8681 -0
  61. package/dist/chunk-OF54BPVD.js +913 -0
  62. package/dist/chunk-OWSN2Q3Q.js +690 -0
  63. package/dist/chunk-PRRB5TTA.js +406 -0
  64. package/dist/chunk-PXWVQF76.js +4086 -0
  65. package/dist/chunk-PYCOIDT2.js +812 -0
  66. package/dist/chunk-PZCSADOV.js +928 -0
  67. package/dist/chunk-Q2XBVS2K.js +1038 -0
  68. package/dist/chunk-QDZRXWN5.js +1776 -0
  69. package/dist/chunk-RNWOZ6WQ.js +913 -0
  70. package/dist/chunk-ROLFT4CJ.js +1693 -0
  71. package/dist/chunk-SLTJRZ2N.js +266 -0
  72. package/dist/chunk-SRUS5XSU.js +4088 -0
  73. package/dist/chunk-TKCA3WZ5.js +5409 -0
  74. package/dist/chunk-TNRMXYI2.js +1650 -0
  75. package/dist/chunk-TQB3GJGM.js +9763 -0
  76. package/dist/chunk-TUFGXG6K.js +510 -0
  77. package/dist/chunk-U6KMTGQJ.js +632 -0
  78. package/dist/chunk-VMGJQST6.js +8681 -0
  79. package/dist/chunk-X4F4TCG4.js +5470 -0
  80. package/dist/chunk-ZIFROE75.js +1544 -0
  81. package/dist/chunk-ZIJQYHSQ.js +1204 -0
  82. package/dist/combat/index.cjs +4 -4
  83. package/dist/combat/index.d.cts +1 -1
  84. package/dist/combat/index.d.ts +1 -1
  85. package/dist/combat/index.js +1 -1
  86. package/dist/ecs/index.cjs +1 -1
  87. package/dist/ecs/index.js +1 -1
  88. package/dist/environment/index.cjs +14 -14
  89. package/dist/environment/index.d.cts +1 -1
  90. package/dist/environment/index.d.ts +1 -1
  91. package/dist/environment/index.js +1 -1
  92. package/dist/gpu/index.cjs +4810 -0
  93. package/dist/gpu/index.js +3714 -0
  94. package/dist/hologram/index.cjs +27 -1
  95. package/dist/hologram/index.js +1 -1
  96. package/dist/index-B2PIsAmR.d.cts +2180 -0
  97. package/dist/index-B2PIsAmR.d.ts +2180 -0
  98. package/dist/index-BHySEPX7.d.cts +2921 -0
  99. package/dist/index-BJV21zuy.d.cts +341 -0
  100. package/dist/index-BJV21zuy.d.ts +341 -0
  101. package/dist/index-BQutTphC.d.cts +790 -0
  102. package/dist/index-ByIq2XrS.d.cts +3910 -0
  103. package/dist/index-BysHjDSO.d.cts +224 -0
  104. package/dist/index-BysHjDSO.d.ts +224 -0
  105. package/dist/index-CKwAJGck.d.ts +455 -0
  106. package/dist/index-CUl3QstQ.d.cts +3006 -0
  107. package/dist/index-CUl3QstQ.d.ts +3006 -0
  108. package/dist/index-CmYtNiI-.d.cts +953 -0
  109. package/dist/index-CmYtNiI-.d.ts +953 -0
  110. package/dist/index-CnRzWxi_.d.cts +522 -0
  111. package/dist/index-CnRzWxi_.d.ts +522 -0
  112. package/dist/index-CwRWbSC7.d.ts +2921 -0
  113. package/dist/index-CxKIBstO.d.ts +790 -0
  114. package/dist/index-DJ6-R8vh.d.cts +455 -0
  115. package/dist/index-DQKisbcI.d.cts +4968 -0
  116. package/dist/index-DQKisbcI.d.ts +4968 -0
  117. package/dist/index-DRT2zJez.d.ts +3910 -0
  118. package/dist/index-DfNLiAka.d.cts +192 -0
  119. package/dist/index-DfNLiAka.d.ts +192 -0
  120. package/dist/index-nMvkoRm8.d.cts +405 -0
  121. package/dist/index-nMvkoRm8.d.ts +405 -0
  122. package/dist/index-s9yOFU37.d.cts +604 -0
  123. package/dist/index-s9yOFU37.d.ts +604 -0
  124. package/dist/index.cjs +22966 -6960
  125. package/dist/index.d.cts +864 -20
  126. package/dist/index.d.ts +864 -20
  127. package/dist/index.js +3062 -48
  128. package/dist/input/index.cjs +1 -1
  129. package/dist/input/index.js +1 -1
  130. package/dist/orbital/index.cjs +3 -3
  131. package/dist/orbital/index.d.cts +1 -1
  132. package/dist/orbital/index.d.ts +1 -1
  133. package/dist/orbital/index.js +1 -1
  134. package/dist/particles/index.cjs +16 -16
  135. package/dist/particles/index.d.cts +1 -1
  136. package/dist/particles/index.d.ts +1 -1
  137. package/dist/particles/index.js +1 -1
  138. package/dist/physics/index.cjs +2377 -21
  139. package/dist/physics/index.d.cts +1 -1
  140. package/dist/physics/index.d.ts +1 -1
  141. package/dist/physics/index.js +35 -1
  142. package/dist/postfx/index.cjs +3491 -0
  143. package/dist/postfx/index.js +93 -0
  144. package/dist/procedural/index.cjs +1 -1
  145. package/dist/procedural/index.js +1 -1
  146. package/dist/puppeteer-5VF6KDVO.js +52197 -0
  147. package/dist/puppeteer-IZVZ3SG4.js +52197 -0
  148. package/dist/rendering/index.cjs +33 -32
  149. package/dist/rendering/index.d.cts +1 -1
  150. package/dist/rendering/index.d.ts +1 -1
  151. package/dist/rendering/index.js +8 -6
  152. package/dist/runtime/index.cjs +23 -13
  153. package/dist/runtime/index.d.cts +1 -1
  154. package/dist/runtime/index.d.ts +1 -1
  155. package/dist/runtime/index.js +8 -6
  156. package/dist/runtime/protocols/index.cjs +349 -0
  157. package/dist/runtime/protocols/index.js +15 -0
  158. package/dist/scene/index.cjs +8 -8
  159. package/dist/scene/index.d.cts +1 -1
  160. package/dist/scene/index.d.ts +1 -1
  161. package/dist/scene/index.js +1 -1
  162. package/dist/shader/index.cjs +3087 -0
  163. package/dist/shader/index.js +3044 -0
  164. package/dist/simulation/index.cjs +10680 -0
  165. package/dist/simulation/index.d.cts +3 -0
  166. package/dist/simulation/index.d.ts +3 -0
  167. package/dist/simulation/index.js +307 -0
  168. package/dist/spatial/index.cjs +2443 -0
  169. package/dist/spatial/index.d.cts +1545 -0
  170. package/dist/spatial/index.d.ts +1545 -0
  171. package/dist/spatial/index.js +2400 -0
  172. package/dist/terrain/index.cjs +1 -1
  173. package/dist/terrain/index.d.cts +1 -1
  174. package/dist/terrain/index.d.ts +1 -1
  175. package/dist/terrain/index.js +1 -1
  176. package/dist/transformers.node-4NKAPD5U.js +45620 -0
  177. package/dist/vm/index.cjs +7 -8
  178. package/dist/vm/index.d.cts +1 -1
  179. package/dist/vm/index.d.ts +1 -1
  180. package/dist/vm/index.js +1 -1
  181. package/dist/vm-bridge/index.cjs +2 -2
  182. package/dist/vm-bridge/index.d.cts +2 -2
  183. package/dist/vm-bridge/index.d.ts +2 -2
  184. package/dist/vm-bridge/index.js +1 -1
  185. package/dist/vr/index.cjs +6 -6
  186. package/dist/vr/index.js +1 -1
  187. package/dist/world/index.cjs +3 -3
  188. package/dist/world/index.d.cts +1 -1
  189. package/dist/world/index.d.ts +1 -1
  190. package/dist/world/index.js +1 -1
  191. package/package.json +53 -21
  192. package/LICENSE +0 -21
@@ -0,0 +1,1156 @@
1
+ import "../chunk-AKLW2MUS.js";
2
+
3
+ // src/choreography/ChoreographyTypes.ts
4
+ var DEFAULT_RETRY_CONFIG = {
5
+ strategy: "exponential",
6
+ maxRetries: 3,
7
+ delay: 1e3,
8
+ backoffMultiplier: 2,
9
+ maxDelay: 3e4
10
+ };
11
+ var Constraints = {
12
+ timeout(ms, hard = true) {
13
+ return { type: "timeout", value: ms, hard, description: `Max ${ms}ms execution time` };
14
+ },
15
+ concurrency(max) {
16
+ return { type: "concurrency", value: max, description: `Max ${max} concurrent steps` };
17
+ },
18
+ trust(minLevel) {
19
+ return { type: "trust", value: minLevel, hard: true, description: `Min trust: ${minLevel}` };
20
+ }
21
+ };
22
+
23
+ // src/choreography/StepExecutor.ts
24
+ import { EventEmitter } from "events";
25
+ var DEFAULT_EXECUTOR_CONFIG = {
26
+ defaultTimeout: 3e4,
27
+ defaultRetry: DEFAULT_RETRY_CONFIG,
28
+ verbose: false
29
+ };
30
+ var StepExecutor = class extends EventEmitter {
31
+ config;
32
+ actionHandler = null;
33
+ runningSteps = /* @__PURE__ */ new Map();
34
+ constructor(config = {}) {
35
+ super();
36
+ this.config = { ...DEFAULT_EXECUTOR_CONFIG, ...config };
37
+ }
38
+ /**
39
+ * Register the action handler for executing agent actions
40
+ */
41
+ setActionHandler(handler) {
42
+ this.actionHandler = handler;
43
+ }
44
+ /**
45
+ * Execute a single step
46
+ */
47
+ async execute(step, context) {
48
+ const startTime = Date.now();
49
+ if (this.shouldSkip(step, context)) {
50
+ const reason = "Condition not met";
51
+ this.emit("step:skipped", step, reason);
52
+ return {
53
+ stepId: step.id,
54
+ success: true,
55
+ outputs: {},
56
+ duration: 0,
57
+ error: void 0
58
+ };
59
+ }
60
+ const agent = context.agents.get(step.agentId);
61
+ if (!agent) {
62
+ throw new Error(`Agent not found: ${step.agentId}`);
63
+ }
64
+ const resolvedInputs = this.resolveInputs(step.inputs, context);
65
+ this.emit("step:inputs:resolved", step, resolvedInputs);
66
+ const retryConfig = {
67
+ ...this.config.defaultRetry,
68
+ ...step.retry || {}
69
+ };
70
+ let lastError = null;
71
+ let attempt = 0;
72
+ while (attempt <= retryConfig.maxRetries) {
73
+ try {
74
+ step.status = "running";
75
+ step.startedAt = Date.now();
76
+ step.retryAttempt = attempt;
77
+ this.emit("step:executing", step, agent);
78
+ const abortController = new AbortController();
79
+ this.runningSteps.set(step.id, abortController);
80
+ const timeout = step.timeout || this.config.defaultTimeout;
81
+ const outputs = await this.executeWithTimeout(
82
+ step,
83
+ agent,
84
+ resolvedInputs,
85
+ context,
86
+ timeout,
87
+ abortController.signal
88
+ );
89
+ this.runningSteps.delete(step.id);
90
+ step.status = "completed";
91
+ step.completedAt = Date.now();
92
+ step.duration = step.completedAt - step.startedAt;
93
+ const result = {
94
+ stepId: step.id,
95
+ success: true,
96
+ outputs,
97
+ duration: step.duration,
98
+ retries: attempt
99
+ };
100
+ this.emit("step:completed", step, result);
101
+ return result;
102
+ } catch (error) {
103
+ lastError = error instanceof Error ? error : new Error(String(error));
104
+ this.runningSteps.delete(step.id);
105
+ if (lastError.message.includes("cancelled")) {
106
+ step.status = "failed";
107
+ step.completedAt = Date.now();
108
+ step.duration = step.completedAt - (step.startedAt || startTime);
109
+ step.error = lastError.message;
110
+ return {
111
+ stepId: step.id,
112
+ success: false,
113
+ outputs: {},
114
+ duration: step.duration,
115
+ error: step.error,
116
+ retries: attempt
117
+ };
118
+ }
119
+ if (attempt < retryConfig.maxRetries) {
120
+ if (retryConfig.condition && !retryConfig.condition(lastError, attempt)) {
121
+ break;
122
+ }
123
+ const delay = this.calculateDelay(retryConfig, attempt);
124
+ this.emit("step:retrying", step, attempt + 1, delay);
125
+ await this.sleep(delay);
126
+ }
127
+ attempt++;
128
+ }
129
+ }
130
+ step.status = "failed";
131
+ step.completedAt = Date.now();
132
+ step.duration = step.completedAt - (step.startedAt || startTime);
133
+ step.error = lastError?.message || "Unknown error";
134
+ this.emit("step:failed", step, lastError || new Error("Unknown error"));
135
+ return {
136
+ stepId: step.id,
137
+ success: false,
138
+ outputs: {},
139
+ duration: step.duration,
140
+ error: step.error,
141
+ retries: attempt - 1
142
+ };
143
+ }
144
+ /**
145
+ * Cancel a running step
146
+ */
147
+ cancel(stepId) {
148
+ const controller = this.runningSteps.get(stepId);
149
+ if (controller) {
150
+ controller.abort();
151
+ this.runningSteps.delete(stepId);
152
+ return true;
153
+ }
154
+ return false;
155
+ }
156
+ /**
157
+ * Check if any steps are running
158
+ */
159
+ isRunning(stepId) {
160
+ if (stepId) {
161
+ return this.runningSteps.has(stepId);
162
+ }
163
+ return this.runningSteps.size > 0;
164
+ }
165
+ // ==========================================================================
166
+ // PRIVATE METHODS
167
+ // ==========================================================================
168
+ /**
169
+ * Check if step should be skipped
170
+ */
171
+ shouldSkip(step, context) {
172
+ if (!step.condition) return false;
173
+ if (typeof step.condition === "function") {
174
+ return !step.condition(context);
175
+ }
176
+ try {
177
+ return !this.evaluateCondition(step.condition, context);
178
+ } catch {
179
+ return false;
180
+ }
181
+ }
182
+ /**
183
+ * Evaluate a string condition
184
+ */
185
+ evaluateCondition(condition, context) {
186
+ const stepRefRegex = /step#(\w+)\.outputs\.(\w+)/g;
187
+ let evaluated = condition;
188
+ evaluated = evaluated.replace(stepRefRegex, (_, stepId, outputKey) => {
189
+ const outputs = context.stepOutputs.get(stepId);
190
+ if (outputs && outputKey in outputs) {
191
+ const value2 = outputs[outputKey];
192
+ if (typeof value2 === "string") {
193
+ return `"${value2}"`;
194
+ }
195
+ return String(value2);
196
+ }
197
+ return "undefined";
198
+ });
199
+ const eqMatch = evaluated.match(/^(.+)\s*==\s*(.+)$/);
200
+ if (eqMatch) {
201
+ const [, left, right] = eqMatch;
202
+ return this.parseValue(left.trim()) === this.parseValue(right.trim());
203
+ }
204
+ const value = this.parseValue(evaluated.trim());
205
+ return Boolean(value);
206
+ }
207
+ /**
208
+ * Parse a string value
209
+ */
210
+ parseValue(str) {
211
+ if (str === "true") return true;
212
+ if (str === "false") return false;
213
+ if (str === "null") return null;
214
+ if (str === "undefined") return void 0;
215
+ if (/^-?\d+$/.test(str)) return parseInt(str, 10);
216
+ if (/^-?\d+\.\d+$/.test(str)) return parseFloat(str);
217
+ if (str.startsWith('"') && str.endsWith('"')) {
218
+ return str.slice(1, -1);
219
+ }
220
+ return str;
221
+ }
222
+ /**
223
+ * Resolve input references
224
+ */
225
+ resolveInputs(inputs, context) {
226
+ const resolved = {};
227
+ for (const [key, value] of Object.entries(inputs)) {
228
+ if (typeof value === "string") {
229
+ const templateRef = value.match(/^\$\{([\w-]+)\.([\w-]+)\}$/);
230
+ if (templateRef) {
231
+ const [, stepName, outputKey] = templateRef;
232
+ let outputs = context.stepOutputs.get(stepName);
233
+ if (!outputs && context.plan?.steps) {
234
+ const referencedStep = context.plan.steps.find(
235
+ (s) => s.name === stepName || s.id === stepName
236
+ );
237
+ if (referencedStep) {
238
+ outputs = context.stepOutputs.get(referencedStep.id);
239
+ }
240
+ }
241
+ if (outputs) {
242
+ resolved[key] = outputs[outputKey];
243
+ continue;
244
+ }
245
+ }
246
+ const stepRef = value.match(/^step#(\w+)\.outputs\.(\w+)$/);
247
+ if (stepRef) {
248
+ const [, stepId, outputKey] = stepRef;
249
+ const outputs = context.stepOutputs.get(stepId);
250
+ resolved[key] = outputs?.[outputKey];
251
+ continue;
252
+ }
253
+ const stateRef = value.match(/^state\.(\w+)$/);
254
+ if (stateRef) {
255
+ resolved[key] = context.variables[stateRef[1]];
256
+ continue;
257
+ }
258
+ }
259
+ resolved[key] = value;
260
+ }
261
+ return resolved;
262
+ }
263
+ /**
264
+ * Execute with timeout
265
+ */
266
+ async executeWithTimeout(step, agent, inputs, context, timeout, signal) {
267
+ if (!this.actionHandler) {
268
+ throw new Error("No action handler registered");
269
+ }
270
+ return new Promise((resolve, reject) => {
271
+ const timer = setTimeout(() => {
272
+ this.emit("step:timeout", step, timeout);
273
+ reject(new Error(`Step timed out after ${timeout}ms`));
274
+ }, timeout);
275
+ signal.addEventListener("abort", () => {
276
+ clearTimeout(timer);
277
+ reject(new Error("Step was cancelled"));
278
+ });
279
+ this.actionHandler(agent, step.action, inputs, context).then((outputs) => {
280
+ clearTimeout(timer);
281
+ resolve(outputs);
282
+ }).catch((error) => {
283
+ clearTimeout(timer);
284
+ reject(error);
285
+ });
286
+ });
287
+ }
288
+ /**
289
+ * Calculate retry delay
290
+ */
291
+ calculateDelay(config, attempt) {
292
+ let delay = config.delay;
293
+ switch (config.strategy) {
294
+ case "none":
295
+ return 0;
296
+ case "immediate":
297
+ return 0;
298
+ case "fixed":
299
+ return delay;
300
+ case "exponential":
301
+ delay = delay * Math.pow(config.backoffMultiplier || 2, attempt);
302
+ break;
303
+ }
304
+ if (config.maxDelay && delay > config.maxDelay) {
305
+ delay = config.maxDelay;
306
+ }
307
+ const jitter = delay * 0.1 * (Math.random() * 2 - 1);
308
+ return Math.round(delay + jitter);
309
+ }
310
+ /**
311
+ * Sleep helper
312
+ */
313
+ sleep(ms) {
314
+ return new Promise((resolve) => setTimeout(resolve, ms));
315
+ }
316
+ };
317
+ var defaultExecutor = null;
318
+ function getDefaultExecutor() {
319
+ if (!defaultExecutor) {
320
+ defaultExecutor = new StepExecutor();
321
+ }
322
+ return defaultExecutor;
323
+ }
324
+ function resetDefaultExecutor() {
325
+ defaultExecutor = null;
326
+ }
327
+
328
+ // src/choreography/ChoreographyPlanner.ts
329
+ import { CapabilityMatcher } from "@holoscript/framework/agents";
330
+ function generateId() {
331
+ return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
332
+ }
333
+ var ChoreographyPlanner = class {
334
+ matcher = new CapabilityMatcher();
335
+ /**
336
+ * Create a choreography plan from definition
337
+ */
338
+ createPlan(definition) {
339
+ const planId = generateId();
340
+ const _agents = new Map(definition.agents.map((a) => [a.id, a]));
341
+ const steps = definition.steps.map((stepDef) => {
342
+ const agentId = this.resolveAgent(stepDef.agent, definition.agents);
343
+ if (!agentId) {
344
+ throw new Error(
345
+ `No agent found for step ${stepDef.id || stepDef.name}: ${JSON.stringify(stepDef.agent)}`
346
+ );
347
+ }
348
+ const outputs = {};
349
+ if (stepDef.outputs) {
350
+ for (const [key, value] of Object.entries(stepDef.outputs)) {
351
+ if (typeof value === "string") {
352
+ outputs[key] = { key, type: "unknown" };
353
+ } else {
354
+ outputs[key] = value;
355
+ }
356
+ }
357
+ }
358
+ const step = {
359
+ id: stepDef.id || `step_${generateId()}`,
360
+ name: stepDef.name,
361
+ description: stepDef.description,
362
+ agentId,
363
+ action: stepDef.action,
364
+ inputs: stepDef.inputs || {},
365
+ outputs,
366
+ dependencies: stepDef.dependencies || stepDef.dependsOn || [],
367
+ parallelGroup: stepDef.parallelGroup,
368
+ status: "pending",
369
+ timeout: stepDef.timeout,
370
+ retry: stepDef.retries !== void 0 ? { maxRetries: stepDef.retries } : void 0,
371
+ condition: stepDef.condition,
372
+ hitlGate: stepDef.hitlGate,
373
+ fallbackStepId: stepDef.fallbackStepId
374
+ };
375
+ return step;
376
+ });
377
+ const stepNameToId = /* @__PURE__ */ new Map();
378
+ for (const step of steps) {
379
+ if (step.name) {
380
+ stepNameToId.set(step.name, step.id);
381
+ }
382
+ stepNameToId.set(step.id, step.id);
383
+ }
384
+ for (const step of steps) {
385
+ step.dependencies = step.dependencies.map((dep) => {
386
+ const resolvedId = stepNameToId.get(dep);
387
+ if (!resolvedId) {
388
+ throw new Error(`Unknown step dependency "${dep}" in step "${step.name || step.id}"`);
389
+ }
390
+ return resolvedId;
391
+ });
392
+ }
393
+ let fallback;
394
+ if (definition.fallback) {
395
+ fallback = this.createPlan(definition.fallback);
396
+ }
397
+ const plan2 = {
398
+ id: planId,
399
+ name: definition.name,
400
+ goal: definition.goal,
401
+ steps,
402
+ participants: definition.agents,
403
+ constraints: definition.constraints || [],
404
+ fallback,
405
+ status: "draft",
406
+ createdAt: Date.now(),
407
+ priority: definition.priority,
408
+ tags: definition.tags,
409
+ metadata: definition.metadata
410
+ };
411
+ return plan2;
412
+ }
413
+ /**
414
+ * Validate a choreography plan
415
+ */
416
+ validate(plan2) {
417
+ const errors = [];
418
+ const warnings = [];
419
+ const stepIds = new Set(plan2.steps.map((s) => s.id));
420
+ const agentIds = new Set(plan2.participants.map((a) => a.id));
421
+ if (plan2.steps.length === 0) {
422
+ errors.push("Plan has no steps");
423
+ }
424
+ for (const step of plan2.steps) {
425
+ if (!agentIds.has(step.agentId)) {
426
+ errors.push(`Step '${step.id}': Agent '${step.agentId}' not in participants`);
427
+ }
428
+ if (!step.action) {
429
+ errors.push(`Step '${step.id}': No action specified`);
430
+ }
431
+ for (const depId of step.dependencies) {
432
+ if (!stepIds.has(depId)) {
433
+ errors.push(`Step '${step.id}': Dependency '${depId}' does not exist`);
434
+ }
435
+ if (depId === step.id) {
436
+ errors.push(`Step '${step.id}': Cannot depend on itself`);
437
+ }
438
+ }
439
+ }
440
+ const cycleCheck = this.detectCycles(plan2.steps);
441
+ if (cycleCheck) {
442
+ errors.push(`Circular dependency detected: ${cycleCheck.join(" -> ")}`);
443
+ }
444
+ if (!plan2.constraints.some((c) => c.type === "timeout")) {
445
+ warnings.push("No timeout constraint specified");
446
+ }
447
+ if (plan2.steps.some((s) => s.hitlGate) && !plan2.participants.some((a) => a.capabilities?.some((c) => c.type === "approve"))) {
448
+ warnings.push("HITL gate present but no approval agent in participants");
449
+ }
450
+ return {
451
+ valid: errors.length === 0,
452
+ errors,
453
+ warnings
454
+ };
455
+ }
456
+ /**
457
+ * Calculate execution order
458
+ */
459
+ calculateExecutionOrder(plan2) {
460
+ const graph = /* @__PURE__ */ new Map();
461
+ const inDegree = /* @__PURE__ */ new Map();
462
+ for (const step of plan2.steps) {
463
+ graph.set(step.id, step.dependencies);
464
+ inDegree.set(step.id, step.dependencies.length);
465
+ }
466
+ const flatOrder = [];
467
+ const parallelGroups = [];
468
+ const queue = [];
469
+ for (const [stepId, degree] of inDegree.entries()) {
470
+ if (degree === 0) {
471
+ queue.push(stepId);
472
+ }
473
+ }
474
+ while (queue.length > 0) {
475
+ const currentGroup = [...queue];
476
+ parallelGroups.push(currentGroup);
477
+ queue.length = 0;
478
+ for (const stepId of currentGroup) {
479
+ flatOrder.push(stepId);
480
+ for (const [otherId, deps] of graph.entries()) {
481
+ if (deps.includes(stepId)) {
482
+ const newDegree = (inDegree.get(otherId) || 0) - 1;
483
+ inDegree.set(otherId, newDegree);
484
+ if (newDegree === 0) {
485
+ queue.push(otherId);
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+ return {
492
+ parallelGroups,
493
+ flatOrder,
494
+ graph
495
+ };
496
+ }
497
+ /**
498
+ * Clone and reset a plan for re-execution
499
+ */
500
+ resetPlan(plan2) {
501
+ return {
502
+ ...plan2,
503
+ id: generateId(),
504
+ status: "draft",
505
+ createdAt: Date.now(),
506
+ startedAt: void 0,
507
+ completedAt: void 0,
508
+ duration: void 0,
509
+ steps: plan2.steps.map((step) => ({
510
+ ...step,
511
+ status: "pending",
512
+ startedAt: void 0,
513
+ completedAt: void 0,
514
+ duration: void 0,
515
+ error: void 0,
516
+ retryAttempt: void 0
517
+ }))
518
+ };
519
+ }
520
+ // ==========================================================================
521
+ // PRIVATE METHODS
522
+ // ==========================================================================
523
+ /**
524
+ * Resolve agent from ID or capability query
525
+ */
526
+ resolveAgent(agentRef, agents) {
527
+ if (typeof agentRef === "string") {
528
+ const agent = agents.find((a) => a.id === agentRef || a.name === agentRef);
529
+ return agent?.id || null;
530
+ }
531
+ const matches = this.matcher.findMatches(agents, agentRef);
532
+ if (matches.length > 0) {
533
+ return matches[0].manifest.id;
534
+ }
535
+ return null;
536
+ }
537
+ /**
538
+ * Detect circular dependencies
539
+ */
540
+ detectCycles(steps) {
541
+ const visited = /* @__PURE__ */ new Set();
542
+ const recursionStack = /* @__PURE__ */ new Set();
543
+ const stepMap = new Map(steps.map((s) => [s.id, s]));
544
+ const dfs = (stepId, path) => {
545
+ if (recursionStack.has(stepId)) {
546
+ return [...path, stepId];
547
+ }
548
+ if (visited.has(stepId)) {
549
+ return null;
550
+ }
551
+ visited.add(stepId);
552
+ recursionStack.add(stepId);
553
+ const step = stepMap.get(stepId);
554
+ if (step) {
555
+ for (const depId of step.dependencies) {
556
+ const cycle = dfs(depId, [...path, stepId]);
557
+ if (cycle) return cycle;
558
+ }
559
+ }
560
+ recursionStack.delete(stepId);
561
+ return null;
562
+ };
563
+ for (const step of steps) {
564
+ const cycle = dfs(step.id, []);
565
+ if (cycle) return cycle;
566
+ }
567
+ return null;
568
+ }
569
+ };
570
+ var PlanBuilder = class {
571
+ definition;
572
+ planner = new ChoreographyPlanner();
573
+ constructor(goal) {
574
+ this.definition = {
575
+ goal,
576
+ agents: [],
577
+ steps: [],
578
+ constraints: []
579
+ };
580
+ }
581
+ /**
582
+ * Set plan name
583
+ */
584
+ name(name) {
585
+ this.definition.name = name;
586
+ return this;
587
+ }
588
+ /**
589
+ * Add an agent to the plan
590
+ */
591
+ agent(manifest) {
592
+ this.definition.agents.push(manifest);
593
+ return this;
594
+ }
595
+ /**
596
+ * Add multiple agents
597
+ */
598
+ agents(manifests) {
599
+ this.definition.agents.push(...manifests);
600
+ return this;
601
+ }
602
+ /**
603
+ * Add a step to the plan
604
+ */
605
+ step(definition) {
606
+ this.definition.steps.push(definition);
607
+ return this;
608
+ }
609
+ /**
610
+ * Add a constraint
611
+ */
612
+ constraint(constraint) {
613
+ this.definition.constraints.push(constraint);
614
+ return this;
615
+ }
616
+ /**
617
+ * Set timeout constraint
618
+ */
619
+ timeout(ms) {
620
+ this.definition.constraints.push({
621
+ type: "timeout",
622
+ value: ms,
623
+ hard: true,
624
+ description: `Maximum ${ms}ms execution time`
625
+ });
626
+ return this;
627
+ }
628
+ /**
629
+ * Set concurrency constraint
630
+ */
631
+ concurrency(max) {
632
+ this.definition.constraints.push({
633
+ type: "concurrency",
634
+ value: max,
635
+ description: `Maximum ${max} concurrent steps`
636
+ });
637
+ return this;
638
+ }
639
+ /**
640
+ * Set fallback plan
641
+ */
642
+ fallback(fallbackPlan) {
643
+ this.definition.fallback = fallbackPlan;
644
+ return this;
645
+ }
646
+ /**
647
+ * Set priority
648
+ */
649
+ priority(priority) {
650
+ this.definition.priority = priority;
651
+ return this;
652
+ }
653
+ /**
654
+ * Add tags
655
+ */
656
+ tags(...tags) {
657
+ this.definition.tags = [...this.definition.tags || [], ...tags];
658
+ return this;
659
+ }
660
+ /**
661
+ * Set metadata
662
+ */
663
+ metadata(meta) {
664
+ this.definition.metadata = { ...this.definition.metadata || {}, ...meta };
665
+ return this;
666
+ }
667
+ /**
668
+ * Build and validate the plan
669
+ */
670
+ build() {
671
+ const plan2 = this.planner.createPlan(this.definition);
672
+ const validation = this.planner.validate(plan2);
673
+ if (!validation.valid) {
674
+ throw new Error(`Plan validation failed:
675
+ ${validation.errors.join("\n")}`);
676
+ }
677
+ return plan2;
678
+ }
679
+ /**
680
+ * Build without validation (for testing)
681
+ */
682
+ buildUnsafe() {
683
+ return this.planner.createPlan(this.definition);
684
+ }
685
+ };
686
+ function plan(goal) {
687
+ return new PlanBuilder(goal);
688
+ }
689
+ var defaultPlanner = null;
690
+ function getDefaultPlanner() {
691
+ if (!defaultPlanner) {
692
+ defaultPlanner = new ChoreographyPlanner();
693
+ }
694
+ return defaultPlanner;
695
+ }
696
+
697
+ // src/choreography/ChoreographyEngine.ts
698
+ import { EventEmitter as EventEmitter2 } from "events";
699
+ var DEFAULT_ENGINE_CONFIG = {
700
+ maxConcurrency: 4,
701
+ defaultTimeout: 3e4,
702
+ executeFallback: true,
703
+ autoHitlPause: true,
704
+ verbose: false
705
+ };
706
+ var ChoreographyEngine = class extends EventEmitter2 {
707
+ config;
708
+ planner;
709
+ executor;
710
+ registry = null;
711
+ activePlans = /* @__PURE__ */ new Map();
712
+ actionHandler = null;
713
+ constructor(config = {}) {
714
+ super();
715
+ this.config = { ...DEFAULT_ENGINE_CONFIG, ...config };
716
+ this.planner = getDefaultPlanner();
717
+ this.executor = getDefaultExecutor();
718
+ this.executor.on("step:completed", (step, result) => {
719
+ const state = this.findPlanWithStep(step.id);
720
+ if (state) {
721
+ this.emit("step:completed", result, state.plan);
722
+ }
723
+ });
724
+ this.executor.on("step:failed", (step, error) => {
725
+ const state = this.findPlanWithStep(step.id);
726
+ if (state) {
727
+ this.emit("step:failed", step, error, state.plan);
728
+ }
729
+ });
730
+ this.executor.on("step:retrying", (step, attempt, _delay) => {
731
+ const state = this.findPlanWithStep(step.id);
732
+ if (state) {
733
+ this.emit("step:retrying", step, attempt, state.plan);
734
+ }
735
+ });
736
+ }
737
+ /**
738
+ * Set the agent registry
739
+ */
740
+ setRegistry(registry) {
741
+ this.registry = registry;
742
+ }
743
+ /**
744
+ * Set the action handler for executing agent actions
745
+ */
746
+ setActionHandler(handler) {
747
+ this.actionHandler = handler;
748
+ this.executor.setActionHandler(handler);
749
+ }
750
+ /**
751
+ * Create a new choreography plan
752
+ */
753
+ createPlan(goal, agents, steps) {
754
+ const plan2 = {
755
+ id: this.generateId(),
756
+ goal,
757
+ steps: [...steps],
758
+ participants: [...agents],
759
+ constraints: [],
760
+ status: "draft",
761
+ createdAt: Date.now()
762
+ };
763
+ this.emit("plan:created", plan2);
764
+ return plan2;
765
+ }
766
+ /**
767
+ * Execute a choreography plan
768
+ */
769
+ async execute(plan2, variables = {}) {
770
+ if (!this.actionHandler) {
771
+ throw new Error("No action handler registered. Call setActionHandler first.");
772
+ }
773
+ const validation = this.planner.validate(plan2);
774
+ if (!validation.valid) {
775
+ throw new Error(`Plan validation failed: ${validation.errors.join(", ")}`);
776
+ }
777
+ const executionOrder = this.planner.calculateExecutionOrder(plan2);
778
+ const state = {
779
+ plan: plan2,
780
+ stepResults: /* @__PURE__ */ new Map(),
781
+ stepOutputs: /* @__PURE__ */ new Map(),
782
+ executionOrder,
783
+ currentGroup: 0,
784
+ paused: false,
785
+ cancelled: false,
786
+ hitlPending: /* @__PURE__ */ new Set(),
787
+ startTime: Date.now(),
788
+ variables
789
+ };
790
+ this.activePlans.set(plan2.id, state);
791
+ plan2.status = "running";
792
+ plan2.startedAt = state.startTime;
793
+ this.emit("plan:started", plan2);
794
+ try {
795
+ const result = await this.executePlan(state);
796
+ if (!result.success && plan2.fallback && this.config.executeFallback) {
797
+ this.emit("plan:failed", plan2, new Error(result.error || "Unknown error"));
798
+ const fallbackResult = await this.execute(plan2.fallback, variables);
799
+ return {
800
+ ...fallbackResult,
801
+ usedFallback: true
802
+ };
803
+ }
804
+ plan2.status = result.success ? "completed" : "failed";
805
+ plan2.completedAt = Date.now();
806
+ plan2.duration = plan2.completedAt - (plan2.startedAt || state.startTime);
807
+ this.emit("plan:completed", result);
808
+ return result;
809
+ } catch (error) {
810
+ plan2.status = "failed";
811
+ plan2.completedAt = Date.now();
812
+ plan2.duration = plan2.completedAt - (plan2.startedAt || state.startTime);
813
+ const err = error instanceof Error ? error : new Error(String(error));
814
+ this.emit("plan:failed", plan2, err);
815
+ return {
816
+ planId: plan2.id,
817
+ success: false,
818
+ status: "failed",
819
+ stepResults: Array.from(state.stepResults.values()),
820
+ duration: plan2.duration,
821
+ stepsCompleted: state.stepResults.size,
822
+ stepsFailed: Array.from(state.stepResults.values()).filter((r) => !r.success).length,
823
+ stepsSkipped: 0,
824
+ error: err.message,
825
+ finalOutputs: {}
826
+ };
827
+ } finally {
828
+ this.activePlans.delete(plan2.id);
829
+ }
830
+ }
831
+ /**
832
+ * Pause a running plan
833
+ */
834
+ async pause(planId) {
835
+ const state = this.activePlans.get(planId);
836
+ if (!state) {
837
+ return;
838
+ }
839
+ state.paused = true;
840
+ state.plan.status = "paused";
841
+ this.emit("plan:paused", state.plan);
842
+ }
843
+ /**
844
+ * Resume a paused plan
845
+ */
846
+ async resume(planId) {
847
+ const state = this.activePlans.get(planId);
848
+ if (!state) {
849
+ return;
850
+ }
851
+ if (!state.paused) {
852
+ return;
853
+ }
854
+ state.paused = false;
855
+ state.plan.status = "running";
856
+ this.emit("plan:resumed", state.plan);
857
+ }
858
+ /**
859
+ * Cancel a running plan
860
+ */
861
+ async cancel(planId) {
862
+ const state = this.activePlans.get(planId);
863
+ if (!state) {
864
+ return;
865
+ }
866
+ state.cancelled = true;
867
+ state.plan.status = "cancelled";
868
+ for (const step of state.plan.steps) {
869
+ if (step.status === "running") {
870
+ this.executor.cancel(step.id);
871
+ step.status = "cancelled";
872
+ }
873
+ }
874
+ this.emit("plan:cancelled", state.plan);
875
+ }
876
+ /**
877
+ * Approve a HITL gate
878
+ */
879
+ approveHitl(planId, stepId) {
880
+ const state = this.activePlans.get(planId);
881
+ if (!state) {
882
+ throw new Error(`Plan not found: ${planId}`);
883
+ }
884
+ if (!state.hitlPending.has(stepId)) {
885
+ throw new Error(`Step ${stepId} is not pending HITL approval`);
886
+ }
887
+ state.hitlPending.delete(stepId);
888
+ const step = state.plan.steps.find((s) => s.id === stepId);
889
+ if (step) {
890
+ this.emit("hitl:approved", step, state.plan);
891
+ }
892
+ }
893
+ /**
894
+ * Reject a HITL gate
895
+ */
896
+ rejectHitl(planId, stepId, reason) {
897
+ const state = this.activePlans.get(planId);
898
+ if (!state) {
899
+ throw new Error(`Plan not found: ${planId}`);
900
+ }
901
+ if (!state.hitlPending.has(stepId)) {
902
+ throw new Error(`Step ${stepId} is not pending HITL approval`);
903
+ }
904
+ state.hitlPending.delete(stepId);
905
+ const step = state.plan.steps.find((s) => s.id === stepId);
906
+ if (step) {
907
+ step.status = "failed";
908
+ step.error = `HITL rejected: ${reason}`;
909
+ this.emit("hitl:rejected", step, reason, state.plan);
910
+ }
911
+ }
912
+ /**
913
+ * Get active plan IDs
914
+ */
915
+ getActivePlans() {
916
+ return Array.from(this.activePlans.keys());
917
+ }
918
+ /**
919
+ * Get plan status
920
+ */
921
+ getPlanStatus(planId) {
922
+ const state = this.activePlans.get(planId);
923
+ return state?.plan.status || null;
924
+ }
925
+ // ==========================================================================
926
+ // PRIVATE METHODS
927
+ // ==========================================================================
928
+ /**
929
+ * Execute the plan
930
+ */
931
+ async executePlan(state) {
932
+ const { plan: _plan, executionOrder } = state;
933
+ for (const group of executionOrder.parallelGroups) {
934
+ while (state.paused && !state.cancelled) {
935
+ await this.sleep(100);
936
+ }
937
+ if (state.cancelled) {
938
+ break;
939
+ }
940
+ await this.executeGroup(state, group);
941
+ const failed = group.some((stepId) => {
942
+ const result = state.stepResults.get(stepId);
943
+ return result && !result.success;
944
+ });
945
+ if (failed) {
946
+ break;
947
+ }
948
+ state.currentGroup++;
949
+ }
950
+ return this.buildResult(state);
951
+ }
952
+ /**
953
+ * Execute a group of steps (potentially in parallel)
954
+ */
955
+ async executeGroup(state, stepIds) {
956
+ const steps = stepIds.map((id) => state.plan.steps.find((s) => s.id === id)).filter((s) => s !== void 0);
957
+ const concurrency = this.getConcurrencyLimit(state.plan);
958
+ const batches = this.chunk(steps, concurrency);
959
+ for (const batch of batches) {
960
+ if (state.cancelled) break;
961
+ const promises = batch.map((step) => this.executeStep(state, step));
962
+ await Promise.all(promises);
963
+ }
964
+ }
965
+ /**
966
+ * Execute a single step
967
+ */
968
+ async executeStep(state, step) {
969
+ if (step.hitlGate && this.config.autoHitlPause) {
970
+ state.hitlPending.add(step.id);
971
+ this.emit("hitl:required", step, state.plan);
972
+ while (state.hitlPending.has(step.id) && !state.cancelled) {
973
+ await this.sleep(100);
974
+ }
975
+ if (state.cancelled) {
976
+ step.status = "cancelled";
977
+ return;
978
+ }
979
+ if (step.status === "failed") {
980
+ state.stepResults.set(step.id, {
981
+ stepId: step.id,
982
+ success: false,
983
+ outputs: {},
984
+ duration: 0,
985
+ error: step.error
986
+ });
987
+ return;
988
+ }
989
+ }
990
+ const context = this.buildStepContext(state, step);
991
+ this.emit("step:started", step, state.plan);
992
+ const result = await this.executor.execute(step, context);
993
+ if (!result.success && step.fallbackStepId && this.config.executeFallback) {
994
+ const fallbackStep = state.plan.steps.find(
995
+ (s) => s.id === step.fallbackStepId || s.name === step.fallbackStepId
996
+ );
997
+ if (fallbackStep) {
998
+ let fallbackResult = state.stepResults.get(fallbackStep.id);
999
+ if (!fallbackResult && fallbackStep.status === "running") {
1000
+ while (!state.stepResults.has(fallbackStep.id) && !state.cancelled) {
1001
+ await this.sleep(50);
1002
+ }
1003
+ fallbackResult = state.stepResults.get(fallbackStep.id);
1004
+ }
1005
+ if (!fallbackResult && fallbackStep.status === "pending") {
1006
+ await this.executeStep(state, fallbackStep);
1007
+ fallbackResult = state.stepResults.get(fallbackStep.id);
1008
+ }
1009
+ if (fallbackResult?.success) {
1010
+ state.stepResults.set(step.id, {
1011
+ stepId: step.id,
1012
+ success: true,
1013
+ outputs: fallbackResult.outputs,
1014
+ duration: result.duration,
1015
+ usedFallback: true
1016
+ });
1017
+ state.stepOutputs.set(step.id, fallbackResult.outputs);
1018
+ return;
1019
+ }
1020
+ }
1021
+ }
1022
+ state.stepResults.set(step.id, result);
1023
+ if (result.success) {
1024
+ state.stepOutputs.set(step.id, result.outputs);
1025
+ }
1026
+ }
1027
+ /**
1028
+ * Build step context
1029
+ */
1030
+ buildStepContext(state, step) {
1031
+ const agents = new Map(state.plan.participants.map((a) => [a.id, a]));
1032
+ return {
1033
+ plan: state.plan,
1034
+ currentStep: step,
1035
+ agents,
1036
+ stepOutputs: state.stepOutputs,
1037
+ variables: state.variables,
1038
+ startTime: state.startTime,
1039
+ elapsedTime: Date.now() - state.startTime
1040
+ };
1041
+ }
1042
+ /**
1043
+ * Build final result
1044
+ */
1045
+ buildResult(state) {
1046
+ const stepResults = Array.from(state.stepResults.values());
1047
+ const completed = stepResults.filter((r) => r.success).length;
1048
+ const failed = stepResults.filter((r) => !r.success).length;
1049
+ const skipped = state.plan.steps.length - stepResults.length;
1050
+ const completedSteps = state.plan.steps.filter((step) => {
1051
+ const result = state.stepResults.get(step.id);
1052
+ return result?.success;
1053
+ });
1054
+ const failedSteps = state.plan.steps.filter((step) => {
1055
+ const result = state.stepResults.get(step.id);
1056
+ return result && !result.success;
1057
+ });
1058
+ const terminalSteps = state.plan.steps.filter(
1059
+ (s) => !state.plan.steps.some((other) => other.dependencies.includes(s.id))
1060
+ );
1061
+ const finalOutputs = {};
1062
+ for (const step of terminalSteps) {
1063
+ const outputs = state.stepOutputs.get(step.id);
1064
+ if (outputs) {
1065
+ Object.assign(finalOutputs, outputs);
1066
+ }
1067
+ }
1068
+ const success = !state.cancelled && failed === 0 && skipped === 0;
1069
+ return {
1070
+ planId: state.plan.id,
1071
+ success,
1072
+ status: state.cancelled ? "cancelled" : success ? "completed" : "failed",
1073
+ stepResults,
1074
+ duration: Date.now() - state.startTime,
1075
+ stepsCompleted: completed,
1076
+ stepsFailed: failed,
1077
+ stepsSkipped: skipped,
1078
+ completedSteps,
1079
+ failedSteps,
1080
+ error: failed > 0 ? `${failed} step(s) failed` : void 0,
1081
+ finalOutputs,
1082
+ metrics: {
1083
+ peakConcurrency: this.getConcurrencyLimit(state.plan)
1084
+ }
1085
+ };
1086
+ }
1087
+ /**
1088
+ * Get concurrency limit from constraints
1089
+ */
1090
+ getConcurrencyLimit(plan2) {
1091
+ const constraint = plan2.constraints.find((c) => c.type === "concurrency");
1092
+ if (constraint && typeof constraint.value === "number") {
1093
+ return constraint.value;
1094
+ }
1095
+ return this.config.maxConcurrency;
1096
+ }
1097
+ /**
1098
+ * Find plan containing a step
1099
+ */
1100
+ findPlanWithStep(stepId) {
1101
+ for (const state of this.activePlans.values()) {
1102
+ if (state.plan.steps.some((s) => s.id === stepId)) {
1103
+ return state;
1104
+ }
1105
+ }
1106
+ return void 0;
1107
+ }
1108
+ /**
1109
+ * Generate unique ID
1110
+ */
1111
+ generateId() {
1112
+ return `plan_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
1113
+ }
1114
+ /**
1115
+ * Chunk array into batches
1116
+ */
1117
+ chunk(array, size) {
1118
+ const chunks = [];
1119
+ for (let i = 0; i < array.length; i += size) {
1120
+ chunks.push(array.slice(i, i + size));
1121
+ }
1122
+ return chunks;
1123
+ }
1124
+ /**
1125
+ * Sleep helper
1126
+ */
1127
+ sleep(ms) {
1128
+ return new Promise((resolve) => setTimeout(resolve, ms));
1129
+ }
1130
+ };
1131
+ var defaultEngine = null;
1132
+ function getDefaultEngine() {
1133
+ if (!defaultEngine) {
1134
+ defaultEngine = new ChoreographyEngine();
1135
+ }
1136
+ return defaultEngine;
1137
+ }
1138
+ function resetDefaultEngine() {
1139
+ defaultEngine = null;
1140
+ }
1141
+ export {
1142
+ ChoreographyEngine,
1143
+ ChoreographyPlanner,
1144
+ Constraints,
1145
+ DEFAULT_ENGINE_CONFIG,
1146
+ DEFAULT_EXECUTOR_CONFIG,
1147
+ DEFAULT_RETRY_CONFIG,
1148
+ PlanBuilder,
1149
+ StepExecutor,
1150
+ getDefaultEngine,
1151
+ getDefaultExecutor,
1152
+ getDefaultPlanner,
1153
+ plan,
1154
+ resetDefaultEngine,
1155
+ resetDefaultExecutor
1156
+ };