@cadenza.io/core 3.27.0 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1241,6 +1241,7 @@ var SignalBroker = class _SignalBroker {
1241
1241
  this.signalObservers = /* @__PURE__ */ new Map();
1242
1242
  this.emittedSignalsRegistry = /* @__PURE__ */ new Set();
1243
1243
  this.signalMetadataRegistry = /* @__PURE__ */ new Map();
1244
+ this.passiveSignalListeners = /* @__PURE__ */ new Map();
1244
1245
  // ── Flush Strategy Management ───────────────────────────────────────
1245
1246
  this.flushStrategies = /* @__PURE__ */ new Map();
1246
1247
  this.strategyData = /* @__PURE__ */ new Map();
@@ -1321,6 +1322,20 @@ var SignalBroker = class _SignalBroker {
1321
1322
  console.log(
1322
1323
  ` \u2022 emittedSignalsRegistry size: ${this.emittedSignalsRegistry.size}`
1323
1324
  );
1325
+ const exactSignalEntries = Array.from(this.signalObservers.entries()).filter(([signal]) => signal.includes(":")).sort((left, right) => {
1326
+ const taskDelta = right[1].tasks.size - left[1].tasks.size;
1327
+ if (taskDelta !== 0) {
1328
+ return taskDelta;
1329
+ }
1330
+ return left[0].localeCompare(right[0]);
1331
+ });
1332
+ console.log(` \u2022 exact signal observer entries: ${exactSignalEntries.length}`);
1333
+ for (const [signal, observer] of exactSignalEntries.slice(0, 8)) {
1334
+ const sampleTaskNames = Array.from(observer.tasks).slice(0, 3).map((task) => task.name);
1335
+ console.log(
1336
+ ` - ${signal} (${observer.tasks.size} tasks) sample=${sampleTaskNames.join(", ")}`
1337
+ );
1338
+ }
1324
1339
  let totalSquashContexts = 0;
1325
1340
  let totalSquashGroups = 0;
1326
1341
  for (const groups of this.strategyData.values()) {
@@ -1734,7 +1749,7 @@ var SignalBroker = class _SignalBroker {
1734
1749
  this.schedule(signal, context, options);
1735
1750
  return;
1736
1751
  }
1737
- this.addSignal(signal);
1752
+ this.validateSignalName(signal);
1738
1753
  this.execute(signal, context);
1739
1754
  }
1740
1755
  /**
@@ -1813,6 +1828,7 @@ var SignalBroker = class _SignalBroker {
1813
1828
  ...context.__metadata,
1814
1829
  __executionTraceId: executionTraceId
1815
1830
  };
1831
+ this.notifyPassiveSignalListeners(signal, context);
1816
1832
  if (this.debug && (!isMetric && !isSubMeta || this.verbose)) {
1817
1833
  console.log(
1818
1834
  `EMITTING ${signal} to listeners ${this.signalObservers.get(signal)?.tasks.size ?? 0} with context ${this.verbose ? JSON.stringify(context) : JSON.stringify(context).slice(0, 100)}`
@@ -1910,11 +1926,37 @@ var SignalBroker = class _SignalBroker {
1910
1926
  this.addSignal(signal, metadata);
1911
1927
  this.signalObservers.get(signal).tasks.add(routineOrTask);
1912
1928
  }
1929
+ addPassiveSignalListener(listener) {
1930
+ const listenerId = uuid();
1931
+ this.passiveSignalListeners.set(listenerId, listener);
1932
+ return () => {
1933
+ this.passiveSignalListeners.delete(listenerId);
1934
+ };
1935
+ }
1936
+ notifyPassiveSignalListeners(signal, context) {
1937
+ if (this.passiveSignalListeners.size === 0) {
1938
+ return;
1939
+ }
1940
+ const metadata = this.getSignalMetadata(signal) ?? null;
1941
+ for (const listener of this.passiveSignalListeners.values()) {
1942
+ try {
1943
+ listener(signal, context, metadata);
1944
+ } catch (error) {
1945
+ if (this.debug) {
1946
+ console.error("Passive signal listener failed", error);
1947
+ }
1948
+ }
1949
+ }
1950
+ }
1913
1951
  registerEmittedSignal(signal, metadata) {
1952
+ const signalKey = this.resolveSignalMetadataKey(signal);
1953
+ if (!signalKey) {
1954
+ return;
1955
+ }
1914
1956
  if (metadata) {
1915
- this.setSignalMetadata(signal, metadata);
1957
+ this.setSignalMetadata(signalKey, metadata);
1916
1958
  }
1917
- this.emittedSignalsRegistry.add(signal);
1959
+ this.emittedSignalsRegistry.add(signalKey);
1918
1960
  }
1919
1961
  /**
1920
1962
  * Unsubscribes a routine/task from a signal.
@@ -2974,16 +3016,17 @@ var GraphNode = class _GraphNode extends SignalEmitter {
2974
3016
  * @return {void} Does not return a value.
2975
3017
  */
2976
3018
  finalize() {
3019
+ const context = this.context?.getFullContext?.() ?? {};
2977
3020
  if (this.nextNodes.length === 0) {
2978
3021
  this.completeSubgraph();
2979
3022
  }
2980
3023
  if (this.errored || this.failed) {
2981
3024
  this.task.mapOnFailSignals(
2982
- (signal) => this.emitWithMetadata(signal, this.context.getFullContext())
3025
+ (signal) => this.emitWithMetadata(signal, { ...context })
2983
3026
  );
2984
3027
  } else if (this.result !== void 0 && this.result !== false) {
2985
3028
  this.task.mapSignals(
2986
- (signal) => this.emitWithMetadata(signal, this.context.getFullContext())
3029
+ (signal) => this.emitWithMetadata(signal, { ...context })
2987
3030
  );
2988
3031
  }
2989
3032
  this.end();
@@ -2997,8 +3040,9 @@ var GraphNode = class _GraphNode extends SignalEmitter {
2997
3040
  */
2998
3041
  onError(error, errorData = {}) {
2999
3042
  const normalizedError = normalizeGraphErrorMessage(error);
3043
+ const context = this.context?.getFullContext?.() ?? {};
3000
3044
  this.result = {
3001
- ...this.context.getFullContext(),
3045
+ ...context,
3002
3046
  __error: `Node error: ${normalizedError}`,
3003
3047
  __retries: this.retries,
3004
3048
  error: `Node error: ${normalizedError}`,
@@ -3882,7 +3926,13 @@ var Actor = class {
3882
3926
  task(handler, bindingOptions = {}) {
3883
3927
  const mode = bindingOptions.mode ?? "read";
3884
3928
  const taskBindingId = `${this.spec.name}:${++this.nextTaskBindingIndex}`;
3885
- const wrapped = (context, emit, inquire, progressCallback) => {
3929
+ const wrapped = (context, emit, inquire, tools, progressCallback) => {
3930
+ const resolvedTools = tools && typeof tools === "object" && !Array.isArray(tools) && "helpers" in tools && "globals" in tools ? tools : {
3931
+ helpers: {},
3932
+ globals: {}
3933
+ };
3934
+ const resolvedProgressCallback = typeof progressCallback === "function" ? progressCallback : typeof tools === "function" ? tools : () => {
3935
+ };
3886
3936
  const normalizedInput = this.normalizeInputContext(context);
3887
3937
  const invocationOptions = this.resolveInvocationOptions(
3888
3938
  context,
@@ -4002,7 +4052,8 @@ var Actor = class {
4002
4052
  patchRuntimeState,
4003
4053
  reduceRuntimeState,
4004
4054
  emit: (signal, payload = {}) => emit(signal, payload),
4005
- inquire: (inquiryName, inquiryContext = {}, options = {}) => inquire(inquiryName, inquiryContext, options)
4055
+ inquire: (inquiryName, inquiryContext = {}, options = {}) => inquire(inquiryName, inquiryContext, options),
4056
+ tools: resolvedTools
4006
4057
  };
4007
4058
  const handlerResult = await handler(actorContext);
4008
4059
  if (invocationOptions.writeContract === "reducer" && typeof handlerResult === "function") {
@@ -4029,7 +4080,7 @@ var Actor = class {
4029
4080
  stateRecord.lastRuntimeWriteAt = writeTimestamp;
4030
4081
  }
4031
4082
  this.touchSession(actorKey, invocationOptions.touchSession, Date.now());
4032
- progressCallback(100);
4083
+ resolvedProgressCallback(100);
4033
4084
  if (invocationOptions.writeContract === "reducer" && typeof handlerResult === "function") {
4034
4085
  return cloneForDurableState(stateRecord.durableState);
4035
4086
  }
@@ -4073,6 +4124,13 @@ var Actor = class {
4073
4124
  this.pruneExpiredActorKeys(Date.now());
4074
4125
  return this.ensureStateRecord(key).runtimeState;
4075
4126
  }
4127
+ /**
4128
+ * Lists all currently materialized actor keys.
4129
+ */
4130
+ listActorKeys() {
4131
+ this.pruneExpiredActorKeys(Date.now());
4132
+ return Array.from(this.stateByKey.keys()).sort();
4133
+ }
4076
4134
  /**
4077
4135
  * Alias of `getDurableVersion`.
4078
4136
  */
@@ -4482,6 +4540,176 @@ var Actor = class {
4482
4540
  }
4483
4541
  };
4484
4542
 
4543
+ // src/tools/definitions.ts
4544
+ function validateAlias(alias) {
4545
+ const normalized = String(alias ?? "").trim();
4546
+ if (!normalized) {
4547
+ throw new Error("Tool dependency alias must be a non-empty string");
4548
+ }
4549
+ return normalized;
4550
+ }
4551
+ function serializeGlobalValue(value) {
4552
+ if (value === void 0 || typeof value === "function") {
4553
+ throw new Error("Global values must be JSON-serializable");
4554
+ }
4555
+ try {
4556
+ return JSON.parse(JSON.stringify(value));
4557
+ } catch (error) {
4558
+ throw new Error(
4559
+ `Global values must be JSON-serializable: ${error instanceof Error ? error.message : String(error)}`
4560
+ );
4561
+ }
4562
+ }
4563
+ function deepFreeze(value) {
4564
+ if (!value || typeof value !== "object") {
4565
+ return value;
4566
+ }
4567
+ Object.freeze(value);
4568
+ for (const nested of Object.values(value)) {
4569
+ if (nested && typeof nested === "object" && !Object.isFrozen(nested)) {
4570
+ deepFreeze(nested);
4571
+ }
4572
+ }
4573
+ return value;
4574
+ }
4575
+ var GlobalDefinition = class {
4576
+ constructor(name, value, description = "", isMeta = false) {
4577
+ this.version = 1;
4578
+ this.destroyed = false;
4579
+ this.name = name;
4580
+ this.description = description;
4581
+ this.isMeta = isMeta;
4582
+ this.value = deepFreeze(serializeGlobalValue(value));
4583
+ }
4584
+ destroy() {
4585
+ this.destroyed = true;
4586
+ }
4587
+ export() {
4588
+ return {
4589
+ name: this.name,
4590
+ description: this.description,
4591
+ version: this.version,
4592
+ isMeta: this.isMeta,
4593
+ value: this.value
4594
+ };
4595
+ }
4596
+ };
4597
+ var HelperDefinition = class {
4598
+ constructor(name, helperFunction, description = "", isMeta = false) {
4599
+ this.version = 1;
4600
+ this.helperAliases = /* @__PURE__ */ new Map();
4601
+ this.globalAliases = /* @__PURE__ */ new Map();
4602
+ this.destroyed = false;
4603
+ this.name = name;
4604
+ this.description = description;
4605
+ this.isMeta = isMeta;
4606
+ this.helperFunction = helperFunction;
4607
+ }
4608
+ usesHelpers(helpers) {
4609
+ attachHelperDependency(
4610
+ this,
4611
+ this.name,
4612
+ this.version,
4613
+ helpers,
4614
+ "meta.helper.helper_associated"
4615
+ );
4616
+ return this;
4617
+ }
4618
+ usesGlobals(globals) {
4619
+ attachGlobalDependency(
4620
+ this,
4621
+ this.name,
4622
+ this.version,
4623
+ globals,
4624
+ "meta.helper.global_associated"
4625
+ );
4626
+ return this;
4627
+ }
4628
+ execute(context, emit, inquire, progressCallback) {
4629
+ return Cadenza.executeHelper(
4630
+ this,
4631
+ context,
4632
+ emit,
4633
+ inquire,
4634
+ progressCallback
4635
+ );
4636
+ }
4637
+ destroy() {
4638
+ this.destroyed = true;
4639
+ }
4640
+ export() {
4641
+ return {
4642
+ name: this.name,
4643
+ description: this.description,
4644
+ version: this.version,
4645
+ isMeta: this.isMeta,
4646
+ functionString: this.helperFunction.toString(),
4647
+ helperAliases: Object.fromEntries(this.helperAliases),
4648
+ globalAliases: Object.fromEntries(this.globalAliases)
4649
+ };
4650
+ }
4651
+ };
4652
+ function attachHelperDependency(owner, ownerName, ownerVersion, helpers, signalName) {
4653
+ for (const [alias, helper] of Object.entries(helpers)) {
4654
+ const normalizedAlias = validateAlias(alias);
4655
+ if (!helper) {
4656
+ throw new Error(
4657
+ `Helper dependency "${normalizedAlias}" must reference a helper definition`
4658
+ );
4659
+ }
4660
+ if (helper.isMeta !== owner.isMeta) {
4661
+ throw new Error(
4662
+ `${ownerName} cannot use ${helper.isMeta ? "meta" : "business"} helper "${helper.name}" across layer boundaries`
4663
+ );
4664
+ }
4665
+ owner.helperAliases.set(normalizedAlias, helper.name);
4666
+ Cadenza.emit(signalName, {
4667
+ data: {
4668
+ alias: normalizedAlias,
4669
+ ...signalName === "meta.task.helper_associated" ? {
4670
+ taskName: ownerName,
4671
+ taskVersion: ownerVersion
4672
+ } : {
4673
+ helperName: ownerName,
4674
+ helperVersion: ownerVersion
4675
+ },
4676
+ dependencyHelperName: helper.name,
4677
+ dependencyHelperVersion: helper.version
4678
+ }
4679
+ });
4680
+ }
4681
+ }
4682
+ function attachGlobalDependency(owner, ownerName, ownerVersion, globals, signalName) {
4683
+ for (const [alias, globalDefinition] of Object.entries(globals)) {
4684
+ const normalizedAlias = validateAlias(alias);
4685
+ if (!globalDefinition) {
4686
+ throw new Error(
4687
+ `Global dependency "${normalizedAlias}" must reference a global definition`
4688
+ );
4689
+ }
4690
+ if (globalDefinition.isMeta !== owner.isMeta) {
4691
+ throw new Error(
4692
+ `${ownerName} cannot use ${globalDefinition.isMeta ? "meta" : "business"} global "${globalDefinition.name}" across layer boundaries`
4693
+ );
4694
+ }
4695
+ owner.globalAliases.set(normalizedAlias, globalDefinition.name);
4696
+ Cadenza.emit(signalName, {
4697
+ data: {
4698
+ alias: normalizedAlias,
4699
+ ...signalName === "meta.task.global_associated" ? {
4700
+ taskName: ownerName,
4701
+ taskVersion: ownerVersion
4702
+ } : {
4703
+ helperName: ownerName,
4704
+ helperVersion: ownerVersion
4705
+ },
4706
+ globalName: globalDefinition.name,
4707
+ globalVersion: globalDefinition.version
4708
+ }
4709
+ });
4710
+ }
4711
+ }
4712
+
4485
4713
  // src/graph/definition/Task.ts
4486
4714
  function normalizeSignalDefinition(input) {
4487
4715
  if (typeof input === "string") {
@@ -4558,6 +4786,8 @@ var Task = class _Task extends SignalEmitter {
4558
4786
  this.observedSignals = /* @__PURE__ */ new Set();
4559
4787
  this.handlesIntents = /* @__PURE__ */ new Set();
4560
4788
  this.inquiresIntents = /* @__PURE__ */ new Set();
4789
+ this.helperAliases = /* @__PURE__ */ new Map();
4790
+ this.globalAliases = /* @__PURE__ */ new Map();
4561
4791
  this.name = name;
4562
4792
  this.taskFunction = task;
4563
4793
  this.description = description;
@@ -4593,6 +4823,8 @@ var Task = class _Task extends SignalEmitter {
4593
4823
  "meta.task.relationship_added",
4594
4824
  "meta.task.relationship_removed",
4595
4825
  "meta.task.intent_associated",
4826
+ "meta.task.helper_associated",
4827
+ "meta.task.global_associated",
4596
4828
  "meta.task.layer_index_changed",
4597
4829
  "meta.node.scheduled",
4598
4830
  "meta.node.mapped",
@@ -5106,10 +5338,18 @@ var Task = class _Task extends SignalEmitter {
5106
5338
  * @return {TaskResult} The result of the executed task.
5107
5339
  */
5108
5340
  execute(context, emit, inquire, progressCallback, nodeData) {
5341
+ const executionContext = this.isMeta ? context.getClonedFullContext() : context.getClonedContext();
5109
5342
  return this.taskFunction(
5110
- this.isMeta ? context.getClonedFullContext() : context.getClonedContext(),
5343
+ executionContext,
5111
5344
  emit,
5112
5345
  inquire,
5346
+ Cadenza.resolveToolsForOwner(
5347
+ this,
5348
+ executionContext,
5349
+ emit,
5350
+ inquire,
5351
+ progressCallback
5352
+ ),
5113
5353
  progressCallback
5114
5354
  );
5115
5355
  }
@@ -5123,6 +5363,7 @@ var Task = class _Task extends SignalEmitter {
5123
5363
  * @throws {Error} Throws an error if adding a predecessor creates a cycle in the task structure.
5124
5364
  */
5125
5365
  doAfter(...tasks) {
5366
+ Cadenza.assertGraphMutationAllowed("Task#doAfter");
5126
5367
  for (const pred of tasks) {
5127
5368
  if (!pred) continue;
5128
5369
  if (this.predecessorTasks.has(pred)) continue;
@@ -5154,6 +5395,7 @@ var Task = class _Task extends SignalEmitter {
5154
5395
  * @throws {Error} Throws an error if adding a task causes a cyclic dependency.
5155
5396
  */
5156
5397
  then(...tasks) {
5398
+ Cadenza.assertGraphMutationAllowed("Task#then");
5157
5399
  for (const next of tasks) {
5158
5400
  if (!next) continue;
5159
5401
  if (this.nextTasks.has(next)) continue;
@@ -5317,6 +5559,7 @@ var Task = class _Task extends SignalEmitter {
5317
5559
  * @return {this} The current instance after adding the specified signals.
5318
5560
  */
5319
5561
  doOn(...signals) {
5562
+ Cadenza.assertGraphMutationAllowed("Task#doOn");
5320
5563
  signals.forEach((input) => {
5321
5564
  const { name: signal, metadata } = normalizeSignalDefinition(input);
5322
5565
  if (this.observedSignals.has(signal)) return;
@@ -5341,6 +5584,7 @@ var Task = class _Task extends SignalEmitter {
5341
5584
  * @return {this} The current instance for method chaining.
5342
5585
  */
5343
5586
  emits(...signals) {
5587
+ Cadenza.assertGraphMutationAllowed("Task#emits");
5344
5588
  signals.forEach((input) => {
5345
5589
  const { name: signal } = normalizeSignalDefinition(input);
5346
5590
  if (this.observedSignals.has(signal))
@@ -5360,6 +5604,7 @@ var Task = class _Task extends SignalEmitter {
5360
5604
  * @return {this} Returns the current instance for chaining.
5361
5605
  */
5362
5606
  emitsOnFail(...signals) {
5607
+ Cadenza.assertGraphMutationAllowed("Task#emitsOnFail");
5363
5608
  signals.forEach((input) => {
5364
5609
  const { name: signal } = normalizeSignalDefinition(input);
5365
5610
  this.signalsToEmitOnFail.add(signal);
@@ -5374,6 +5619,7 @@ var Task = class _Task extends SignalEmitter {
5374
5619
  * @return {void} This method does not return a value.
5375
5620
  */
5376
5621
  attachSignal(...signals) {
5622
+ Cadenza.assertGraphMutationAllowed("Task#attachSignal");
5377
5623
  signals.forEach((input) => {
5378
5624
  const { name: signal, metadata } = normalizeSignalDefinition(input);
5379
5625
  this.emitsSignals.add(signal);
@@ -5470,6 +5716,7 @@ var Task = class _Task extends SignalEmitter {
5470
5716
  return this;
5471
5717
  }
5472
5718
  respondsTo(...inquires) {
5719
+ Cadenza.assertGraphMutationAllowed("Task#respondsTo");
5473
5720
  for (const intentName of inquires) {
5474
5721
  if (this.handlesIntents.has(intentName)) {
5475
5722
  continue;
@@ -5505,6 +5752,26 @@ var Task = class _Task extends SignalEmitter {
5505
5752
  }
5506
5753
  return this;
5507
5754
  }
5755
+ usesHelpers(helpers) {
5756
+ attachHelperDependency(
5757
+ this,
5758
+ this.name,
5759
+ this.version,
5760
+ helpers,
5761
+ "meta.task.helper_associated"
5762
+ );
5763
+ return this;
5764
+ }
5765
+ usesGlobals(globals) {
5766
+ attachGlobalDependency(
5767
+ this,
5768
+ this.name,
5769
+ this.version,
5770
+ globals,
5771
+ "meta.task.global_associated"
5772
+ );
5773
+ return this;
5774
+ }
5508
5775
  attachIntents(...intentNames) {
5509
5776
  for (const intent of intentNames) {
5510
5777
  this.inquiresIntents.add(intent);
@@ -5597,6 +5864,7 @@ var Task = class _Task extends SignalEmitter {
5597
5864
  this.nextTasks.clear();
5598
5865
  this.predecessorTasks.clear();
5599
5866
  this.destroyed = true;
5867
+ Cadenza.forgetTask(this.name);
5600
5868
  if (this.register) {
5601
5869
  Cadenza.registry.tasks.delete(this.name);
5602
5870
  this.emitMetricsWithMetadata("meta.task.destroyed", {
@@ -5638,6 +5906,8 @@ var Task = class _Task extends SignalEmitter {
5638
5906
  __validateInputContext: this.validateInputContext,
5639
5907
  __outputSchema: this.outputContextSchema,
5640
5908
  __validateOutputContext: this.validateOutputContext,
5909
+ __helperAliases: Object.fromEntries(this.helperAliases),
5910
+ __globalAliases: Object.fromEntries(this.globalAliases),
5641
5911
  __nextTasks: Array.from(this.nextTasks).map((t) => t.name),
5642
5912
  __previousTasks: Array.from(this.predecessorTasks).map((t) => t.name)
5643
5913
  };
@@ -5884,6 +6154,13 @@ var DebounceTask = class extends Task {
5884
6154
  this.lastContext.getClonedContext(),
5885
6155
  this.lastEmitFunction,
5886
6156
  this.lastInquireFunction,
6157
+ Cadenza.resolveToolsForOwner(
6158
+ this,
6159
+ this.lastContext.getClonedContext(),
6160
+ this.lastEmitFunction,
6161
+ this.lastInquireFunction,
6162
+ this.lastProgressCallback
6163
+ ),
5887
6164
  this.lastProgressCallback
5888
6165
  );
5889
6166
  } catch (error) {
@@ -6038,6 +6315,19 @@ var EphemeralTask = class extends Task {
6038
6315
  progressCallback,
6039
6316
  nodeData
6040
6317
  );
6318
+ if (result instanceof Promise) {
6319
+ return result.then((resolved) => {
6320
+ if (this.once || this.condition(resolved)) {
6321
+ this.destroy();
6322
+ }
6323
+ return resolved;
6324
+ }).catch((error) => {
6325
+ if (this.once || this.condition(error)) {
6326
+ this.destroy();
6327
+ }
6328
+ throw error;
6329
+ });
6330
+ }
6041
6331
  if (this.once || this.condition(result)) {
6042
6332
  this.destroy();
6043
6333
  }
@@ -7028,6 +7318,386 @@ var InquiryBroker = class _InquiryBroker extends SignalEmitter {
7028
7318
  }
7029
7319
  };
7030
7320
 
7321
+ // src/runtime/RuntimeDefinitionRegistry.ts
7322
+ function createLinkKey(predecessorTaskName, successorTaskName) {
7323
+ return `${predecessorTaskName}=>${successorTaskName}`;
7324
+ }
7325
+ function createTaskSignalKey(taskName, signalName) {
7326
+ return `${taskName}=>${signalName}`;
7327
+ }
7328
+ function createTaskIntentKey(taskName, intentName) {
7329
+ return `${taskName}=>${intentName}`;
7330
+ }
7331
+ function createRoutineSignalKey(routineName, signalName) {
7332
+ return `${routineName}=>${signalName}`;
7333
+ }
7334
+ var RuntimeDefinitionRegistry = class {
7335
+ constructor() {
7336
+ this.taskDefinitions = /* @__PURE__ */ new Map();
7337
+ this.helperDefinitions = /* @__PURE__ */ new Map();
7338
+ this.globalDefinitions = /* @__PURE__ */ new Map();
7339
+ this.routineDefinitions = /* @__PURE__ */ new Map();
7340
+ this.intentDefinitions = /* @__PURE__ */ new Map();
7341
+ this.actorDefinitions = /* @__PURE__ */ new Map();
7342
+ this.actorTaskDefinitions = /* @__PURE__ */ new Map();
7343
+ this.taskLinks = /* @__PURE__ */ new Map();
7344
+ this.taskSignalObservations = /* @__PURE__ */ new Map();
7345
+ this.taskSignalEmissions = /* @__PURE__ */ new Map();
7346
+ this.taskIntentBindings = /* @__PURE__ */ new Map();
7347
+ this.taskHelperBindings = /* @__PURE__ */ new Map();
7348
+ this.taskGlobalBindings = /* @__PURE__ */ new Map();
7349
+ this.helperHelperBindings = /* @__PURE__ */ new Map();
7350
+ this.helperGlobalBindings = /* @__PURE__ */ new Map();
7351
+ this.routineSignalObservations = /* @__PURE__ */ new Map();
7352
+ }
7353
+ reset() {
7354
+ this.taskDefinitions.clear();
7355
+ this.helperDefinitions.clear();
7356
+ this.globalDefinitions.clear();
7357
+ this.routineDefinitions.clear();
7358
+ this.intentDefinitions.clear();
7359
+ this.actorDefinitions.clear();
7360
+ this.actorTaskDefinitions.clear();
7361
+ this.taskLinks.clear();
7362
+ this.taskSignalObservations.clear();
7363
+ this.taskSignalEmissions.clear();
7364
+ this.taskIntentBindings.clear();
7365
+ this.taskHelperBindings.clear();
7366
+ this.taskGlobalBindings.clear();
7367
+ this.helperHelperBindings.clear();
7368
+ this.helperGlobalBindings.clear();
7369
+ this.routineSignalObservations.clear();
7370
+ }
7371
+ setTaskDefinition(definition) {
7372
+ this.taskDefinitions.set(definition.name, {
7373
+ ...definition,
7374
+ kind: definition.kind ?? "task",
7375
+ options: definition.options ? { ...definition.options } : void 0
7376
+ });
7377
+ }
7378
+ setHelperDefinition(definition) {
7379
+ this.helperDefinitions.set(definition.name, {
7380
+ ...definition,
7381
+ kind: definition.kind ?? "helper"
7382
+ });
7383
+ }
7384
+ setGlobalDefinition(definition) {
7385
+ this.globalDefinitions.set(definition.name, {
7386
+ ...definition,
7387
+ kind: definition.kind ?? "global",
7388
+ value: definition.value
7389
+ });
7390
+ }
7391
+ setRoutineDefinition(definition) {
7392
+ this.routineDefinitions.set(definition.name, {
7393
+ ...definition,
7394
+ startTaskNames: [...definition.startTaskNames],
7395
+ isMeta: definition.isMeta === true
7396
+ });
7397
+ }
7398
+ setIntentDefinition(definition) {
7399
+ this.intentDefinitions.set(definition.name, {
7400
+ ...definition,
7401
+ input: definition.input ? { ...definition.input } : void 0,
7402
+ output: definition.output ? { ...definition.output } : void 0
7403
+ });
7404
+ }
7405
+ setActorDefinition(definition) {
7406
+ this.actorDefinitions.set(definition.name, {
7407
+ ...definition,
7408
+ state: definition.state ? {
7409
+ ...definition.state,
7410
+ durable: definition.state.durable ? { ...definition.state.durable } : void 0,
7411
+ runtime: definition.state.runtime ? { ...definition.state.runtime } : void 0
7412
+ } : void 0,
7413
+ tasks: definition.tasks ? definition.tasks.map((task) => ({ ...task })) : void 0
7414
+ });
7415
+ }
7416
+ setActorTaskDefinition(definition) {
7417
+ this.actorTaskDefinitions.set(definition.taskName, {
7418
+ ...definition,
7419
+ mode: definition.mode ?? "read",
7420
+ options: definition.options ? { ...definition.options } : void 0
7421
+ });
7422
+ }
7423
+ setTaskLink(definition) {
7424
+ this.taskLinks.set(
7425
+ createLinkKey(
7426
+ definition.predecessorTaskName,
7427
+ definition.successorTaskName
7428
+ ),
7429
+ { ...definition }
7430
+ );
7431
+ }
7432
+ setTaskSignalObservation(definition) {
7433
+ const signalName = typeof definition.signal === "string" ? definition.signal : definition.signal.name;
7434
+ this.taskSignalObservations.set(
7435
+ createTaskSignalKey(definition.taskName, signalName),
7436
+ {
7437
+ taskName: definition.taskName,
7438
+ signal: typeof definition.signal === "string" ? definition.signal : {
7439
+ name: definition.signal.name,
7440
+ deliveryMode: definition.signal.deliveryMode,
7441
+ broadcastFilter: definition.signal.broadcastFilter ?? null
7442
+ }
7443
+ }
7444
+ );
7445
+ }
7446
+ setTaskSignalEmission(definition) {
7447
+ const signalName = typeof definition.signal === "string" ? definition.signal : definition.signal.name;
7448
+ this.taskSignalEmissions.set(
7449
+ `${definition.taskName}=>${definition.mode ?? "after"}=>${signalName}`,
7450
+ {
7451
+ taskName: definition.taskName,
7452
+ mode: definition.mode ?? "after",
7453
+ signal: typeof definition.signal === "string" ? definition.signal : {
7454
+ name: definition.signal.name,
7455
+ deliveryMode: definition.signal.deliveryMode,
7456
+ broadcastFilter: definition.signal.broadcastFilter ?? null
7457
+ }
7458
+ }
7459
+ );
7460
+ }
7461
+ setTaskIntentBinding(definition) {
7462
+ this.taskIntentBindings.set(
7463
+ createTaskIntentKey(definition.taskName, definition.intentName),
7464
+ { ...definition }
7465
+ );
7466
+ }
7467
+ setTaskHelperBinding(definition) {
7468
+ this.taskHelperBindings.set(
7469
+ `${definition.taskName}=>${definition.alias}`,
7470
+ { ...definition }
7471
+ );
7472
+ }
7473
+ setTaskGlobalBinding(definition) {
7474
+ this.taskGlobalBindings.set(
7475
+ `${definition.taskName}=>${definition.alias}`,
7476
+ { ...definition }
7477
+ );
7478
+ }
7479
+ setHelperHelperBinding(definition) {
7480
+ this.helperHelperBindings.set(
7481
+ `${definition.helperName}=>${definition.alias}`,
7482
+ { ...definition }
7483
+ );
7484
+ }
7485
+ setHelperGlobalBinding(definition) {
7486
+ this.helperGlobalBindings.set(
7487
+ `${definition.helperName}=>${definition.alias}`,
7488
+ { ...definition }
7489
+ );
7490
+ }
7491
+ setRoutineSignalObservation(definition) {
7492
+ this.routineSignalObservations.set(
7493
+ createRoutineSignalKey(definition.routineName, definition.signal),
7494
+ { ...definition }
7495
+ );
7496
+ }
7497
+ isRuntimeOwnedTask(taskName) {
7498
+ return this.taskDefinitions.has(taskName) || this.actorTaskDefinitions.has(taskName);
7499
+ }
7500
+ isRuntimeOwnedHelper(helperName) {
7501
+ return this.helperDefinitions.has(helperName);
7502
+ }
7503
+ isRuntimeOwnedGlobal(globalName) {
7504
+ return this.globalDefinitions.has(globalName);
7505
+ }
7506
+ isRuntimeOwnedRoutine(routineName) {
7507
+ return this.routineDefinitions.has(routineName);
7508
+ }
7509
+ isRuntimeOwnedActor(actorName) {
7510
+ return this.actorDefinitions.has(actorName);
7511
+ }
7512
+ };
7513
+ var runtimeDefinitionRegistry = new RuntimeDefinitionRegistry();
7514
+
7515
+ // src/runtime/sandbox.ts
7516
+ import vm from "vm";
7517
+ import ts from "typescript";
7518
+ var FORBIDDEN_SOURCE_PATTERNS = [
7519
+ {
7520
+ pattern: /\bimport\b/,
7521
+ message: "Runtime handler source must not contain import statements"
7522
+ },
7523
+ {
7524
+ pattern: /\bexport\b/,
7525
+ message: "Runtime handler source must not contain export statements"
7526
+ },
7527
+ {
7528
+ pattern: /\brequire\s*\(/,
7529
+ message: "Runtime handler source must not call require()"
7530
+ },
7531
+ {
7532
+ pattern: /\bprocess\b/,
7533
+ message: "Runtime handler source must not access process"
7534
+ },
7535
+ {
7536
+ pattern: /\bFunction\s*\(/,
7537
+ message: "Runtime handler source must not create dynamic functions"
7538
+ },
7539
+ {
7540
+ pattern: /\beval\s*\(/,
7541
+ message: "Runtime handler source must not call eval()"
7542
+ }
7543
+ ];
7544
+ function transpileIfNeeded(source, language, filename) {
7545
+ if (language === "js") {
7546
+ return source;
7547
+ }
7548
+ const result = ts.transpileModule(source, {
7549
+ compilerOptions: {
7550
+ target: ts.ScriptTarget.ES2020,
7551
+ module: ts.ModuleKind.ESNext
7552
+ },
7553
+ fileName: filename,
7554
+ reportDiagnostics: true
7555
+ });
7556
+ const diagnostics = result.diagnostics ?? [];
7557
+ const blockingDiagnostics = diagnostics.filter(
7558
+ (diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error
7559
+ );
7560
+ if (blockingDiagnostics.length > 0) {
7561
+ const message = blockingDiagnostics.map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")).join("; ");
7562
+ throw new Error(`TypeScript transpile failed: ${message}`);
7563
+ }
7564
+ return result.outputText;
7565
+ }
7566
+ function createSandbox() {
7567
+ const sandbox = /* @__PURE__ */ Object.create(null);
7568
+ sandbox.global = void 0;
7569
+ sandbox.globalThis = sandbox;
7570
+ sandbox.process = void 0;
7571
+ sandbox.require = void 0;
7572
+ sandbox.module = void 0;
7573
+ sandbox.exports = void 0;
7574
+ sandbox.Buffer = void 0;
7575
+ sandbox.fetch = void 0;
7576
+ sandbox.WebSocket = void 0;
7577
+ sandbox.XMLHttpRequest = void 0;
7578
+ sandbox.setTimeout = void 0;
7579
+ sandbox.setInterval = void 0;
7580
+ sandbox.clearTimeout = void 0;
7581
+ sandbox.clearInterval = void 0;
7582
+ sandbox.queueMicrotask = void 0;
7583
+ return vm.createContext(sandbox);
7584
+ }
7585
+ function compileFunctionFromSource(source, language, filename, label) {
7586
+ const normalizedSource = String(source ?? "").trim();
7587
+ if (!normalizedSource) {
7588
+ throw new Error(`${label} source must be a non-empty string`);
7589
+ }
7590
+ for (const rule of FORBIDDEN_SOURCE_PATTERNS) {
7591
+ if (rule.pattern.test(normalizedSource)) {
7592
+ throw new Error(rule.message);
7593
+ }
7594
+ }
7595
+ const wrappedSource = `const __runtime_handler = ${normalizedSource};
7596
+ __runtime_handler;`;
7597
+ const transpiledSource = transpileIfNeeded(
7598
+ wrappedSource,
7599
+ language,
7600
+ filename
7601
+ ).trim();
7602
+ const sandbox = createSandbox();
7603
+ const script = new vm.Script(transpiledSource, {
7604
+ filename
7605
+ });
7606
+ const compiled = script.runInContext(sandbox, {
7607
+ timeout: 1e3,
7608
+ displayErrors: true,
7609
+ contextCodeGeneration: {
7610
+ strings: false,
7611
+ wasm: false
7612
+ }
7613
+ });
7614
+ if (typeof compiled !== "function") {
7615
+ throw new Error(`${label} source must evaluate to a function`);
7616
+ }
7617
+ return compiled;
7618
+ }
7619
+ function compileRuntimeTaskFunction(definition) {
7620
+ return compileFunctionFromSource(
7621
+ definition.handlerSource,
7622
+ definition.language,
7623
+ `${definition.name}.runtime-task.${definition.language}`,
7624
+ `Task "${definition.name}"`
7625
+ );
7626
+ }
7627
+ function compileRuntimeHelperFunction(definition) {
7628
+ return compileFunctionFromSource(
7629
+ definition.handlerSource,
7630
+ definition.language,
7631
+ `${definition.name}.runtime-helper.${definition.language}`,
7632
+ `Helper "${definition.name}"`
7633
+ );
7634
+ }
7635
+ function compileRuntimeActorTaskHandler(definition) {
7636
+ return compileFunctionFromSource(
7637
+ definition.handlerSource,
7638
+ definition.language,
7639
+ `${definition.actorName}.${definition.taskName}.runtime-actor-task.${definition.language}`,
7640
+ `Actor task "${definition.taskName}"`
7641
+ );
7642
+ }
7643
+
7644
+ // src/runtime/sanitize.ts
7645
+ function isPlainObject2(value) {
7646
+ return typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype;
7647
+ }
7648
+ function sanitizeForJson(value, seen = /* @__PURE__ */ new WeakSet()) {
7649
+ if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
7650
+ return value ?? null;
7651
+ }
7652
+ if (typeof value === "bigint") {
7653
+ return value.toString();
7654
+ }
7655
+ if (typeof value === "function") {
7656
+ return `[Function ${value.name || "anonymous"}]`;
7657
+ }
7658
+ if (typeof value === "symbol") {
7659
+ return value.toString();
7660
+ }
7661
+ if (value instanceof Date) {
7662
+ return value.toISOString();
7663
+ }
7664
+ if (value instanceof Set) {
7665
+ return Array.from(value).map((entry) => sanitizeForJson(entry, seen));
7666
+ }
7667
+ if (value instanceof Map) {
7668
+ return Array.from(value.entries()).map(([key, entry]) => [
7669
+ sanitizeForJson(key, seen),
7670
+ sanitizeForJson(entry, seen)
7671
+ ]);
7672
+ }
7673
+ if (Array.isArray(value)) {
7674
+ return value.map((entry) => sanitizeForJson(entry, seen));
7675
+ }
7676
+ if (typeof value === "object") {
7677
+ if (seen.has(value)) {
7678
+ return "[Circular]";
7679
+ }
7680
+ seen.add(value);
7681
+ if (!isPlainObject2(value)) {
7682
+ const clone = {};
7683
+ for (const key of Object.keys(value)) {
7684
+ clone[key] = sanitizeForJson(
7685
+ value[key],
7686
+ seen
7687
+ );
7688
+ }
7689
+ clone.__type = value.constructor?.name ?? "Object";
7690
+ return clone;
7691
+ }
7692
+ const result = {};
7693
+ for (const [key, entry] of Object.entries(value)) {
7694
+ result[key] = sanitizeForJson(entry, seen);
7695
+ }
7696
+ return result;
7697
+ }
7698
+ return String(value);
7699
+ }
7700
+
7031
7701
  // src/Cadenza.ts
7032
7702
  var Cadenza = class {
7033
7703
  /**
@@ -7110,6 +7780,73 @@ var Cadenza = class {
7110
7780
  throw new Error("Task or Routine name must be a non-empty string.");
7111
7781
  }
7112
7782
  }
7783
+ static assertGraphMutationAllowed(operationName) {
7784
+ if (this.helperExecutionDepth > 0) {
7785
+ throw new Error(
7786
+ `${operationName} is not allowed during helper execution`
7787
+ );
7788
+ }
7789
+ }
7790
+ static executeHelper(helper, context, emit, inquire, progressCallback) {
7791
+ const helperContext = context && typeof context === "object" ? context : {};
7792
+ const tools = this.resolveToolsForOwner(
7793
+ helper,
7794
+ helperContext,
7795
+ emit,
7796
+ inquire,
7797
+ progressCallback
7798
+ );
7799
+ this.helperExecutionDepth += 1;
7800
+ try {
7801
+ return helper.helperFunction(
7802
+ helperContext,
7803
+ emit,
7804
+ inquire,
7805
+ tools,
7806
+ progressCallback
7807
+ );
7808
+ } finally {
7809
+ this.helperExecutionDepth = Math.max(0, this.helperExecutionDepth - 1);
7810
+ }
7811
+ }
7812
+ static resolveToolsForOwner(owner, context, emit, inquire, progressCallback) {
7813
+ const helpers = {};
7814
+ const globals = {};
7815
+ for (const [alias, helperName] of owner.helperAliases.entries()) {
7816
+ const helper = this.getHelper(helperName);
7817
+ if (!helper) {
7818
+ continue;
7819
+ }
7820
+ if (helper.isMeta !== owner.isMeta) {
7821
+ throw new Error(
7822
+ `Tool alias "${alias}" resolves across layer boundaries`
7823
+ );
7824
+ }
7825
+ helpers[alias] = (helperContext = context) => this.executeHelper(
7826
+ helper,
7827
+ helperContext,
7828
+ emit,
7829
+ inquire,
7830
+ progressCallback
7831
+ );
7832
+ }
7833
+ for (const [alias, globalName] of owner.globalAliases.entries()) {
7834
+ const globalDefinition = this.getGlobal(globalName);
7835
+ if (!globalDefinition) {
7836
+ continue;
7837
+ }
7838
+ if (globalDefinition.isMeta !== owner.isMeta) {
7839
+ throw new Error(
7840
+ `Global alias "${alias}" resolves across layer boundaries`
7841
+ );
7842
+ }
7843
+ globals[alias] = globalDefinition.value;
7844
+ }
7845
+ return {
7846
+ helpers,
7847
+ globals
7848
+ };
7849
+ }
7113
7850
  static resolveTaskOptionsForActorTask(func, options = {}) {
7114
7851
  const metadata = getActorTaskRuntimeMetadata(func);
7115
7852
  if (!metadata?.forceMeta) {
@@ -7126,6 +7863,22 @@ var Cadenza = class {
7126
7863
  static registerActor(actor) {
7127
7864
  this.actorCache.set(actor.spec.name, actor);
7128
7865
  }
7866
+ static getHelper(name) {
7867
+ return this.helperCache.get(name);
7868
+ }
7869
+ static getAllHelpers() {
7870
+ return Array.from(this.helperCache.values()).filter(
7871
+ (helper) => !helper.destroyed
7872
+ );
7873
+ }
7874
+ static getGlobal(name) {
7875
+ return this.globalCache.get(name);
7876
+ }
7877
+ static getAllGlobals() {
7878
+ return Array.from(this.globalCache.values()).filter(
7879
+ (globalDefinition) => !globalDefinition.destroyed
7880
+ );
7881
+ }
7129
7882
  /**
7130
7883
  * Executes the specified task or GraphRoutine with the given context using an internal runner.
7131
7884
  *
@@ -7188,6 +7941,9 @@ var Cadenza = class {
7188
7941
  static get(taskName) {
7189
7942
  return this.registry?.tasks.get(taskName) ?? this.taskCache.get(taskName);
7190
7943
  }
7944
+ static forgetTask(taskName) {
7945
+ this.taskCache.delete(taskName);
7946
+ }
7191
7947
  static getActor(actorName) {
7192
7948
  return this.actorCache.get(actorName);
7193
7949
  }
@@ -7195,9 +7951,10 @@ var Cadenza = class {
7195
7951
  return Array.from(this.actorCache.values());
7196
7952
  }
7197
7953
  static getRoutine(routineName) {
7198
- return this.registry?.routines.get(routineName);
7954
+ return this.registry?.routines.get(routineName) ?? this.routineCache.get(routineName);
7199
7955
  }
7200
7956
  static defineIntent(intent) {
7957
+ this.assertGraphMutationAllowed("Cadenza.defineIntent");
7201
7958
  this.inquiryBroker?.addIntent(intent);
7202
7959
  return intent;
7203
7960
  }
@@ -7351,6 +8108,7 @@ var Cadenza = class {
7351
8108
  * participate in the graph like any other task.
7352
8109
  */
7353
8110
  static createActor(spec, options = {}) {
8111
+ this.assertGraphMutationAllowed("Cadenza.createActor");
7354
8112
  this.bootstrap();
7355
8113
  const actor = new Actor(spec, options);
7356
8114
  this.registerActor(actor);
@@ -7466,6 +8224,7 @@ var Cadenza = class {
7466
8224
  * ```
7467
8225
  */
7468
8226
  static createTask(name, func, description, options = {}) {
8227
+ this.assertGraphMutationAllowed("Cadenza.createTask");
7469
8228
  this.bootstrap();
7470
8229
  this.validateName(name);
7471
8230
  const actorResolvedOptions = this.resolveTaskOptionsForActorTask(
@@ -7515,14 +8274,172 @@ var Cadenza = class {
7515
8274
  this.taskCache.set(name, createdTask);
7516
8275
  return createdTask;
7517
8276
  }
7518
- /**
7519
- * Creates a meta task with the specified name, functionality, description, and options.
7520
- * This is used for creating tasks that lives on the meta layer.
7521
- * The meta layer is a special layer that is executed separately from the business logic layer and is used for extending Cadenzas core functionality.
7522
- * See {@link Task} or {@link createTask} for more information.
7523
- *
7524
- * @param {string} name - The name of the meta task.
7525
- * @param {TaskFunction} func - The function to be executed by the meta task.
8277
+ static createTaskFromDefinition(definition) {
8278
+ this.bootstrap();
8279
+ this.validateName(definition.name);
8280
+ const existing = this.get(definition.name);
8281
+ if (existing) {
8282
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedTask(definition.name)) {
8283
+ throw new Error(
8284
+ `Task "${definition.name}" already exists and is not runtime-owned`
8285
+ );
8286
+ }
8287
+ existing.destroy();
8288
+ }
8289
+ const taskFunction = compileRuntimeTaskFunction(definition);
8290
+ const createdTask = definition.kind === "metaTask" ? this.createMetaTask(
8291
+ definition.name,
8292
+ taskFunction,
8293
+ definition.description ?? "",
8294
+ definition.options ?? {}
8295
+ ) : this.createTask(
8296
+ definition.name,
8297
+ taskFunction,
8298
+ definition.description ?? "",
8299
+ definition.options ?? {}
8300
+ );
8301
+ runtimeDefinitionRegistry.setTaskDefinition(definition);
8302
+ return createdTask;
8303
+ }
8304
+ static createHelper(name, func, description = "") {
8305
+ this.bootstrap();
8306
+ this.validateName(name);
8307
+ this.assertGraphMutationAllowed("Cadenza.createHelper");
8308
+ if (this.helperCache.has(name)) {
8309
+ throw new Error(`Helper "${name}" already exists`);
8310
+ }
8311
+ const helper = new HelperDefinition(name, func, description, false);
8312
+ this.helperCache.set(name, helper);
8313
+ this.emit("meta.helper.created", {
8314
+ data: {
8315
+ name,
8316
+ version: helper.version,
8317
+ description,
8318
+ functionString: func.toString(),
8319
+ isMeta: false
8320
+ }
8321
+ });
8322
+ return helper;
8323
+ }
8324
+ static createMetaHelper(name, func, description = "") {
8325
+ this.bootstrap();
8326
+ this.validateName(name);
8327
+ this.assertGraphMutationAllowed("Cadenza.createMetaHelper");
8328
+ if (this.helperCache.has(name)) {
8329
+ throw new Error(`Helper "${name}" already exists`);
8330
+ }
8331
+ const helper = new HelperDefinition(name, func, description, true);
8332
+ this.helperCache.set(name, helper);
8333
+ this.emit("meta.helper.created", {
8334
+ data: {
8335
+ name,
8336
+ version: helper.version,
8337
+ description,
8338
+ functionString: func.toString(),
8339
+ isMeta: true
8340
+ }
8341
+ });
8342
+ return helper;
8343
+ }
8344
+ static createHelperFromDefinition(definition) {
8345
+ this.bootstrap();
8346
+ this.validateName(definition.name);
8347
+ const existing = this.getHelper(definition.name);
8348
+ if (existing) {
8349
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedHelper(definition.name)) {
8350
+ throw new Error(
8351
+ `Helper "${definition.name}" already exists and is not runtime-owned`
8352
+ );
8353
+ }
8354
+ existing.destroy();
8355
+ this.helperCache.delete(definition.name);
8356
+ }
8357
+ const helperFunction = compileRuntimeHelperFunction(definition);
8358
+ const helper = definition.kind === "metaHelper" ? this.createMetaHelper(
8359
+ definition.name,
8360
+ helperFunction,
8361
+ definition.description ?? ""
8362
+ ) : this.createHelper(
8363
+ definition.name,
8364
+ helperFunction,
8365
+ definition.description ?? ""
8366
+ );
8367
+ runtimeDefinitionRegistry.setHelperDefinition(definition);
8368
+ return helper;
8369
+ }
8370
+ static createGlobal(name, value, description = "") {
8371
+ this.bootstrap();
8372
+ this.validateName(name);
8373
+ this.assertGraphMutationAllowed("Cadenza.createGlobal");
8374
+ if (this.globalCache.has(name)) {
8375
+ throw new Error(`Global "${name}" already exists`);
8376
+ }
8377
+ const globalDefinition = new GlobalDefinition(name, value, description, false);
8378
+ this.globalCache.set(name, globalDefinition);
8379
+ this.emit("meta.global.created", {
8380
+ data: {
8381
+ name,
8382
+ version: globalDefinition.version,
8383
+ description,
8384
+ isMeta: false,
8385
+ value: globalDefinition.value
8386
+ }
8387
+ });
8388
+ return globalDefinition;
8389
+ }
8390
+ static createMetaGlobal(name, value, description = "") {
8391
+ this.bootstrap();
8392
+ this.validateName(name);
8393
+ this.assertGraphMutationAllowed("Cadenza.createMetaGlobal");
8394
+ if (this.globalCache.has(name)) {
8395
+ throw new Error(`Global "${name}" already exists`);
8396
+ }
8397
+ const globalDefinition = new GlobalDefinition(name, value, description, true);
8398
+ this.globalCache.set(name, globalDefinition);
8399
+ this.emit("meta.global.created", {
8400
+ data: {
8401
+ name,
8402
+ version: globalDefinition.version,
8403
+ description,
8404
+ isMeta: true,
8405
+ value: globalDefinition.value
8406
+ }
8407
+ });
8408
+ return globalDefinition;
8409
+ }
8410
+ static createGlobalFromDefinition(definition) {
8411
+ this.bootstrap();
8412
+ this.validateName(definition.name);
8413
+ const existing = this.getGlobal(definition.name);
8414
+ if (existing) {
8415
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedGlobal(definition.name)) {
8416
+ throw new Error(
8417
+ `Global "${definition.name}" already exists and is not runtime-owned`
8418
+ );
8419
+ }
8420
+ existing.destroy();
8421
+ this.globalCache.delete(definition.name);
8422
+ }
8423
+ const globalDefinition = definition.kind === "metaGlobal" ? this.createMetaGlobal(
8424
+ definition.name,
8425
+ definition.value,
8426
+ definition.description ?? ""
8427
+ ) : this.createGlobal(
8428
+ definition.name,
8429
+ definition.value,
8430
+ definition.description ?? ""
8431
+ );
8432
+ runtimeDefinitionRegistry.setGlobalDefinition(definition);
8433
+ return globalDefinition;
8434
+ }
8435
+ /**
8436
+ * Creates a meta task with the specified name, functionality, description, and options.
8437
+ * This is used for creating tasks that lives on the meta layer.
8438
+ * The meta layer is a special layer that is executed separately from the business logic layer and is used for extending Cadenzas core functionality.
8439
+ * See {@link Task} or {@link createTask} for more information.
8440
+ *
8441
+ * @param {string} name - The name of the meta task.
8442
+ * @param {TaskFunction} func - The function to be executed by the meta task.
7526
8443
  * @param {string} [description] - An optional description of the meta task.
7527
8444
  * @param {TaskOptions} [options={}] - Additional optional task configuration. Automatically sets `isMeta` to true.
7528
8445
  * @return {Task} A task instance configured as a meta task.
@@ -7580,6 +8497,7 @@ var Cadenza = class {
7580
8497
  *
7581
8498
  */
7582
8499
  static createUniqueTask(name, func, description, options = {}) {
8500
+ this.assertGraphMutationAllowed("Cadenza.createUniqueTask");
7583
8501
  options.isUnique = true;
7584
8502
  return this.createTask(name, func, description, options);
7585
8503
  }
@@ -7628,6 +8546,7 @@ var Cadenza = class {
7628
8546
  * ```
7629
8547
  */
7630
8548
  static createThrottledTask(name, func, throttledIdGetter = () => "default", description, options = {}) {
8549
+ this.assertGraphMutationAllowed("Cadenza.createThrottledTask");
7631
8550
  options.concurrency = 1;
7632
8551
  options.getTagCallback = throttledIdGetter;
7633
8552
  return this.createTask(name, func, description, options);
@@ -7687,6 +8606,7 @@ var Cadenza = class {
7687
8606
  * ```
7688
8607
  */
7689
8608
  static createDebounceTask(name, func, description, debounceTime = 1e3, options = {}) {
8609
+ this.assertGraphMutationAllowed("Cadenza.createDebounceTask");
7690
8610
  this.bootstrap();
7691
8611
  this.validateName(name);
7692
8612
  const actorResolvedOptions = this.resolveTaskOptionsForActorTask(
@@ -7815,6 +8735,7 @@ var Cadenza = class {
7815
8735
  * ```
7816
8736
  */
7817
8737
  static createEphemeralTask(name, func, description, options = {}) {
8738
+ this.assertGraphMutationAllowed("Cadenza.createEphemeralTask");
7818
8739
  this.bootstrap();
7819
8740
  this.validateName(name);
7820
8741
  const actorResolvedOptions = this.resolveTaskOptionsForActorTask(
@@ -7911,12 +8832,46 @@ var Cadenza = class {
7911
8832
  * ```
7912
8833
  */
7913
8834
  static createRoutine(name, tasks, description = "") {
8835
+ this.assertGraphMutationAllowed("Cadenza.createRoutine");
7914
8836
  this.bootstrap();
7915
8837
  this.validateName(name);
7916
8838
  if (tasks.length === 0) {
7917
8839
  throw new Error(`Routine '${name}' created with no starting tasks.`);
7918
8840
  }
7919
- return new GraphRoutine(name, tasks, description);
8841
+ const createdRoutine = new GraphRoutine(name, tasks, description);
8842
+ this.routineCache.set(name, createdRoutine);
8843
+ return createdRoutine;
8844
+ }
8845
+ static createRoutineFromDefinition(definition) {
8846
+ const existing = this.getRoutine(definition.name);
8847
+ if (existing) {
8848
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedRoutine(definition.name)) {
8849
+ throw new Error(
8850
+ `Routine "${definition.name}" already exists and is not runtime-owned`
8851
+ );
8852
+ }
8853
+ existing.destroy();
8854
+ }
8855
+ const startTasks = definition.startTaskNames.map((taskName) => {
8856
+ const task = this.get(taskName);
8857
+ if (!task) {
8858
+ throw new Error(
8859
+ `Routine "${definition.name}" references missing task "${taskName}"`
8860
+ );
8861
+ }
8862
+ return task;
8863
+ });
8864
+ const routine = definition.isMeta === true ? this.createMetaRoutine(
8865
+ definition.name,
8866
+ startTasks,
8867
+ definition.description ?? ""
8868
+ ) : this.createRoutine(
8869
+ definition.name,
8870
+ startTasks,
8871
+ definition.description ?? ""
8872
+ );
8873
+ runtimeDefinitionRegistry.setRoutineDefinition(definition);
8874
+ return routine;
7920
8875
  }
7921
8876
  /**
7922
8877
  * Creates a meta routine with a given name, tasks, and optional description.
@@ -7931,47 +8886,1434 @@ var Cadenza = class {
7931
8886
  * @throws {Error} If no starting tasks are provided.
7932
8887
  */
7933
8888
  static createMetaRoutine(name, tasks, description = "") {
8889
+ this.assertGraphMutationAllowed("Cadenza.createMetaRoutine");
7934
8890
  this.bootstrap();
7935
8891
  this.validateName(name);
7936
8892
  if (tasks.length === 0) {
7937
8893
  throw new Error(`Routine '${name}' created with no starting tasks.`);
7938
8894
  }
7939
- return new GraphRoutine(name, tasks, description, true);
8895
+ const createdRoutine = new GraphRoutine(name, tasks, description, true);
8896
+ this.routineCache.set(name, createdRoutine);
8897
+ return createdRoutine;
8898
+ }
8899
+ static snapshotRuntime() {
8900
+ const taskMap = /* @__PURE__ */ new Map();
8901
+ for (const task of this.taskCache.values()) {
8902
+ taskMap.set(task.name, task);
8903
+ }
8904
+ for (const task of this.registry?.tasks.values() ?? []) {
8905
+ taskMap.set(task.name, task);
8906
+ }
8907
+ const tasks = Array.from(taskMap.values()).map((task) => {
8908
+ const runtimeTaskDefinition = runtimeDefinitionRegistry.taskDefinitions.get(
8909
+ task.name
8910
+ );
8911
+ const runtimeActorTaskDefinition = runtimeDefinitionRegistry.actorTaskDefinitions.get(task.name);
8912
+ return {
8913
+ name: task.name,
8914
+ version: task.version,
8915
+ description: task.description,
8916
+ kind: runtimeActorTaskDefinition ? "actorTask" : task.isMeta ? "metaTask" : "task",
8917
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedTask(task.name) === true,
8918
+ language: runtimeTaskDefinition?.language ?? runtimeActorTaskDefinition?.language ?? null,
8919
+ handlerSource: runtimeTaskDefinition?.handlerSource ?? runtimeActorTaskDefinition?.handlerSource ?? null,
8920
+ concurrency: task.concurrency,
8921
+ timeout: task.timeout,
8922
+ retryCount: task.retryCount,
8923
+ retryDelay: task.retryDelay,
8924
+ retryDelayMax: task.retryDelayMax,
8925
+ retryDelayFactor: task.retryDelayFactor,
8926
+ validateInputContext: task.validateInputContext,
8927
+ validateOutputContext: task.validateOutputContext,
8928
+ inputContextSchema: sanitizeForJson(task.inputContextSchema),
8929
+ outputContextSchema: sanitizeForJson(task.outputContextSchema),
8930
+ nextTaskNames: Array.from(task.nextTasks).map((nextTask) => nextTask.name),
8931
+ predecessorTaskNames: Array.from(task.predecessorTasks).map(
8932
+ (predecessorTask) => predecessorTask.name
8933
+ ),
8934
+ signals: {
8935
+ emits: Array.from(task.emitsSignals),
8936
+ emitsAfter: Array.from(task.signalsToEmitAfter),
8937
+ emitsOnFail: Array.from(task.signalsToEmitOnFail),
8938
+ observed: Array.from(task.observedSignals)
8939
+ },
8940
+ intents: {
8941
+ handles: Array.from(task.handlesIntents),
8942
+ inquires: Array.from(task.inquiresIntents)
8943
+ },
8944
+ tools: {
8945
+ helpers: Object.fromEntries(task.helperAliases),
8946
+ globals: Object.fromEntries(task.globalAliases)
8947
+ },
8948
+ actorName: runtimeActorTaskDefinition?.actorName ?? null,
8949
+ actorMode: runtimeActorTaskDefinition?.mode ?? null
8950
+ };
8951
+ });
8952
+ const helpers = this.getAllHelpers().map((helper) => {
8953
+ const runtimeHelperDefinition = runtimeDefinitionRegistry.helperDefinitions.get(helper.name);
8954
+ return {
8955
+ name: helper.name,
8956
+ version: helper.version,
8957
+ description: helper.description,
8958
+ kind: helper.isMeta ? "metaHelper" : "helper",
8959
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedHelper(helper.name),
8960
+ language: runtimeHelperDefinition?.language ?? null,
8961
+ handlerSource: runtimeHelperDefinition?.handlerSource ?? null,
8962
+ tools: {
8963
+ helpers: Object.fromEntries(helper.helperAliases),
8964
+ globals: Object.fromEntries(helper.globalAliases)
8965
+ }
8966
+ };
8967
+ });
8968
+ const globals = this.getAllGlobals().map((globalDefinition) => ({
8969
+ name: globalDefinition.name,
8970
+ version: globalDefinition.version,
8971
+ description: globalDefinition.description,
8972
+ kind: globalDefinition.isMeta ? "metaGlobal" : "global",
8973
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedGlobal(
8974
+ globalDefinition.name
8975
+ ),
8976
+ value: sanitizeForJson(globalDefinition.value)
8977
+ }));
8978
+ const routineMap = /* @__PURE__ */ new Map();
8979
+ for (const routine of this.routineCache.values()) {
8980
+ routineMap.set(routine.name, routine);
8981
+ }
8982
+ for (const routine of this.registry?.routines.values() ?? []) {
8983
+ routineMap.set(routine.name, routine);
8984
+ }
8985
+ const routines = Array.from(routineMap.values()).map(
8986
+ (routine) => ({
8987
+ name: routine.name,
8988
+ version: routine.version,
8989
+ description: routine.description,
8990
+ isMeta: routine.isMeta,
8991
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedRoutine(routine.name) === true,
8992
+ startTaskNames: Array.from(routine.tasks).map((task) => task.name),
8993
+ observedSignals: Array.from(routine.observedSignals)
8994
+ })
8995
+ );
8996
+ const intents = Array.from(this.inquiryBroker?.intents.values() ?? []).map(
8997
+ (intent) => {
8998
+ const sanitizedIntent = sanitizeForJson(intent);
8999
+ return {
9000
+ ...sanitizedIntent,
9001
+ runtimeOwned: runtimeDefinitionRegistry.intentDefinitions.has(
9002
+ intent.name
9003
+ )
9004
+ };
9005
+ }
9006
+ );
9007
+ const signals = Array.from(
9008
+ this.signalBroker?.emittedSignalsRegistry.values() ?? []
9009
+ ).map((signalName) => ({
9010
+ name: signalName,
9011
+ metadata: sanitizeForJson(
9012
+ this.signalBroker?.signalMetadataRegistry.get(signalName) ?? null
9013
+ ) ?? null
9014
+ }));
9015
+ const actors = this.getAllActors().map((actor) => {
9016
+ const definition = actor.toDefinition();
9017
+ const actorKeys = actor.listActorKeys().map((actorKey) => ({
9018
+ actorKey,
9019
+ durableState: sanitizeForJson(actor.getDurableState(actorKey)),
9020
+ runtimeState: sanitizeForJson(actor.getRuntimeState(actorKey)),
9021
+ durableVersion: actor.getDurableVersion(actorKey),
9022
+ runtimeVersion: actor.getRuntimeVersion(actorKey)
9023
+ }));
9024
+ return {
9025
+ name: actor.spec.name,
9026
+ description: actor.spec.description ?? "",
9027
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedActor(
9028
+ actor.spec.name
9029
+ ),
9030
+ definition: sanitizeForJson(definition),
9031
+ actorKeys
9032
+ };
9033
+ });
9034
+ const actorTasks = Array.from(
9035
+ runtimeDefinitionRegistry.actorTaskDefinitions.values()
9036
+ ).map((definition) => ({
9037
+ actorName: definition.actorName,
9038
+ taskName: definition.taskName,
9039
+ description: definition.description ?? "",
9040
+ mode: definition.mode ?? "read",
9041
+ language: definition.language,
9042
+ handlerSource: definition.handlerSource,
9043
+ runtimeOwned: true
9044
+ }));
9045
+ const links = Array.from(runtimeDefinitionRegistry.taskLinks.values()).map(
9046
+ (link) => ({ ...link })
9047
+ );
9048
+ return {
9049
+ runtimeMode: "core",
9050
+ bootstrapped: this.isBootstrapped,
9051
+ mode: this.mode,
9052
+ tasks,
9053
+ helpers,
9054
+ globals,
9055
+ routines,
9056
+ intents,
9057
+ signals,
9058
+ actors,
9059
+ actorTasks,
9060
+ links
9061
+ };
7940
9062
  }
7941
9063
  static reset() {
7942
9064
  this.signalBroker?.reset();
7943
9065
  this.inquiryBroker?.reset();
7944
9066
  this.registry?.reset();
7945
9067
  this.taskCache.clear();
9068
+ this.routineCache.clear();
7946
9069
  this.actorCache.clear();
9070
+ this.helperCache.clear();
9071
+ this.globalCache.clear();
7947
9072
  this.runtimeInquiryDelegate = void 0;
7948
9073
  this.runtimeValidationPolicy = {};
7949
9074
  this.runtimeValidationScopes.clear();
7950
9075
  this.emittedMissingSchemaWarnings.clear();
9076
+ this.helperExecutionDepth = 0;
9077
+ runtimeDefinitionRegistry.reset();
7951
9078
  this.isBootstrapped = false;
7952
9079
  }
7953
9080
  };
7954
9081
  Cadenza.taskCache = /* @__PURE__ */ new Map();
9082
+ Cadenza.routineCache = /* @__PURE__ */ new Map();
7955
9083
  Cadenza.actorCache = /* @__PURE__ */ new Map();
9084
+ Cadenza.helperCache = /* @__PURE__ */ new Map();
9085
+ Cadenza.globalCache = /* @__PURE__ */ new Map();
7956
9086
  Cadenza.runtimeValidationPolicy = {};
7957
9087
  Cadenza.runtimeValidationScopes = /* @__PURE__ */ new Map();
7958
9088
  Cadenza.emittedMissingSchemaWarnings = /* @__PURE__ */ new Set();
9089
+ Cadenza.helperExecutionDepth = 0;
7959
9090
  Cadenza.isBootstrapped = false;
7960
9091
  Cadenza.mode = "production";
7961
9092
 
9093
+ // src/runtime/RuntimeSubscriptionManager.ts
9094
+ import { v4 as uuid8 } from "uuid";
9095
+ function isObject3(value) {
9096
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9097
+ }
9098
+ function asStringOrNull(value) {
9099
+ return typeof value === "string" && value.length > 0 ? value : null;
9100
+ }
9101
+ function asNumberOrNull(value) {
9102
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
9103
+ }
9104
+ function normalizeEventContext(context) {
9105
+ const sanitized = sanitizeForJson(context);
9106
+ return isObject3(sanitized) ? sanitized : { value: sanitized };
9107
+ }
9108
+ function matchesSignalPattern(fullSignal, signalName, patterns) {
9109
+ return patterns.some((pattern) => {
9110
+ if (pattern === "*") {
9111
+ return true;
9112
+ }
9113
+ if (pattern === fullSignal || pattern === signalName) {
9114
+ return true;
9115
+ }
9116
+ if (!pattern.endsWith(".*")) {
9117
+ return false;
9118
+ }
9119
+ const prefix = pattern.slice(0, -2);
9120
+ return signalName === prefix || signalName.startsWith(`${prefix}.`);
9121
+ });
9122
+ }
9123
+ var RuntimeSubscriptionManagerError = class extends Error {
9124
+ constructor(code, message) {
9125
+ super(message);
9126
+ this.code = code;
9127
+ this.name = "RuntimeSubscriptionManagerError";
9128
+ }
9129
+ };
9130
+ var RuntimeSubscriptionManager = class {
9131
+ constructor() {
9132
+ this.subscriptions = /* @__PURE__ */ new Map();
9133
+ this.removeBrokerListener = null;
9134
+ this.nextSequence = 0;
9135
+ this.attach();
9136
+ }
9137
+ dispose() {
9138
+ this.reset();
9139
+ this.removeBrokerListener?.();
9140
+ this.removeBrokerListener = null;
9141
+ }
9142
+ subscribe(signalPatterns, maxQueueSize) {
9143
+ this.attach();
9144
+ const descriptor = {
9145
+ subscriptionId: uuid8(),
9146
+ signalPatterns: [...signalPatterns],
9147
+ maxQueueSize,
9148
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
9149
+ pendingEvents: 0
9150
+ };
9151
+ this.subscriptions.set(descriptor.subscriptionId, {
9152
+ descriptor,
9153
+ events: [],
9154
+ nextWaiter: null
9155
+ });
9156
+ return { ...descriptor };
9157
+ }
9158
+ unsubscribe(subscriptionId) {
9159
+ const subscription = this.requireSubscription(subscriptionId);
9160
+ this.clearWaiter(
9161
+ subscription,
9162
+ new RuntimeSubscriptionManagerError(
9163
+ "not_found",
9164
+ `Subscription "${subscriptionId}" was closed`
9165
+ )
9166
+ );
9167
+ this.subscriptions.delete(subscriptionId);
9168
+ return { ...subscription.descriptor };
9169
+ }
9170
+ async nextEvent(subscriptionId, timeoutMs) {
9171
+ const subscription = this.requireSubscription(subscriptionId);
9172
+ if (subscription.events.length > 0) {
9173
+ const event = subscription.events.shift() ?? null;
9174
+ subscription.descriptor.pendingEvents = subscription.events.length;
9175
+ return {
9176
+ subscriptionId,
9177
+ event,
9178
+ timedOut: false,
9179
+ pendingEvents: subscription.events.length
9180
+ };
9181
+ }
9182
+ if (timeoutMs <= 0) {
9183
+ return {
9184
+ subscriptionId,
9185
+ event: null,
9186
+ timedOut: true,
9187
+ pendingEvents: 0
9188
+ };
9189
+ }
9190
+ if (subscription.nextWaiter) {
9191
+ throw new RuntimeSubscriptionManagerError(
9192
+ "conflict",
9193
+ `Subscription "${subscriptionId}" already has a pending nextEvent request`
9194
+ );
9195
+ }
9196
+ return new Promise((resolve, reject) => {
9197
+ const timer = setTimeout(() => {
9198
+ subscription.nextWaiter = null;
9199
+ resolve({
9200
+ subscriptionId,
9201
+ event: null,
9202
+ timedOut: true,
9203
+ pendingEvents: subscription.events.length
9204
+ });
9205
+ }, timeoutMs);
9206
+ subscription.nextWaiter = {
9207
+ resolve: (result) => {
9208
+ clearTimeout(timer);
9209
+ subscription.nextWaiter = null;
9210
+ resolve(result);
9211
+ },
9212
+ reject: (error) => {
9213
+ clearTimeout(timer);
9214
+ subscription.nextWaiter = null;
9215
+ reject(error);
9216
+ },
9217
+ timer
9218
+ };
9219
+ });
9220
+ }
9221
+ pollEvents(subscriptionId, limit) {
9222
+ const subscription = this.requireSubscription(subscriptionId);
9223
+ const events = subscription.events.splice(0, limit);
9224
+ subscription.descriptor.pendingEvents = subscription.events.length;
9225
+ return {
9226
+ subscriptionId,
9227
+ events,
9228
+ pendingEvents: subscription.events.length
9229
+ };
9230
+ }
9231
+ reset() {
9232
+ for (const subscription of this.subscriptions.values()) {
9233
+ this.clearWaiter(
9234
+ subscription,
9235
+ new RuntimeSubscriptionManagerError(
9236
+ "not_found",
9237
+ `Subscription "${subscription.descriptor.subscriptionId}" was reset`
9238
+ )
9239
+ );
9240
+ subscription.events.length = 0;
9241
+ subscription.descriptor.pendingEvents = 0;
9242
+ }
9243
+ this.subscriptions.clear();
9244
+ }
9245
+ attach() {
9246
+ if (this.removeBrokerListener) {
9247
+ return;
9248
+ }
9249
+ Cadenza.bootstrap();
9250
+ this.removeBrokerListener = Cadenza.signalBroker.addPassiveSignalListener(
9251
+ (signal, context, metadata) => this.captureSignal(signal, context, metadata)
9252
+ );
9253
+ }
9254
+ captureSignal(signal, context, metadata) {
9255
+ if (this.subscriptions.size === 0) {
9256
+ return;
9257
+ }
9258
+ const normalizedContext = normalizeEventContext(context);
9259
+ const emission = isObject3(normalizedContext.__signalEmission) ? normalizedContext.__signalEmission : {};
9260
+ const metadataObject = isObject3(normalizedContext.__metadata) ? normalizedContext.__metadata : {};
9261
+ const fullSignal = signal;
9262
+ const [baseSignalName, ...signalTagParts] = signal.split(":");
9263
+ const signalName = baseSignalName ?? signal;
9264
+ const signalTag = signalTagParts.length > 0 ? signalTagParts.join(":") : null;
9265
+ const eventTemplate = {
9266
+ type: "signal",
9267
+ signal: fullSignal,
9268
+ signalName,
9269
+ signalTag,
9270
+ emittedAt: asStringOrNull(emission.emittedAt),
9271
+ isMeta: emission.isMeta === true || signalName.startsWith("meta."),
9272
+ isSubMeta: normalizedContext.__isSubMeta === true || signalName.startsWith("sub_meta."),
9273
+ metadata: sanitizeForJson(metadata) ?? null,
9274
+ source: {
9275
+ taskName: asStringOrNull(emission.taskName),
9276
+ taskVersion: asNumberOrNull(emission.taskVersion),
9277
+ taskExecutionId: asStringOrNull(emission.taskExecutionId),
9278
+ routineName: asStringOrNull(normalizedContext.__routineName) ?? asStringOrNull(emission.routineName),
9279
+ routineVersion: asNumberOrNull(normalizedContext.__routineVersion) ?? asNumberOrNull(emission.routineVersion),
9280
+ routineExecutionId: asStringOrNull(normalizedContext.__routineExecId) ?? asStringOrNull(emission.routineExecutionId),
9281
+ executionTraceId: asStringOrNull(emission.executionTraceId) ?? asStringOrNull(normalizedContext.__executionTraceId) ?? asStringOrNull(metadataObject.__executionTraceId),
9282
+ consumed: emission.consumed === true,
9283
+ consumedBy: asStringOrNull(emission.consumedBy)
9284
+ },
9285
+ context: normalizedContext
9286
+ };
9287
+ for (const subscription of this.subscriptions.values()) {
9288
+ if (!matchesSignalPattern(
9289
+ fullSignal,
9290
+ signalName,
9291
+ subscription.descriptor.signalPatterns
9292
+ )) {
9293
+ continue;
9294
+ }
9295
+ const event = {
9296
+ id: uuid8(),
9297
+ subscriptionId: subscription.descriptor.subscriptionId,
9298
+ sequence: ++this.nextSequence,
9299
+ ...eventTemplate
9300
+ };
9301
+ if (subscription.nextWaiter) {
9302
+ subscription.nextWaiter.resolve({
9303
+ subscriptionId: subscription.descriptor.subscriptionId,
9304
+ event,
9305
+ timedOut: false,
9306
+ pendingEvents: subscription.events.length
9307
+ });
9308
+ continue;
9309
+ }
9310
+ subscription.events.push(event);
9311
+ if (subscription.events.length > subscription.descriptor.maxQueueSize) {
9312
+ subscription.events.shift();
9313
+ }
9314
+ subscription.descriptor.pendingEvents = subscription.events.length;
9315
+ }
9316
+ }
9317
+ clearWaiter(subscription, error) {
9318
+ if (!subscription.nextWaiter) {
9319
+ return;
9320
+ }
9321
+ if (subscription.nextWaiter.timer) {
9322
+ clearTimeout(subscription.nextWaiter.timer);
9323
+ }
9324
+ subscription.nextWaiter.reject(error);
9325
+ subscription.nextWaiter = null;
9326
+ }
9327
+ requireSubscription(subscriptionId) {
9328
+ const subscription = this.subscriptions.get(subscriptionId);
9329
+ if (!subscription) {
9330
+ throw new RuntimeSubscriptionManagerError(
9331
+ "not_found",
9332
+ `No subscription named "${subscriptionId}" exists`
9333
+ );
9334
+ }
9335
+ return subscription;
9336
+ }
9337
+ };
9338
+
9339
+ // src/runtime/RuntimeHost.ts
9340
+ var SUPPORTED_OPERATIONS = [
9341
+ "runtime.bootstrap",
9342
+ "runtime.info",
9343
+ "runtime.detach",
9344
+ "runtime.shutdown",
9345
+ "runtime.reset",
9346
+ "runtime.snapshot",
9347
+ "runtime.subscribe",
9348
+ "runtime.unsubscribe",
9349
+ "runtime.nextEvent",
9350
+ "runtime.pollEvents",
9351
+ "task.upsert",
9352
+ "helper.upsert",
9353
+ "global.upsert",
9354
+ "task.link",
9355
+ "task.observeSignal",
9356
+ "task.emitSignal",
9357
+ "task.respondToIntent",
9358
+ "task.useHelper",
9359
+ "task.useGlobal",
9360
+ "helper.useHelper",
9361
+ "helper.useGlobal",
9362
+ "routine.upsert",
9363
+ "routine.observeSignal",
9364
+ "intent.upsert",
9365
+ "actor.upsert",
9366
+ "actorTask.upsert",
9367
+ "run",
9368
+ "emit",
9369
+ "inquire"
9370
+ ];
9371
+ var RuntimeProtocolException = class extends Error {
9372
+ constructor(code, message, details) {
9373
+ super(message);
9374
+ this.code = code;
9375
+ this.details = details;
9376
+ this.name = "RuntimeProtocolException";
9377
+ }
9378
+ };
9379
+ function isObject4(value) {
9380
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9381
+ }
9382
+ function assertObject(value, message) {
9383
+ if (!isObject4(value)) {
9384
+ throw new RuntimeProtocolException("invalid_payload", message);
9385
+ }
9386
+ }
9387
+ function assertString(value, fieldName) {
9388
+ if (typeof value !== "string" || !value.trim()) {
9389
+ throw new RuntimeProtocolException(
9390
+ "invalid_payload",
9391
+ `${fieldName} must be a non-empty string`
9392
+ );
9393
+ }
9394
+ return value;
9395
+ }
9396
+ function assertStringArray(value, fieldName) {
9397
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
9398
+ throw new RuntimeProtocolException(
9399
+ "invalid_payload",
9400
+ `${fieldName} must be an array of strings`
9401
+ );
9402
+ }
9403
+ return value;
9404
+ }
9405
+ function normalizeSignalDefinition2(signal) {
9406
+ if (typeof signal === "string") {
9407
+ return signal;
9408
+ }
9409
+ if (isObject4(signal) && typeof signal.name === "string" && signal.name.trim().length > 0) {
9410
+ return {
9411
+ name: signal.name,
9412
+ deliveryMode: signal.deliveryMode === "single" || signal.deliveryMode === "broadcast" ? signal.deliveryMode : void 0,
9413
+ broadcastFilter: signal.broadcastFilter && isObject4(signal.broadcastFilter) ? signal.broadcastFilter : null
9414
+ };
9415
+ }
9416
+ throw new RuntimeProtocolException(
9417
+ "invalid_payload",
9418
+ "signal must be a signal string or structured signal definition"
9419
+ );
9420
+ }
9421
+ var RuntimeHost = class {
9422
+ constructor(options = {}) {
9423
+ this.pendingControlAction = null;
9424
+ this.subscriptionManager = new RuntimeSubscriptionManager();
9425
+ this.runtimeSharing = options.runtimeSharing ?? "isolated";
9426
+ this.runtimeName = options.runtimeName ?? null;
9427
+ this.sessionId = options.sessionId ?? null;
9428
+ this.sessionRole = options.sessionRole ?? null;
9429
+ this.activeSessionCountProvider = options.activeSessionCountProvider ?? (() => 1);
9430
+ this.daemonProcessId = options.daemonProcessId ?? null;
9431
+ this.onResetRuntime = options.onResetRuntime ?? null;
9432
+ }
9433
+ dispose() {
9434
+ this.subscriptionManager.dispose();
9435
+ }
9436
+ resetSubscriptions() {
9437
+ this.subscriptionManager.reset();
9438
+ }
9439
+ consumeControlAction() {
9440
+ const action = this.pendingControlAction;
9441
+ this.pendingControlAction = null;
9442
+ return action;
9443
+ }
9444
+ handshake() {
9445
+ return {
9446
+ ready: true,
9447
+ protocol: "cadenza-runtime-jsonl",
9448
+ protocolVersion: "1",
9449
+ runtimeMode: "core",
9450
+ runtimeSharing: this.runtimeSharing,
9451
+ runtimeName: this.runtimeName,
9452
+ sessionId: this.sessionId,
9453
+ sessionRole: this.sessionRole,
9454
+ supportedOperations: [...SUPPORTED_OPERATIONS]
9455
+ };
9456
+ }
9457
+ async handle(request) {
9458
+ try {
9459
+ if (!request || typeof request !== "object") {
9460
+ throw new RuntimeProtocolException(
9461
+ "invalid_request",
9462
+ "Request must be an object"
9463
+ );
9464
+ }
9465
+ if (typeof request.operation !== "string" || !SUPPORTED_OPERATIONS.includes(
9466
+ request.operation
9467
+ )) {
9468
+ throw new RuntimeProtocolException(
9469
+ "unsupported_operation",
9470
+ `Unsupported operation: ${String(request.operation ?? "")}`
9471
+ );
9472
+ }
9473
+ const operation = request.operation;
9474
+ this.assertOperationAllowed(operation);
9475
+ const result = await this.dispatch(operation, request.payload);
9476
+ return {
9477
+ id: request.id,
9478
+ operation,
9479
+ ok: true,
9480
+ result: sanitizeForJson(result)
9481
+ };
9482
+ } catch (error) {
9483
+ const normalizedError = this.normalizeError(error);
9484
+ return {
9485
+ id: request?.id,
9486
+ operation: typeof request?.operation === "string" ? request.operation : "runtime.snapshot",
9487
+ ok: false,
9488
+ error: normalizedError
9489
+ };
9490
+ }
9491
+ }
9492
+ normalizeError(error) {
9493
+ if (error instanceof RuntimeSubscriptionManagerError) {
9494
+ return {
9495
+ code: error.code,
9496
+ message: error.message
9497
+ };
9498
+ }
9499
+ if (error instanceof RuntimeProtocolException) {
9500
+ return {
9501
+ code: error.code,
9502
+ message: error.message,
9503
+ details: error.details ? sanitizeForJson(error.details) : void 0
9504
+ };
9505
+ }
9506
+ if (error instanceof Error) {
9507
+ return {
9508
+ code: "runtime_error",
9509
+ message: error.message
9510
+ };
9511
+ }
9512
+ return {
9513
+ code: "runtime_error",
9514
+ message: String(error)
9515
+ };
9516
+ }
9517
+ async dispatch(operation, payload) {
9518
+ switch (operation) {
9519
+ case "runtime.bootstrap":
9520
+ return this.bootstrapRuntime(payload);
9521
+ case "runtime.info":
9522
+ return this.runtimeInfo();
9523
+ case "runtime.detach":
9524
+ return this.detachRuntime();
9525
+ case "runtime.shutdown":
9526
+ return this.shutdownRuntime();
9527
+ case "runtime.reset":
9528
+ return this.resetRuntime();
9529
+ case "runtime.snapshot":
9530
+ return Cadenza.snapshotRuntime();
9531
+ case "runtime.subscribe":
9532
+ return this.subscribe(payload);
9533
+ case "runtime.unsubscribe":
9534
+ return this.unsubscribe(payload);
9535
+ case "runtime.nextEvent":
9536
+ return this.nextEvent(payload);
9537
+ case "runtime.pollEvents":
9538
+ return this.pollEvents(payload);
9539
+ case "task.upsert":
9540
+ return this.upsertTask(payload);
9541
+ case "helper.upsert":
9542
+ return this.upsertHelper(payload);
9543
+ case "global.upsert":
9544
+ return this.upsertGlobal(payload);
9545
+ case "task.link":
9546
+ return this.linkTasks(payload);
9547
+ case "task.observeSignal":
9548
+ return this.observeTaskSignal(payload);
9549
+ case "task.emitSignal":
9550
+ return this.emitTaskSignal(payload);
9551
+ case "task.respondToIntent":
9552
+ return this.bindTaskIntent(payload);
9553
+ case "task.useHelper":
9554
+ return this.bindTaskHelper(payload);
9555
+ case "task.useGlobal":
9556
+ return this.bindTaskGlobal(payload);
9557
+ case "helper.useHelper":
9558
+ return this.bindHelperHelper(payload);
9559
+ case "helper.useGlobal":
9560
+ return this.bindHelperGlobal(payload);
9561
+ case "routine.upsert":
9562
+ return this.upsertRoutine(payload);
9563
+ case "routine.observeSignal":
9564
+ return this.observeRoutineSignal(payload);
9565
+ case "intent.upsert":
9566
+ return this.upsertIntent(payload);
9567
+ case "actor.upsert":
9568
+ return this.upsertActor(payload);
9569
+ case "actorTask.upsert":
9570
+ return this.upsertActorTask(payload);
9571
+ case "run":
9572
+ return this.runTarget(payload);
9573
+ case "emit":
9574
+ return this.emitSignal(payload);
9575
+ case "inquire":
9576
+ return this.inquireIntent(payload);
9577
+ }
9578
+ }
9579
+ assertOperationAllowed(operation) {
9580
+ if (!this.sessionRole) {
9581
+ return;
9582
+ }
9583
+ if (this.sessionRole === "owner") {
9584
+ return;
9585
+ }
9586
+ if (this.sessionRole === "writer") {
9587
+ if (operation === "runtime.reset" || operation === "runtime.shutdown") {
9588
+ throw new RuntimeProtocolException(
9589
+ "forbidden",
9590
+ `Session role "${this.sessionRole}" cannot perform ${operation}`
9591
+ );
9592
+ }
9593
+ return;
9594
+ }
9595
+ const observerOperations = /* @__PURE__ */ new Set([
9596
+ "runtime.info",
9597
+ "runtime.detach",
9598
+ "runtime.snapshot",
9599
+ "runtime.subscribe",
9600
+ "runtime.unsubscribe",
9601
+ "runtime.nextEvent",
9602
+ "runtime.pollEvents",
9603
+ "inquire"
9604
+ ]);
9605
+ if (!observerOperations.has(operation)) {
9606
+ throw new RuntimeProtocolException(
9607
+ "forbidden",
9608
+ `Session role "${this.sessionRole}" cannot perform ${operation}`
9609
+ );
9610
+ }
9611
+ }
9612
+ bootstrapRuntime(payload) {
9613
+ const mode = isObject4(payload) && typeof payload.mode === "string" ? payload.mode : void 0;
9614
+ if (mode) {
9615
+ Cadenza.setMode(mode);
9616
+ } else {
9617
+ Cadenza.bootstrap();
9618
+ }
9619
+ return {
9620
+ bootstrapped: true,
9621
+ mode: Cadenza.mode
9622
+ };
9623
+ }
9624
+ runtimeInfo() {
9625
+ return {
9626
+ runtimeMode: "core",
9627
+ runtimeSharing: this.runtimeSharing,
9628
+ runtimeName: this.runtimeName,
9629
+ sessionId: this.sessionId,
9630
+ sessionRole: this.sessionRole,
9631
+ activeSessionCount: this.activeSessionCountProvider(),
9632
+ daemonProcessId: this.daemonProcessId,
9633
+ bootstrapped: Cadenza.isBootstrapped,
9634
+ mode: Cadenza.mode
9635
+ };
9636
+ }
9637
+ detachRuntime() {
9638
+ this.pendingControlAction = "detach";
9639
+ return {
9640
+ detached: true,
9641
+ runtimeName: this.runtimeName,
9642
+ sessionId: this.sessionId
9643
+ };
9644
+ }
9645
+ shutdownRuntime() {
9646
+ this.pendingControlAction = "shutdown";
9647
+ return {
9648
+ shutdown: true,
9649
+ runtimeName: this.runtimeName
9650
+ };
9651
+ }
9652
+ resetRuntime() {
9653
+ if (this.onResetRuntime) {
9654
+ this.onResetRuntime();
9655
+ } else {
9656
+ Cadenza.reset();
9657
+ this.subscriptionManager.reset();
9658
+ }
9659
+ return {
9660
+ reset: true,
9661
+ bootstrapped: false
9662
+ };
9663
+ }
9664
+ subscribe(payload) {
9665
+ assertObject(payload, "runtime.subscribe payload must be an object");
9666
+ const signalPatterns = this.parseSignalPatterns(payload.signalPatterns);
9667
+ const maxQueueSize = this.parsePositiveInteger(
9668
+ payload.maxQueueSize,
9669
+ "maxQueueSize",
9670
+ 100
9671
+ );
9672
+ return {
9673
+ subscription: this.subscriptionManager.subscribe(signalPatterns, maxQueueSize)
9674
+ };
9675
+ }
9676
+ unsubscribe(payload) {
9677
+ assertObject(payload, "runtime.unsubscribe payload must be an object");
9678
+ const subscriptionId = assertString(payload.subscriptionId, "subscriptionId");
9679
+ return {
9680
+ unsubscribed: true,
9681
+ subscription: this.subscriptionManager.unsubscribe(subscriptionId)
9682
+ };
9683
+ }
9684
+ async nextEvent(payload) {
9685
+ assertObject(payload, "runtime.nextEvent payload must be an object");
9686
+ const subscriptionId = assertString(payload.subscriptionId, "subscriptionId");
9687
+ const timeoutMs = this.parseNonNegativeInteger(
9688
+ payload.timeoutMs,
9689
+ "timeoutMs",
9690
+ 0
9691
+ );
9692
+ return this.subscriptionManager.nextEvent(subscriptionId, timeoutMs);
9693
+ }
9694
+ pollEvents(payload) {
9695
+ assertObject(payload, "runtime.pollEvents payload must be an object");
9696
+ const subscriptionId = assertString(payload.subscriptionId, "subscriptionId");
9697
+ const limit = this.parsePositiveInteger(payload.limit, "limit", 50);
9698
+ return this.subscriptionManager.pollEvents(subscriptionId, limit);
9699
+ }
9700
+ upsertTask(payload) {
9701
+ assertObject(payload, "task.upsert payload must be an object");
9702
+ const definition = payload;
9703
+ definition.name = assertString(definition.name, "name");
9704
+ definition.handlerSource = assertString(
9705
+ definition.handlerSource,
9706
+ "handlerSource"
9707
+ );
9708
+ definition.language = definition.language === "js" || definition.language === "ts" ? definition.language : (() => {
9709
+ throw new RuntimeProtocolException(
9710
+ "invalid_payload",
9711
+ "language must be 'js' or 'ts'"
9712
+ );
9713
+ })();
9714
+ definition.kind = definition.kind === "metaTask" ? "metaTask" : "task";
9715
+ runtimeDefinitionRegistry.setTaskDefinition(definition);
9716
+ const task = Cadenza.createTaskFromDefinition(definition);
9717
+ this.applyTaskDecorations(definition.name);
9718
+ this.applyAllTaskLinks();
9719
+ this.rematerializeRoutinesStartingWith(definition.name);
9720
+ return {
9721
+ task: this.snapshotTask(task)
9722
+ };
9723
+ }
9724
+ upsertHelper(payload) {
9725
+ assertObject(payload, "helper.upsert payload must be an object");
9726
+ const definition = payload;
9727
+ definition.name = assertString(definition.name, "name");
9728
+ definition.handlerSource = assertString(
9729
+ definition.handlerSource,
9730
+ "handlerSource"
9731
+ );
9732
+ definition.language = definition.language === "js" || definition.language === "ts" ? definition.language : (() => {
9733
+ throw new RuntimeProtocolException(
9734
+ "invalid_payload",
9735
+ "language must be 'js' or 'ts'"
9736
+ );
9737
+ })();
9738
+ definition.kind = definition.kind === "metaHelper" ? "metaHelper" : "helper";
9739
+ runtimeDefinitionRegistry.setHelperDefinition(definition);
9740
+ compileRuntimeHelperFunction(definition);
9741
+ Cadenza.createHelperFromDefinition(definition);
9742
+ this.applyHelperDecorations(definition.name);
9743
+ return {
9744
+ helper: this.snapshotHelper(definition.name)
9745
+ };
9746
+ }
9747
+ upsertGlobal(payload) {
9748
+ assertObject(payload, "global.upsert payload must be an object");
9749
+ const definition = {
9750
+ name: assertString(payload.name, "name"),
9751
+ description: typeof payload.description === "string" ? payload.description : "",
9752
+ kind: payload.kind === "metaGlobal" ? "metaGlobal" : "global",
9753
+ value: payload.value
9754
+ };
9755
+ runtimeDefinitionRegistry.setGlobalDefinition(definition);
9756
+ Cadenza.createGlobalFromDefinition(definition);
9757
+ return {
9758
+ global: this.snapshotGlobal(definition.name)
9759
+ };
9760
+ }
9761
+ linkTasks(payload) {
9762
+ assertObject(payload, "task.link payload must be an object");
9763
+ const definition = {
9764
+ predecessorTaskName: assertString(
9765
+ payload.predecessorTaskName,
9766
+ "predecessorTaskName"
9767
+ ),
9768
+ successorTaskName: assertString(
9769
+ payload.successorTaskName,
9770
+ "successorTaskName"
9771
+ )
9772
+ };
9773
+ runtimeDefinitionRegistry.setTaskLink(definition);
9774
+ this.applyAllTaskLinks();
9775
+ return {
9776
+ linked: true,
9777
+ ...definition
9778
+ };
9779
+ }
9780
+ observeTaskSignal(payload) {
9781
+ assertObject(payload, "task.observeSignal payload must be an object");
9782
+ const definition = {
9783
+ taskName: assertString(payload.taskName, "taskName"),
9784
+ signal: normalizeSignalDefinition2(payload.signal)
9785
+ };
9786
+ runtimeDefinitionRegistry.setTaskSignalObservation(definition);
9787
+ this.requireTask(definition.taskName).doOn(definition.signal);
9788
+ return {
9789
+ observed: true,
9790
+ taskName: definition.taskName,
9791
+ signal: typeof definition.signal === "string" ? definition.signal : definition.signal.name
9792
+ };
9793
+ }
9794
+ emitTaskSignal(payload) {
9795
+ assertObject(payload, "task.emitSignal payload must be an object");
9796
+ const mode = payload.mode === "attach" || payload.mode === "onFail" ? payload.mode : "after";
9797
+ const definition = {
9798
+ taskName: assertString(payload.taskName, "taskName"),
9799
+ signal: normalizeSignalDefinition2(payload.signal),
9800
+ mode
9801
+ };
9802
+ runtimeDefinitionRegistry.setTaskSignalEmission(definition);
9803
+ const task = this.requireTask(definition.taskName);
9804
+ if (definition.mode === "attach") {
9805
+ task.attachSignal(definition.signal);
9806
+ } else if (definition.mode === "onFail") {
9807
+ task.emitsOnFail(definition.signal);
9808
+ } else {
9809
+ task.emits(definition.signal);
9810
+ }
9811
+ return {
9812
+ attached: true,
9813
+ taskName: definition.taskName,
9814
+ mode: definition.mode,
9815
+ signal: typeof definition.signal === "string" ? definition.signal : definition.signal.name
9816
+ };
9817
+ }
9818
+ bindTaskIntent(payload) {
9819
+ assertObject(payload, "task.respondToIntent payload must be an object");
9820
+ const taskName = assertString(payload.taskName, "taskName");
9821
+ const intentName = assertString(payload.intentName, "intentName");
9822
+ runtimeDefinitionRegistry.setTaskIntentBinding({
9823
+ taskName,
9824
+ intentName
9825
+ });
9826
+ this.requireTask(taskName).respondsTo(intentName);
9827
+ return {
9828
+ bound: true,
9829
+ taskName,
9830
+ intentName
9831
+ };
9832
+ }
9833
+ bindTaskHelper(payload) {
9834
+ assertObject(payload, "task.useHelper payload must be an object");
9835
+ const definition = {
9836
+ taskName: assertString(payload.taskName, "taskName"),
9837
+ alias: assertString(payload.alias, "alias"),
9838
+ helperName: assertString(payload.helperName, "helperName")
9839
+ };
9840
+ runtimeDefinitionRegistry.setTaskHelperBinding(definition);
9841
+ this.requireTask(definition.taskName).usesHelpers({
9842
+ [definition.alias]: Cadenza.getHelper(definition.helperName)
9843
+ });
9844
+ return {
9845
+ bound: true,
9846
+ ...definition
9847
+ };
9848
+ }
9849
+ bindTaskGlobal(payload) {
9850
+ assertObject(payload, "task.useGlobal payload must be an object");
9851
+ const definition = {
9852
+ taskName: assertString(payload.taskName, "taskName"),
9853
+ alias: assertString(payload.alias, "alias"),
9854
+ globalName: assertString(payload.globalName, "globalName")
9855
+ };
9856
+ runtimeDefinitionRegistry.setTaskGlobalBinding(definition);
9857
+ this.requireTask(definition.taskName).usesGlobals({
9858
+ [definition.alias]: Cadenza.getGlobal(definition.globalName)
9859
+ });
9860
+ return {
9861
+ bound: true,
9862
+ ...definition
9863
+ };
9864
+ }
9865
+ bindHelperHelper(payload) {
9866
+ assertObject(payload, "helper.useHelper payload must be an object");
9867
+ const definition = {
9868
+ helperName: assertString(payload.helperName, "helperName"),
9869
+ alias: assertString(payload.alias, "alias"),
9870
+ dependencyHelperName: assertString(
9871
+ payload.dependencyHelperName,
9872
+ "dependencyHelperName"
9873
+ )
9874
+ };
9875
+ runtimeDefinitionRegistry.setHelperHelperBinding(definition);
9876
+ const helper = Cadenza.getHelper(definition.helperName);
9877
+ if (!helper) {
9878
+ throw new RuntimeProtocolException(
9879
+ "not_found",
9880
+ `No helper named "${definition.helperName}" exists`
9881
+ );
9882
+ }
9883
+ helper.usesHelpers({
9884
+ [definition.alias]: Cadenza.getHelper(definition.dependencyHelperName)
9885
+ });
9886
+ return {
9887
+ bound: true,
9888
+ ...definition
9889
+ };
9890
+ }
9891
+ bindHelperGlobal(payload) {
9892
+ assertObject(payload, "helper.useGlobal payload must be an object");
9893
+ const definition = {
9894
+ helperName: assertString(payload.helperName, "helperName"),
9895
+ alias: assertString(payload.alias, "alias"),
9896
+ globalName: assertString(payload.globalName, "globalName")
9897
+ };
9898
+ runtimeDefinitionRegistry.setHelperGlobalBinding(definition);
9899
+ const helper = Cadenza.getHelper(definition.helperName);
9900
+ if (!helper) {
9901
+ throw new RuntimeProtocolException(
9902
+ "not_found",
9903
+ `No helper named "${definition.helperName}" exists`
9904
+ );
9905
+ }
9906
+ helper.usesGlobals({
9907
+ [definition.alias]: Cadenza.getGlobal(definition.globalName)
9908
+ });
9909
+ return {
9910
+ bound: true,
9911
+ ...definition
9912
+ };
9913
+ }
9914
+ upsertRoutine(payload) {
9915
+ assertObject(payload, "routine.upsert payload must be an object");
9916
+ const definition = {
9917
+ name: assertString(payload.name, "name"),
9918
+ description: typeof payload.description === "string" ? payload.description : "",
9919
+ startTaskNames: assertStringArray(payload.startTaskNames, "startTaskNames"),
9920
+ isMeta: payload.isMeta === true
9921
+ };
9922
+ if (definition.startTaskNames.length === 0) {
9923
+ throw new RuntimeProtocolException(
9924
+ "invalid_payload",
9925
+ "startTaskNames must contain at least one task name"
9926
+ );
9927
+ }
9928
+ runtimeDefinitionRegistry.setRoutineDefinition(definition);
9929
+ const routine = Cadenza.createRoutineFromDefinition(definition);
9930
+ this.applyRoutineDecorations(definition.name);
9931
+ return {
9932
+ routine: this.snapshotRoutine(routine)
9933
+ };
9934
+ }
9935
+ observeRoutineSignal(payload) {
9936
+ assertObject(payload, "routine.observeSignal payload must be an object");
9937
+ const routineName = assertString(payload.routineName, "routineName");
9938
+ const signal = assertString(payload.signal, "signal");
9939
+ runtimeDefinitionRegistry.setRoutineSignalObservation({
9940
+ routineName,
9941
+ signal
9942
+ });
9943
+ this.requireRoutine(routineName).doOn(signal);
9944
+ return {
9945
+ observed: true,
9946
+ routineName,
9947
+ signal
9948
+ };
9949
+ }
9950
+ upsertIntent(payload) {
9951
+ assertObject(payload, "intent.upsert payload must be an object");
9952
+ const intent = {
9953
+ name: assertString(payload.name, "name"),
9954
+ description: typeof payload.description === "string" ? payload.description : "",
9955
+ input: isObject4(payload.input) ? payload.input : { type: "object" },
9956
+ output: isObject4(payload.output) ? payload.output : { type: "object" }
9957
+ };
9958
+ runtimeDefinitionRegistry.setIntentDefinition(intent);
9959
+ Cadenza.defineIntent(intent);
9960
+ return {
9961
+ intent: sanitizeForJson(intent)
9962
+ };
9963
+ }
9964
+ upsertActor(payload) {
9965
+ assertObject(payload, "actor.upsert payload must be an object");
9966
+ const definition = payload;
9967
+ definition.name = assertString(definition.name, "name");
9968
+ definition.description = assertString(definition.description, "description");
9969
+ definition.defaultKey = assertString(definition.defaultKey, "defaultKey");
9970
+ runtimeDefinitionRegistry.setActorDefinition(definition);
9971
+ const actor = Cadenza.createActorFromDefinition(definition);
9972
+ this.rematerializeActorTasksFor(definition.name);
9973
+ return {
9974
+ actor: sanitizeForJson({
9975
+ name: actor.spec.name,
9976
+ description: actor.spec.description ?? "",
9977
+ defaultKey: actor.spec.defaultKey
9978
+ })
9979
+ };
9980
+ }
9981
+ upsertActorTask(payload) {
9982
+ assertObject(payload, "actorTask.upsert payload must be an object");
9983
+ const definition = {
9984
+ actorName: assertString(payload.actorName, "actorName"),
9985
+ taskName: assertString(payload.taskName, "taskName"),
9986
+ description: typeof payload.description === "string" ? payload.description : "",
9987
+ mode: payload.mode === "write" || payload.mode === "meta" ? payload.mode : "read",
9988
+ handlerSource: assertString(payload.handlerSource, "handlerSource"),
9989
+ language: payload.language === "js" || payload.language === "ts" ? payload.language : (() => {
9990
+ throw new RuntimeProtocolException(
9991
+ "invalid_payload",
9992
+ "language must be 'js' or 'ts'"
9993
+ );
9994
+ })(),
9995
+ options: isObject4(payload.options) ? { ...payload.options } : void 0
9996
+ };
9997
+ runtimeDefinitionRegistry.setActorTaskDefinition(definition);
9998
+ const task = this.materializeActorTask(definition.taskName);
9999
+ this.applyTaskDecorations(definition.taskName);
10000
+ this.applyAllTaskLinks();
10001
+ this.rematerializeRoutinesStartingWith(definition.taskName);
10002
+ return {
10003
+ actorTask: this.snapshotTask(task)
10004
+ };
10005
+ }
10006
+ async runTarget(payload) {
10007
+ assertObject(payload, "run payload must be an object");
10008
+ const targetName = assertString(payload.targetName, "targetName");
10009
+ const context = isObject4(payload.context) ? payload.context : {};
10010
+ let target = Cadenza.getRoutine(targetName);
10011
+ if (!target) {
10012
+ const routineDefinition = runtimeDefinitionRegistry.routineDefinitions.get(targetName);
10013
+ if (routineDefinition) {
10014
+ target = Cadenza.createRoutineFromDefinition(routineDefinition);
10015
+ this.applyRoutineDecorations(targetName);
10016
+ }
10017
+ }
10018
+ target = target ?? Cadenza.get(targetName);
10019
+ if (!target) {
10020
+ throw new RuntimeProtocolException(
10021
+ "not_found",
10022
+ `No task or routine named "${targetName}" exists`
10023
+ );
10024
+ }
10025
+ const runner = "isMeta" in target && target.isMeta ? Cadenza.metaRunner : Cadenza.runner;
10026
+ const runResult = runner.run(target, context);
10027
+ const completedRun = await Promise.resolve(runResult);
10028
+ return {
10029
+ targetName,
10030
+ run: completedRun.export()
10031
+ };
10032
+ }
10033
+ emitSignal(payload) {
10034
+ assertObject(payload, "emit payload must be an object");
10035
+ const signal = assertString(payload.signal, "signal");
10036
+ const context = isObject4(payload.context) ? payload.context : {};
10037
+ const options = isObject4(payload.options) ? payload.options : {};
10038
+ Cadenza.emit(signal, context, options);
10039
+ return {
10040
+ emitted: true,
10041
+ signal
10042
+ };
10043
+ }
10044
+ async inquireIntent(payload) {
10045
+ assertObject(payload, "inquire payload must be an object");
10046
+ const inquiry = assertString(payload.intent, "intent");
10047
+ const context = isObject4(payload.context) ? payload.context : {};
10048
+ const options = isObject4(payload.options) ? payload.options : {};
10049
+ const response = await Cadenza.inquire(inquiry, context, options);
10050
+ return {
10051
+ inquiry,
10052
+ response
10053
+ };
10054
+ }
10055
+ requireTask(taskName) {
10056
+ const task = Cadenza.get(taskName);
10057
+ if (!task) {
10058
+ throw new RuntimeProtocolException(
10059
+ "not_found",
10060
+ `No task named "${taskName}" exists`
10061
+ );
10062
+ }
10063
+ return task;
10064
+ }
10065
+ requireRoutine(routineName) {
10066
+ const routine = Cadenza.getRoutine(routineName);
10067
+ if (!routine) {
10068
+ throw new RuntimeProtocolException(
10069
+ "not_found",
10070
+ `No routine named "${routineName}" exists`
10071
+ );
10072
+ }
10073
+ return routine;
10074
+ }
10075
+ applyTaskDecorations(taskName) {
10076
+ const task = this.requireTask(taskName);
10077
+ for (const observation of runtimeDefinitionRegistry.taskSignalObservations.values()) {
10078
+ if (observation.taskName !== taskName) {
10079
+ continue;
10080
+ }
10081
+ task.doOn(observation.signal);
10082
+ }
10083
+ for (const emission of runtimeDefinitionRegistry.taskSignalEmissions.values()) {
10084
+ if (emission.taskName !== taskName) {
10085
+ continue;
10086
+ }
10087
+ if (emission.mode === "attach") {
10088
+ task.attachSignal(emission.signal);
10089
+ } else if (emission.mode === "onFail") {
10090
+ task.emitsOnFail(emission.signal);
10091
+ } else {
10092
+ task.emits(emission.signal);
10093
+ }
10094
+ }
10095
+ for (const binding of runtimeDefinitionRegistry.taskIntentBindings.values()) {
10096
+ if (binding.taskName !== taskName) {
10097
+ continue;
10098
+ }
10099
+ task.respondsTo(binding.intentName);
10100
+ }
10101
+ for (const binding of runtimeDefinitionRegistry.taskHelperBindings.values()) {
10102
+ if (binding.taskName !== taskName) {
10103
+ continue;
10104
+ }
10105
+ task.usesHelpers({
10106
+ [binding.alias]: Cadenza.getHelper(binding.helperName)
10107
+ });
10108
+ }
10109
+ for (const binding of runtimeDefinitionRegistry.taskGlobalBindings.values()) {
10110
+ if (binding.taskName !== taskName) {
10111
+ continue;
10112
+ }
10113
+ task.usesGlobals({
10114
+ [binding.alias]: Cadenza.getGlobal(binding.globalName)
10115
+ });
10116
+ }
10117
+ }
10118
+ applyHelperDecorations(helperName) {
10119
+ const helper = Cadenza.getHelper(helperName);
10120
+ if (!helper) {
10121
+ throw new RuntimeProtocolException(
10122
+ "not_found",
10123
+ `No helper named "${helperName}" exists`
10124
+ );
10125
+ }
10126
+ for (const binding of runtimeDefinitionRegistry.helperHelperBindings.values()) {
10127
+ if (binding.helperName !== helperName) {
10128
+ continue;
10129
+ }
10130
+ helper.usesHelpers({
10131
+ [binding.alias]: Cadenza.getHelper(binding.dependencyHelperName)
10132
+ });
10133
+ }
10134
+ for (const binding of runtimeDefinitionRegistry.helperGlobalBindings.values()) {
10135
+ if (binding.helperName !== helperName) {
10136
+ continue;
10137
+ }
10138
+ helper.usesGlobals({
10139
+ [binding.alias]: Cadenza.getGlobal(binding.globalName)
10140
+ });
10141
+ }
10142
+ }
10143
+ applyAllTaskLinks() {
10144
+ for (const link of runtimeDefinitionRegistry.taskLinks.values()) {
10145
+ const predecessor = Cadenza.get(link.predecessorTaskName);
10146
+ const successor = Cadenza.get(link.successorTaskName);
10147
+ if (!predecessor || !successor) {
10148
+ continue;
10149
+ }
10150
+ predecessor.then(successor);
10151
+ }
10152
+ }
10153
+ applyRoutineDecorations(routineName) {
10154
+ const routine = this.requireRoutine(routineName);
10155
+ for (const observation of runtimeDefinitionRegistry.routineSignalObservations.values()) {
10156
+ if (observation.routineName !== routineName) {
10157
+ continue;
10158
+ }
10159
+ routine.doOn(observation.signal);
10160
+ }
10161
+ }
10162
+ rematerializeRoutinesStartingWith(taskName) {
10163
+ for (const definition of runtimeDefinitionRegistry.routineDefinitions.values()) {
10164
+ if (!definition.startTaskNames.includes(taskName)) {
10165
+ continue;
10166
+ }
10167
+ const recreated = Cadenza.createRoutineFromDefinition(definition);
10168
+ this.applyRoutineDecorations(recreated.name);
10169
+ }
10170
+ }
10171
+ rematerializeActorTasksFor(actorName) {
10172
+ for (const definition of runtimeDefinitionRegistry.actorTaskDefinitions.values()) {
10173
+ if (definition.actorName !== actorName) {
10174
+ continue;
10175
+ }
10176
+ this.materializeActorTask(definition.taskName);
10177
+ this.applyTaskDecorations(definition.taskName);
10178
+ this.applyAllTaskLinks();
10179
+ this.rematerializeRoutinesStartingWith(definition.taskName);
10180
+ }
10181
+ }
10182
+ materializeActorTask(taskName) {
10183
+ const definition = runtimeDefinitionRegistry.actorTaskDefinitions.get(taskName);
10184
+ if (!definition) {
10185
+ throw new RuntimeProtocolException(
10186
+ "not_found",
10187
+ `No actor task definition named "${taskName}" exists`
10188
+ );
10189
+ }
10190
+ const actor = Cadenza.getActor(definition.actorName);
10191
+ if (!actor) {
10192
+ throw new RuntimeProtocolException(
10193
+ "not_found",
10194
+ `No actor named "${definition.actorName}" exists`
10195
+ );
10196
+ }
10197
+ const existingTask = Cadenza.get(definition.taskName);
10198
+ if (existingTask && !runtimeDefinitionRegistry.isRuntimeOwnedTask(existingTask.name)) {
10199
+ throw new RuntimeProtocolException(
10200
+ "conflict",
10201
+ `Task "${definition.taskName}" already exists and is not runtime-owned`
10202
+ );
10203
+ }
10204
+ existingTask?.destroy();
10205
+ const handler = compileRuntimeActorTaskHandler(definition);
10206
+ return Cadenza.createTask(
10207
+ definition.taskName,
10208
+ actor.task(handler, { mode: definition.mode }),
10209
+ definition.description ?? "",
10210
+ definition.options ?? {}
10211
+ );
10212
+ }
10213
+ snapshotTask(task) {
10214
+ const snapshot = Cadenza.snapshotRuntime();
10215
+ const existing = snapshot.tasks.find((entry) => entry.name === task.name);
10216
+ if (existing) {
10217
+ return existing;
10218
+ }
10219
+ const runtimeTaskDefinition = runtimeDefinitionRegistry.taskDefinitions.get(
10220
+ task.name
10221
+ );
10222
+ const runtimeActorTaskDefinition = runtimeDefinitionRegistry.actorTaskDefinitions.get(task.name);
10223
+ return {
10224
+ name: task.name,
10225
+ version: task.version,
10226
+ description: task.description,
10227
+ kind: runtimeActorTaskDefinition ? "actorTask" : task.isMeta ? "metaTask" : "task",
10228
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedTask(task.name),
10229
+ language: runtimeTaskDefinition?.language ?? runtimeActorTaskDefinition?.language ?? null,
10230
+ handlerSource: runtimeTaskDefinition?.handlerSource ?? runtimeActorTaskDefinition?.handlerSource ?? null,
10231
+ tools: {
10232
+ helpers: Object.fromEntries(task.helperAliases),
10233
+ globals: Object.fromEntries(task.globalAliases)
10234
+ }
10235
+ };
10236
+ }
10237
+ snapshotHelper(helperName) {
10238
+ const snapshot = Cadenza.snapshotRuntime();
10239
+ return snapshot.helpers.find((entry) => entry.name === helperName) ?? {
10240
+ name: helperName
10241
+ };
10242
+ }
10243
+ snapshotGlobal(globalName) {
10244
+ const snapshot = Cadenza.snapshotRuntime();
10245
+ return snapshot.globals.find((entry) => entry.name === globalName) ?? {
10246
+ name: globalName
10247
+ };
10248
+ }
10249
+ snapshotRoutine(routine) {
10250
+ const snapshot = Cadenza.snapshotRuntime();
10251
+ return snapshot.routines.find((entry) => entry.name === routine.name) ?? {
10252
+ name: routine.name,
10253
+ version: routine.version,
10254
+ description: routine.description,
10255
+ isMeta: routine.isMeta,
10256
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedRoutine(
10257
+ routine.name
10258
+ ),
10259
+ startTaskNames: Array.from(routine.tasks).map((task) => task.name),
10260
+ observedSignals: Array.from(routine.observedSignals)
10261
+ };
10262
+ }
10263
+ parseSignalPatterns(value) {
10264
+ if (value === void 0) {
10265
+ return ["*"];
10266
+ }
10267
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string" || entry.trim().length === 0)) {
10268
+ throw new RuntimeProtocolException(
10269
+ "invalid_payload",
10270
+ "signalPatterns must be an array of non-empty strings"
10271
+ );
10272
+ }
10273
+ return Array.from(new Set(value.map((entry) => entry.trim())));
10274
+ }
10275
+ parsePositiveInteger(value, fieldName, fallback) {
10276
+ if (value === void 0) {
10277
+ return fallback;
10278
+ }
10279
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
10280
+ throw new RuntimeProtocolException(
10281
+ "invalid_payload",
10282
+ `${fieldName} must be a positive integer`
10283
+ );
10284
+ }
10285
+ return value;
10286
+ }
10287
+ parseNonNegativeInteger(value, fieldName, fallback) {
10288
+ if (value === void 0) {
10289
+ return fallback;
10290
+ }
10291
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
10292
+ throw new RuntimeProtocolException(
10293
+ "invalid_payload",
10294
+ `${fieldName} must be a non-negative integer`
10295
+ );
10296
+ }
10297
+ return value;
10298
+ }
10299
+ };
10300
+
7962
10301
  // src/index.ts
7963
10302
  var index_default = Cadenza;
7964
10303
  export {
7965
10304
  Actor,
7966
10305
  DebounceTask,
7967
10306
  EphemeralTask,
10307
+ GlobalDefinition,
7968
10308
  GraphContext,
7969
10309
  GraphRegistry,
7970
10310
  GraphRoutine,
7971
10311
  GraphRun,
7972
10312
  GraphRunner,
10313
+ HelperDefinition,
7973
10314
  InquiryBroker,
7974
10315
  META_ACTOR_SESSION_STATE_PERSIST_INTENT,
10316
+ RuntimeHost,
7975
10317
  SignalBroker,
7976
10318
  SignalEmitter,
7977
10319
  Task,