@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.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -23,13 +33,16 @@ __export(index_exports, {
23
33
  Actor: () => Actor,
24
34
  DebounceTask: () => DebounceTask,
25
35
  EphemeralTask: () => EphemeralTask,
36
+ GlobalDefinition: () => GlobalDefinition,
26
37
  GraphContext: () => GraphContext,
27
38
  GraphRegistry: () => GraphRegistry,
28
39
  GraphRoutine: () => GraphRoutine,
29
40
  GraphRun: () => GraphRun,
30
41
  GraphRunner: () => GraphRunner,
42
+ HelperDefinition: () => HelperDefinition,
31
43
  InquiryBroker: () => InquiryBroker,
32
44
  META_ACTOR_SESSION_STATE_PERSIST_INTENT: () => META_ACTOR_SESSION_STATE_PERSIST_INTENT,
45
+ RuntimeHost: () => RuntimeHost,
33
46
  SignalBroker: () => SignalBroker,
34
47
  SignalEmitter: () => SignalEmitter,
35
48
  Task: () => Task,
@@ -1281,6 +1294,7 @@ var SignalBroker = class _SignalBroker {
1281
1294
  this.signalObservers = /* @__PURE__ */ new Map();
1282
1295
  this.emittedSignalsRegistry = /* @__PURE__ */ new Set();
1283
1296
  this.signalMetadataRegistry = /* @__PURE__ */ new Map();
1297
+ this.passiveSignalListeners = /* @__PURE__ */ new Map();
1284
1298
  // ── Flush Strategy Management ───────────────────────────────────────
1285
1299
  this.flushStrategies = /* @__PURE__ */ new Map();
1286
1300
  this.strategyData = /* @__PURE__ */ new Map();
@@ -1361,6 +1375,20 @@ var SignalBroker = class _SignalBroker {
1361
1375
  console.log(
1362
1376
  ` \u2022 emittedSignalsRegistry size: ${this.emittedSignalsRegistry.size}`
1363
1377
  );
1378
+ const exactSignalEntries = Array.from(this.signalObservers.entries()).filter(([signal]) => signal.includes(":")).sort((left, right) => {
1379
+ const taskDelta = right[1].tasks.size - left[1].tasks.size;
1380
+ if (taskDelta !== 0) {
1381
+ return taskDelta;
1382
+ }
1383
+ return left[0].localeCompare(right[0]);
1384
+ });
1385
+ console.log(` \u2022 exact signal observer entries: ${exactSignalEntries.length}`);
1386
+ for (const [signal, observer] of exactSignalEntries.slice(0, 8)) {
1387
+ const sampleTaskNames = Array.from(observer.tasks).slice(0, 3).map((task) => task.name);
1388
+ console.log(
1389
+ ` - ${signal} (${observer.tasks.size} tasks) sample=${sampleTaskNames.join(", ")}`
1390
+ );
1391
+ }
1364
1392
  let totalSquashContexts = 0;
1365
1393
  let totalSquashGroups = 0;
1366
1394
  for (const groups of this.strategyData.values()) {
@@ -1774,7 +1802,7 @@ var SignalBroker = class _SignalBroker {
1774
1802
  this.schedule(signal, context, options);
1775
1803
  return;
1776
1804
  }
1777
- this.addSignal(signal);
1805
+ this.validateSignalName(signal);
1778
1806
  this.execute(signal, context);
1779
1807
  }
1780
1808
  /**
@@ -1853,6 +1881,7 @@ var SignalBroker = class _SignalBroker {
1853
1881
  ...context.__metadata,
1854
1882
  __executionTraceId: executionTraceId
1855
1883
  };
1884
+ this.notifyPassiveSignalListeners(signal, context);
1856
1885
  if (this.debug && (!isMetric && !isSubMeta || this.verbose)) {
1857
1886
  console.log(
1858
1887
  `EMITTING ${signal} to listeners ${this.signalObservers.get(signal)?.tasks.size ?? 0} with context ${this.verbose ? JSON.stringify(context) : JSON.stringify(context).slice(0, 100)}`
@@ -1950,11 +1979,37 @@ var SignalBroker = class _SignalBroker {
1950
1979
  this.addSignal(signal, metadata);
1951
1980
  this.signalObservers.get(signal).tasks.add(routineOrTask);
1952
1981
  }
1982
+ addPassiveSignalListener(listener) {
1983
+ const listenerId = (0, import_uuid.v4)();
1984
+ this.passiveSignalListeners.set(listenerId, listener);
1985
+ return () => {
1986
+ this.passiveSignalListeners.delete(listenerId);
1987
+ };
1988
+ }
1989
+ notifyPassiveSignalListeners(signal, context) {
1990
+ if (this.passiveSignalListeners.size === 0) {
1991
+ return;
1992
+ }
1993
+ const metadata = this.getSignalMetadata(signal) ?? null;
1994
+ for (const listener of this.passiveSignalListeners.values()) {
1995
+ try {
1996
+ listener(signal, context, metadata);
1997
+ } catch (error) {
1998
+ if (this.debug) {
1999
+ console.error("Passive signal listener failed", error);
2000
+ }
2001
+ }
2002
+ }
2003
+ }
1953
2004
  registerEmittedSignal(signal, metadata) {
2005
+ const signalKey = this.resolveSignalMetadataKey(signal);
2006
+ if (!signalKey) {
2007
+ return;
2008
+ }
1954
2009
  if (metadata) {
1955
- this.setSignalMetadata(signal, metadata);
2010
+ this.setSignalMetadata(signalKey, metadata);
1956
2011
  }
1957
- this.emittedSignalsRegistry.add(signal);
2012
+ this.emittedSignalsRegistry.add(signalKey);
1958
2013
  }
1959
2014
  /**
1960
2015
  * Unsubscribes a routine/task from a signal.
@@ -3014,16 +3069,17 @@ var GraphNode = class _GraphNode extends SignalEmitter {
3014
3069
  * @return {void} Does not return a value.
3015
3070
  */
3016
3071
  finalize() {
3072
+ const context = this.context?.getFullContext?.() ?? {};
3017
3073
  if (this.nextNodes.length === 0) {
3018
3074
  this.completeSubgraph();
3019
3075
  }
3020
3076
  if (this.errored || this.failed) {
3021
3077
  this.task.mapOnFailSignals(
3022
- (signal) => this.emitWithMetadata(signal, this.context.getFullContext())
3078
+ (signal) => this.emitWithMetadata(signal, { ...context })
3023
3079
  );
3024
3080
  } else if (this.result !== void 0 && this.result !== false) {
3025
3081
  this.task.mapSignals(
3026
- (signal) => this.emitWithMetadata(signal, this.context.getFullContext())
3082
+ (signal) => this.emitWithMetadata(signal, { ...context })
3027
3083
  );
3028
3084
  }
3029
3085
  this.end();
@@ -3037,8 +3093,9 @@ var GraphNode = class _GraphNode extends SignalEmitter {
3037
3093
  */
3038
3094
  onError(error, errorData = {}) {
3039
3095
  const normalizedError = normalizeGraphErrorMessage(error);
3096
+ const context = this.context?.getFullContext?.() ?? {};
3040
3097
  this.result = {
3041
- ...this.context.getFullContext(),
3098
+ ...context,
3042
3099
  __error: `Node error: ${normalizedError}`,
3043
3100
  __retries: this.retries,
3044
3101
  error: `Node error: ${normalizedError}`,
@@ -3922,7 +3979,13 @@ var Actor = class {
3922
3979
  task(handler, bindingOptions = {}) {
3923
3980
  const mode = bindingOptions.mode ?? "read";
3924
3981
  const taskBindingId = `${this.spec.name}:${++this.nextTaskBindingIndex}`;
3925
- const wrapped = (context, emit, inquire, progressCallback) => {
3982
+ const wrapped = (context, emit, inquire, tools, progressCallback) => {
3983
+ const resolvedTools = tools && typeof tools === "object" && !Array.isArray(tools) && "helpers" in tools && "globals" in tools ? tools : {
3984
+ helpers: {},
3985
+ globals: {}
3986
+ };
3987
+ const resolvedProgressCallback = typeof progressCallback === "function" ? progressCallback : typeof tools === "function" ? tools : () => {
3988
+ };
3926
3989
  const normalizedInput = this.normalizeInputContext(context);
3927
3990
  const invocationOptions = this.resolveInvocationOptions(
3928
3991
  context,
@@ -4042,7 +4105,8 @@ var Actor = class {
4042
4105
  patchRuntimeState,
4043
4106
  reduceRuntimeState,
4044
4107
  emit: (signal, payload = {}) => emit(signal, payload),
4045
- inquire: (inquiryName, inquiryContext = {}, options = {}) => inquire(inquiryName, inquiryContext, options)
4108
+ inquire: (inquiryName, inquiryContext = {}, options = {}) => inquire(inquiryName, inquiryContext, options),
4109
+ tools: resolvedTools
4046
4110
  };
4047
4111
  const handlerResult = await handler(actorContext);
4048
4112
  if (invocationOptions.writeContract === "reducer" && typeof handlerResult === "function") {
@@ -4069,7 +4133,7 @@ var Actor = class {
4069
4133
  stateRecord.lastRuntimeWriteAt = writeTimestamp;
4070
4134
  }
4071
4135
  this.touchSession(actorKey, invocationOptions.touchSession, Date.now());
4072
- progressCallback(100);
4136
+ resolvedProgressCallback(100);
4073
4137
  if (invocationOptions.writeContract === "reducer" && typeof handlerResult === "function") {
4074
4138
  return cloneForDurableState(stateRecord.durableState);
4075
4139
  }
@@ -4113,6 +4177,13 @@ var Actor = class {
4113
4177
  this.pruneExpiredActorKeys(Date.now());
4114
4178
  return this.ensureStateRecord(key).runtimeState;
4115
4179
  }
4180
+ /**
4181
+ * Lists all currently materialized actor keys.
4182
+ */
4183
+ listActorKeys() {
4184
+ this.pruneExpiredActorKeys(Date.now());
4185
+ return Array.from(this.stateByKey.keys()).sort();
4186
+ }
4116
4187
  /**
4117
4188
  * Alias of `getDurableVersion`.
4118
4189
  */
@@ -4522,6 +4593,176 @@ var Actor = class {
4522
4593
  }
4523
4594
  };
4524
4595
 
4596
+ // src/tools/definitions.ts
4597
+ function validateAlias(alias) {
4598
+ const normalized = String(alias ?? "").trim();
4599
+ if (!normalized) {
4600
+ throw new Error("Tool dependency alias must be a non-empty string");
4601
+ }
4602
+ return normalized;
4603
+ }
4604
+ function serializeGlobalValue(value) {
4605
+ if (value === void 0 || typeof value === "function") {
4606
+ throw new Error("Global values must be JSON-serializable");
4607
+ }
4608
+ try {
4609
+ return JSON.parse(JSON.stringify(value));
4610
+ } catch (error) {
4611
+ throw new Error(
4612
+ `Global values must be JSON-serializable: ${error instanceof Error ? error.message : String(error)}`
4613
+ );
4614
+ }
4615
+ }
4616
+ function deepFreeze(value) {
4617
+ if (!value || typeof value !== "object") {
4618
+ return value;
4619
+ }
4620
+ Object.freeze(value);
4621
+ for (const nested of Object.values(value)) {
4622
+ if (nested && typeof nested === "object" && !Object.isFrozen(nested)) {
4623
+ deepFreeze(nested);
4624
+ }
4625
+ }
4626
+ return value;
4627
+ }
4628
+ var GlobalDefinition = class {
4629
+ constructor(name, value, description = "", isMeta = false) {
4630
+ this.version = 1;
4631
+ this.destroyed = false;
4632
+ this.name = name;
4633
+ this.description = description;
4634
+ this.isMeta = isMeta;
4635
+ this.value = deepFreeze(serializeGlobalValue(value));
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
+ value: this.value
4647
+ };
4648
+ }
4649
+ };
4650
+ var HelperDefinition = class {
4651
+ constructor(name, helperFunction, description = "", isMeta = false) {
4652
+ this.version = 1;
4653
+ this.helperAliases = /* @__PURE__ */ new Map();
4654
+ this.globalAliases = /* @__PURE__ */ new Map();
4655
+ this.destroyed = false;
4656
+ this.name = name;
4657
+ this.description = description;
4658
+ this.isMeta = isMeta;
4659
+ this.helperFunction = helperFunction;
4660
+ }
4661
+ usesHelpers(helpers) {
4662
+ attachHelperDependency(
4663
+ this,
4664
+ this.name,
4665
+ this.version,
4666
+ helpers,
4667
+ "meta.helper.helper_associated"
4668
+ );
4669
+ return this;
4670
+ }
4671
+ usesGlobals(globals) {
4672
+ attachGlobalDependency(
4673
+ this,
4674
+ this.name,
4675
+ this.version,
4676
+ globals,
4677
+ "meta.helper.global_associated"
4678
+ );
4679
+ return this;
4680
+ }
4681
+ execute(context, emit, inquire, progressCallback) {
4682
+ return Cadenza.executeHelper(
4683
+ this,
4684
+ context,
4685
+ emit,
4686
+ inquire,
4687
+ progressCallback
4688
+ );
4689
+ }
4690
+ destroy() {
4691
+ this.destroyed = true;
4692
+ }
4693
+ export() {
4694
+ return {
4695
+ name: this.name,
4696
+ description: this.description,
4697
+ version: this.version,
4698
+ isMeta: this.isMeta,
4699
+ functionString: this.helperFunction.toString(),
4700
+ helperAliases: Object.fromEntries(this.helperAliases),
4701
+ globalAliases: Object.fromEntries(this.globalAliases)
4702
+ };
4703
+ }
4704
+ };
4705
+ function attachHelperDependency(owner, ownerName, ownerVersion, helpers, signalName) {
4706
+ for (const [alias, helper] of Object.entries(helpers)) {
4707
+ const normalizedAlias = validateAlias(alias);
4708
+ if (!helper) {
4709
+ throw new Error(
4710
+ `Helper dependency "${normalizedAlias}" must reference a helper definition`
4711
+ );
4712
+ }
4713
+ if (helper.isMeta !== owner.isMeta) {
4714
+ throw new Error(
4715
+ `${ownerName} cannot use ${helper.isMeta ? "meta" : "business"} helper "${helper.name}" across layer boundaries`
4716
+ );
4717
+ }
4718
+ owner.helperAliases.set(normalizedAlias, helper.name);
4719
+ Cadenza.emit(signalName, {
4720
+ data: {
4721
+ alias: normalizedAlias,
4722
+ ...signalName === "meta.task.helper_associated" ? {
4723
+ taskName: ownerName,
4724
+ taskVersion: ownerVersion
4725
+ } : {
4726
+ helperName: ownerName,
4727
+ helperVersion: ownerVersion
4728
+ },
4729
+ dependencyHelperName: helper.name,
4730
+ dependencyHelperVersion: helper.version
4731
+ }
4732
+ });
4733
+ }
4734
+ }
4735
+ function attachGlobalDependency(owner, ownerName, ownerVersion, globals, signalName) {
4736
+ for (const [alias, globalDefinition] of Object.entries(globals)) {
4737
+ const normalizedAlias = validateAlias(alias);
4738
+ if (!globalDefinition) {
4739
+ throw new Error(
4740
+ `Global dependency "${normalizedAlias}" must reference a global definition`
4741
+ );
4742
+ }
4743
+ if (globalDefinition.isMeta !== owner.isMeta) {
4744
+ throw new Error(
4745
+ `${ownerName} cannot use ${globalDefinition.isMeta ? "meta" : "business"} global "${globalDefinition.name}" across layer boundaries`
4746
+ );
4747
+ }
4748
+ owner.globalAliases.set(normalizedAlias, globalDefinition.name);
4749
+ Cadenza.emit(signalName, {
4750
+ data: {
4751
+ alias: normalizedAlias,
4752
+ ...signalName === "meta.task.global_associated" ? {
4753
+ taskName: ownerName,
4754
+ taskVersion: ownerVersion
4755
+ } : {
4756
+ helperName: ownerName,
4757
+ helperVersion: ownerVersion
4758
+ },
4759
+ globalName: globalDefinition.name,
4760
+ globalVersion: globalDefinition.version
4761
+ }
4762
+ });
4763
+ }
4764
+ }
4765
+
4525
4766
  // src/graph/definition/Task.ts
4526
4767
  function normalizeSignalDefinition(input) {
4527
4768
  if (typeof input === "string") {
@@ -4598,6 +4839,8 @@ var Task = class _Task extends SignalEmitter {
4598
4839
  this.observedSignals = /* @__PURE__ */ new Set();
4599
4840
  this.handlesIntents = /* @__PURE__ */ new Set();
4600
4841
  this.inquiresIntents = /* @__PURE__ */ new Set();
4842
+ this.helperAliases = /* @__PURE__ */ new Map();
4843
+ this.globalAliases = /* @__PURE__ */ new Map();
4601
4844
  this.name = name;
4602
4845
  this.taskFunction = task;
4603
4846
  this.description = description;
@@ -4633,6 +4876,8 @@ var Task = class _Task extends SignalEmitter {
4633
4876
  "meta.task.relationship_added",
4634
4877
  "meta.task.relationship_removed",
4635
4878
  "meta.task.intent_associated",
4879
+ "meta.task.helper_associated",
4880
+ "meta.task.global_associated",
4636
4881
  "meta.task.layer_index_changed",
4637
4882
  "meta.node.scheduled",
4638
4883
  "meta.node.mapped",
@@ -5146,10 +5391,18 @@ var Task = class _Task extends SignalEmitter {
5146
5391
  * @return {TaskResult} The result of the executed task.
5147
5392
  */
5148
5393
  execute(context, emit, inquire, progressCallback, nodeData) {
5394
+ const executionContext = this.isMeta ? context.getClonedFullContext() : context.getClonedContext();
5149
5395
  return this.taskFunction(
5150
- this.isMeta ? context.getClonedFullContext() : context.getClonedContext(),
5396
+ executionContext,
5151
5397
  emit,
5152
5398
  inquire,
5399
+ Cadenza.resolveToolsForOwner(
5400
+ this,
5401
+ executionContext,
5402
+ emit,
5403
+ inquire,
5404
+ progressCallback
5405
+ ),
5153
5406
  progressCallback
5154
5407
  );
5155
5408
  }
@@ -5163,6 +5416,7 @@ var Task = class _Task extends SignalEmitter {
5163
5416
  * @throws {Error} Throws an error if adding a predecessor creates a cycle in the task structure.
5164
5417
  */
5165
5418
  doAfter(...tasks) {
5419
+ Cadenza.assertGraphMutationAllowed("Task#doAfter");
5166
5420
  for (const pred of tasks) {
5167
5421
  if (!pred) continue;
5168
5422
  if (this.predecessorTasks.has(pred)) continue;
@@ -5194,6 +5448,7 @@ var Task = class _Task extends SignalEmitter {
5194
5448
  * @throws {Error} Throws an error if adding a task causes a cyclic dependency.
5195
5449
  */
5196
5450
  then(...tasks) {
5451
+ Cadenza.assertGraphMutationAllowed("Task#then");
5197
5452
  for (const next of tasks) {
5198
5453
  if (!next) continue;
5199
5454
  if (this.nextTasks.has(next)) continue;
@@ -5357,6 +5612,7 @@ var Task = class _Task extends SignalEmitter {
5357
5612
  * @return {this} The current instance after adding the specified signals.
5358
5613
  */
5359
5614
  doOn(...signals) {
5615
+ Cadenza.assertGraphMutationAllowed("Task#doOn");
5360
5616
  signals.forEach((input) => {
5361
5617
  const { name: signal, metadata } = normalizeSignalDefinition(input);
5362
5618
  if (this.observedSignals.has(signal)) return;
@@ -5381,6 +5637,7 @@ var Task = class _Task extends SignalEmitter {
5381
5637
  * @return {this} The current instance for method chaining.
5382
5638
  */
5383
5639
  emits(...signals) {
5640
+ Cadenza.assertGraphMutationAllowed("Task#emits");
5384
5641
  signals.forEach((input) => {
5385
5642
  const { name: signal } = normalizeSignalDefinition(input);
5386
5643
  if (this.observedSignals.has(signal))
@@ -5400,6 +5657,7 @@ var Task = class _Task extends SignalEmitter {
5400
5657
  * @return {this} Returns the current instance for chaining.
5401
5658
  */
5402
5659
  emitsOnFail(...signals) {
5660
+ Cadenza.assertGraphMutationAllowed("Task#emitsOnFail");
5403
5661
  signals.forEach((input) => {
5404
5662
  const { name: signal } = normalizeSignalDefinition(input);
5405
5663
  this.signalsToEmitOnFail.add(signal);
@@ -5414,6 +5672,7 @@ var Task = class _Task extends SignalEmitter {
5414
5672
  * @return {void} This method does not return a value.
5415
5673
  */
5416
5674
  attachSignal(...signals) {
5675
+ Cadenza.assertGraphMutationAllowed("Task#attachSignal");
5417
5676
  signals.forEach((input) => {
5418
5677
  const { name: signal, metadata } = normalizeSignalDefinition(input);
5419
5678
  this.emitsSignals.add(signal);
@@ -5510,6 +5769,7 @@ var Task = class _Task extends SignalEmitter {
5510
5769
  return this;
5511
5770
  }
5512
5771
  respondsTo(...inquires) {
5772
+ Cadenza.assertGraphMutationAllowed("Task#respondsTo");
5513
5773
  for (const intentName of inquires) {
5514
5774
  if (this.handlesIntents.has(intentName)) {
5515
5775
  continue;
@@ -5545,6 +5805,26 @@ var Task = class _Task extends SignalEmitter {
5545
5805
  }
5546
5806
  return this;
5547
5807
  }
5808
+ usesHelpers(helpers) {
5809
+ attachHelperDependency(
5810
+ this,
5811
+ this.name,
5812
+ this.version,
5813
+ helpers,
5814
+ "meta.task.helper_associated"
5815
+ );
5816
+ return this;
5817
+ }
5818
+ usesGlobals(globals) {
5819
+ attachGlobalDependency(
5820
+ this,
5821
+ this.name,
5822
+ this.version,
5823
+ globals,
5824
+ "meta.task.global_associated"
5825
+ );
5826
+ return this;
5827
+ }
5548
5828
  attachIntents(...intentNames) {
5549
5829
  for (const intent of intentNames) {
5550
5830
  this.inquiresIntents.add(intent);
@@ -5637,6 +5917,7 @@ var Task = class _Task extends SignalEmitter {
5637
5917
  this.nextTasks.clear();
5638
5918
  this.predecessorTasks.clear();
5639
5919
  this.destroyed = true;
5920
+ Cadenza.forgetTask(this.name);
5640
5921
  if (this.register) {
5641
5922
  Cadenza.registry.tasks.delete(this.name);
5642
5923
  this.emitMetricsWithMetadata("meta.task.destroyed", {
@@ -5678,6 +5959,8 @@ var Task = class _Task extends SignalEmitter {
5678
5959
  __validateInputContext: this.validateInputContext,
5679
5960
  __outputSchema: this.outputContextSchema,
5680
5961
  __validateOutputContext: this.validateOutputContext,
5962
+ __helperAliases: Object.fromEntries(this.helperAliases),
5963
+ __globalAliases: Object.fromEntries(this.globalAliases),
5681
5964
  __nextTasks: Array.from(this.nextTasks).map((t) => t.name),
5682
5965
  __previousTasks: Array.from(this.predecessorTasks).map((t) => t.name)
5683
5966
  };
@@ -5924,6 +6207,13 @@ var DebounceTask = class extends Task {
5924
6207
  this.lastContext.getClonedContext(),
5925
6208
  this.lastEmitFunction,
5926
6209
  this.lastInquireFunction,
6210
+ Cadenza.resolveToolsForOwner(
6211
+ this,
6212
+ this.lastContext.getClonedContext(),
6213
+ this.lastEmitFunction,
6214
+ this.lastInquireFunction,
6215
+ this.lastProgressCallback
6216
+ ),
5927
6217
  this.lastProgressCallback
5928
6218
  );
5929
6219
  } catch (error) {
@@ -6078,6 +6368,19 @@ var EphemeralTask = class extends Task {
6078
6368
  progressCallback,
6079
6369
  nodeData
6080
6370
  );
6371
+ if (result instanceof Promise) {
6372
+ return result.then((resolved) => {
6373
+ if (this.once || this.condition(resolved)) {
6374
+ this.destroy();
6375
+ }
6376
+ return resolved;
6377
+ }).catch((error) => {
6378
+ if (this.once || this.condition(error)) {
6379
+ this.destroy();
6380
+ }
6381
+ throw error;
6382
+ });
6383
+ }
6081
6384
  if (this.once || this.condition(result)) {
6082
6385
  this.destroy();
6083
6386
  }
@@ -7068,6 +7371,386 @@ var InquiryBroker = class _InquiryBroker extends SignalEmitter {
7068
7371
  }
7069
7372
  };
7070
7373
 
7374
+ // src/runtime/RuntimeDefinitionRegistry.ts
7375
+ function createLinkKey(predecessorTaskName, successorTaskName) {
7376
+ return `${predecessorTaskName}=>${successorTaskName}`;
7377
+ }
7378
+ function createTaskSignalKey(taskName, signalName) {
7379
+ return `${taskName}=>${signalName}`;
7380
+ }
7381
+ function createTaskIntentKey(taskName, intentName) {
7382
+ return `${taskName}=>${intentName}`;
7383
+ }
7384
+ function createRoutineSignalKey(routineName, signalName) {
7385
+ return `${routineName}=>${signalName}`;
7386
+ }
7387
+ var RuntimeDefinitionRegistry = class {
7388
+ constructor() {
7389
+ this.taskDefinitions = /* @__PURE__ */ new Map();
7390
+ this.helperDefinitions = /* @__PURE__ */ new Map();
7391
+ this.globalDefinitions = /* @__PURE__ */ new Map();
7392
+ this.routineDefinitions = /* @__PURE__ */ new Map();
7393
+ this.intentDefinitions = /* @__PURE__ */ new Map();
7394
+ this.actorDefinitions = /* @__PURE__ */ new Map();
7395
+ this.actorTaskDefinitions = /* @__PURE__ */ new Map();
7396
+ this.taskLinks = /* @__PURE__ */ new Map();
7397
+ this.taskSignalObservations = /* @__PURE__ */ new Map();
7398
+ this.taskSignalEmissions = /* @__PURE__ */ new Map();
7399
+ this.taskIntentBindings = /* @__PURE__ */ new Map();
7400
+ this.taskHelperBindings = /* @__PURE__ */ new Map();
7401
+ this.taskGlobalBindings = /* @__PURE__ */ new Map();
7402
+ this.helperHelperBindings = /* @__PURE__ */ new Map();
7403
+ this.helperGlobalBindings = /* @__PURE__ */ new Map();
7404
+ this.routineSignalObservations = /* @__PURE__ */ new Map();
7405
+ }
7406
+ reset() {
7407
+ this.taskDefinitions.clear();
7408
+ this.helperDefinitions.clear();
7409
+ this.globalDefinitions.clear();
7410
+ this.routineDefinitions.clear();
7411
+ this.intentDefinitions.clear();
7412
+ this.actorDefinitions.clear();
7413
+ this.actorTaskDefinitions.clear();
7414
+ this.taskLinks.clear();
7415
+ this.taskSignalObservations.clear();
7416
+ this.taskSignalEmissions.clear();
7417
+ this.taskIntentBindings.clear();
7418
+ this.taskHelperBindings.clear();
7419
+ this.taskGlobalBindings.clear();
7420
+ this.helperHelperBindings.clear();
7421
+ this.helperGlobalBindings.clear();
7422
+ this.routineSignalObservations.clear();
7423
+ }
7424
+ setTaskDefinition(definition) {
7425
+ this.taskDefinitions.set(definition.name, {
7426
+ ...definition,
7427
+ kind: definition.kind ?? "task",
7428
+ options: definition.options ? { ...definition.options } : void 0
7429
+ });
7430
+ }
7431
+ setHelperDefinition(definition) {
7432
+ this.helperDefinitions.set(definition.name, {
7433
+ ...definition,
7434
+ kind: definition.kind ?? "helper"
7435
+ });
7436
+ }
7437
+ setGlobalDefinition(definition) {
7438
+ this.globalDefinitions.set(definition.name, {
7439
+ ...definition,
7440
+ kind: definition.kind ?? "global",
7441
+ value: definition.value
7442
+ });
7443
+ }
7444
+ setRoutineDefinition(definition) {
7445
+ this.routineDefinitions.set(definition.name, {
7446
+ ...definition,
7447
+ startTaskNames: [...definition.startTaskNames],
7448
+ isMeta: definition.isMeta === true
7449
+ });
7450
+ }
7451
+ setIntentDefinition(definition) {
7452
+ this.intentDefinitions.set(definition.name, {
7453
+ ...definition,
7454
+ input: definition.input ? { ...definition.input } : void 0,
7455
+ output: definition.output ? { ...definition.output } : void 0
7456
+ });
7457
+ }
7458
+ setActorDefinition(definition) {
7459
+ this.actorDefinitions.set(definition.name, {
7460
+ ...definition,
7461
+ state: definition.state ? {
7462
+ ...definition.state,
7463
+ durable: definition.state.durable ? { ...definition.state.durable } : void 0,
7464
+ runtime: definition.state.runtime ? { ...definition.state.runtime } : void 0
7465
+ } : void 0,
7466
+ tasks: definition.tasks ? definition.tasks.map((task) => ({ ...task })) : void 0
7467
+ });
7468
+ }
7469
+ setActorTaskDefinition(definition) {
7470
+ this.actorTaskDefinitions.set(definition.taskName, {
7471
+ ...definition,
7472
+ mode: definition.mode ?? "read",
7473
+ options: definition.options ? { ...definition.options } : void 0
7474
+ });
7475
+ }
7476
+ setTaskLink(definition) {
7477
+ this.taskLinks.set(
7478
+ createLinkKey(
7479
+ definition.predecessorTaskName,
7480
+ definition.successorTaskName
7481
+ ),
7482
+ { ...definition }
7483
+ );
7484
+ }
7485
+ setTaskSignalObservation(definition) {
7486
+ const signalName = typeof definition.signal === "string" ? definition.signal : definition.signal.name;
7487
+ this.taskSignalObservations.set(
7488
+ createTaskSignalKey(definition.taskName, signalName),
7489
+ {
7490
+ taskName: definition.taskName,
7491
+ signal: typeof definition.signal === "string" ? definition.signal : {
7492
+ name: definition.signal.name,
7493
+ deliveryMode: definition.signal.deliveryMode,
7494
+ broadcastFilter: definition.signal.broadcastFilter ?? null
7495
+ }
7496
+ }
7497
+ );
7498
+ }
7499
+ setTaskSignalEmission(definition) {
7500
+ const signalName = typeof definition.signal === "string" ? definition.signal : definition.signal.name;
7501
+ this.taskSignalEmissions.set(
7502
+ `${definition.taskName}=>${definition.mode ?? "after"}=>${signalName}`,
7503
+ {
7504
+ taskName: definition.taskName,
7505
+ mode: definition.mode ?? "after",
7506
+ signal: typeof definition.signal === "string" ? definition.signal : {
7507
+ name: definition.signal.name,
7508
+ deliveryMode: definition.signal.deliveryMode,
7509
+ broadcastFilter: definition.signal.broadcastFilter ?? null
7510
+ }
7511
+ }
7512
+ );
7513
+ }
7514
+ setTaskIntentBinding(definition) {
7515
+ this.taskIntentBindings.set(
7516
+ createTaskIntentKey(definition.taskName, definition.intentName),
7517
+ { ...definition }
7518
+ );
7519
+ }
7520
+ setTaskHelperBinding(definition) {
7521
+ this.taskHelperBindings.set(
7522
+ `${definition.taskName}=>${definition.alias}`,
7523
+ { ...definition }
7524
+ );
7525
+ }
7526
+ setTaskGlobalBinding(definition) {
7527
+ this.taskGlobalBindings.set(
7528
+ `${definition.taskName}=>${definition.alias}`,
7529
+ { ...definition }
7530
+ );
7531
+ }
7532
+ setHelperHelperBinding(definition) {
7533
+ this.helperHelperBindings.set(
7534
+ `${definition.helperName}=>${definition.alias}`,
7535
+ { ...definition }
7536
+ );
7537
+ }
7538
+ setHelperGlobalBinding(definition) {
7539
+ this.helperGlobalBindings.set(
7540
+ `${definition.helperName}=>${definition.alias}`,
7541
+ { ...definition }
7542
+ );
7543
+ }
7544
+ setRoutineSignalObservation(definition) {
7545
+ this.routineSignalObservations.set(
7546
+ createRoutineSignalKey(definition.routineName, definition.signal),
7547
+ { ...definition }
7548
+ );
7549
+ }
7550
+ isRuntimeOwnedTask(taskName) {
7551
+ return this.taskDefinitions.has(taskName) || this.actorTaskDefinitions.has(taskName);
7552
+ }
7553
+ isRuntimeOwnedHelper(helperName) {
7554
+ return this.helperDefinitions.has(helperName);
7555
+ }
7556
+ isRuntimeOwnedGlobal(globalName) {
7557
+ return this.globalDefinitions.has(globalName);
7558
+ }
7559
+ isRuntimeOwnedRoutine(routineName) {
7560
+ return this.routineDefinitions.has(routineName);
7561
+ }
7562
+ isRuntimeOwnedActor(actorName) {
7563
+ return this.actorDefinitions.has(actorName);
7564
+ }
7565
+ };
7566
+ var runtimeDefinitionRegistry = new RuntimeDefinitionRegistry();
7567
+
7568
+ // src/runtime/sandbox.ts
7569
+ var import_node_vm = __toESM(require("vm"));
7570
+ var import_typescript = __toESM(require("typescript"));
7571
+ var FORBIDDEN_SOURCE_PATTERNS = [
7572
+ {
7573
+ pattern: /\bimport\b/,
7574
+ message: "Runtime handler source must not contain import statements"
7575
+ },
7576
+ {
7577
+ pattern: /\bexport\b/,
7578
+ message: "Runtime handler source must not contain export statements"
7579
+ },
7580
+ {
7581
+ pattern: /\brequire\s*\(/,
7582
+ message: "Runtime handler source must not call require()"
7583
+ },
7584
+ {
7585
+ pattern: /\bprocess\b/,
7586
+ message: "Runtime handler source must not access process"
7587
+ },
7588
+ {
7589
+ pattern: /\bFunction\s*\(/,
7590
+ message: "Runtime handler source must not create dynamic functions"
7591
+ },
7592
+ {
7593
+ pattern: /\beval\s*\(/,
7594
+ message: "Runtime handler source must not call eval()"
7595
+ }
7596
+ ];
7597
+ function transpileIfNeeded(source, language, filename) {
7598
+ if (language === "js") {
7599
+ return source;
7600
+ }
7601
+ const result = import_typescript.default.transpileModule(source, {
7602
+ compilerOptions: {
7603
+ target: import_typescript.default.ScriptTarget.ES2020,
7604
+ module: import_typescript.default.ModuleKind.ESNext
7605
+ },
7606
+ fileName: filename,
7607
+ reportDiagnostics: true
7608
+ });
7609
+ const diagnostics = result.diagnostics ?? [];
7610
+ const blockingDiagnostics = diagnostics.filter(
7611
+ (diagnostic) => diagnostic.category === import_typescript.default.DiagnosticCategory.Error
7612
+ );
7613
+ if (blockingDiagnostics.length > 0) {
7614
+ const message = blockingDiagnostics.map((diagnostic) => import_typescript.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n")).join("; ");
7615
+ throw new Error(`TypeScript transpile failed: ${message}`);
7616
+ }
7617
+ return result.outputText;
7618
+ }
7619
+ function createSandbox() {
7620
+ const sandbox = /* @__PURE__ */ Object.create(null);
7621
+ sandbox.global = void 0;
7622
+ sandbox.globalThis = sandbox;
7623
+ sandbox.process = void 0;
7624
+ sandbox.require = void 0;
7625
+ sandbox.module = void 0;
7626
+ sandbox.exports = void 0;
7627
+ sandbox.Buffer = void 0;
7628
+ sandbox.fetch = void 0;
7629
+ sandbox.WebSocket = void 0;
7630
+ sandbox.XMLHttpRequest = void 0;
7631
+ sandbox.setTimeout = void 0;
7632
+ sandbox.setInterval = void 0;
7633
+ sandbox.clearTimeout = void 0;
7634
+ sandbox.clearInterval = void 0;
7635
+ sandbox.queueMicrotask = void 0;
7636
+ return import_node_vm.default.createContext(sandbox);
7637
+ }
7638
+ function compileFunctionFromSource(source, language, filename, label) {
7639
+ const normalizedSource = String(source ?? "").trim();
7640
+ if (!normalizedSource) {
7641
+ throw new Error(`${label} source must be a non-empty string`);
7642
+ }
7643
+ for (const rule of FORBIDDEN_SOURCE_PATTERNS) {
7644
+ if (rule.pattern.test(normalizedSource)) {
7645
+ throw new Error(rule.message);
7646
+ }
7647
+ }
7648
+ const wrappedSource = `const __runtime_handler = ${normalizedSource};
7649
+ __runtime_handler;`;
7650
+ const transpiledSource = transpileIfNeeded(
7651
+ wrappedSource,
7652
+ language,
7653
+ filename
7654
+ ).trim();
7655
+ const sandbox = createSandbox();
7656
+ const script = new import_node_vm.default.Script(transpiledSource, {
7657
+ filename
7658
+ });
7659
+ const compiled = script.runInContext(sandbox, {
7660
+ timeout: 1e3,
7661
+ displayErrors: true,
7662
+ contextCodeGeneration: {
7663
+ strings: false,
7664
+ wasm: false
7665
+ }
7666
+ });
7667
+ if (typeof compiled !== "function") {
7668
+ throw new Error(`${label} source must evaluate to a function`);
7669
+ }
7670
+ return compiled;
7671
+ }
7672
+ function compileRuntimeTaskFunction(definition) {
7673
+ return compileFunctionFromSource(
7674
+ definition.handlerSource,
7675
+ definition.language,
7676
+ `${definition.name}.runtime-task.${definition.language}`,
7677
+ `Task "${definition.name}"`
7678
+ );
7679
+ }
7680
+ function compileRuntimeHelperFunction(definition) {
7681
+ return compileFunctionFromSource(
7682
+ definition.handlerSource,
7683
+ definition.language,
7684
+ `${definition.name}.runtime-helper.${definition.language}`,
7685
+ `Helper "${definition.name}"`
7686
+ );
7687
+ }
7688
+ function compileRuntimeActorTaskHandler(definition) {
7689
+ return compileFunctionFromSource(
7690
+ definition.handlerSource,
7691
+ definition.language,
7692
+ `${definition.actorName}.${definition.taskName}.runtime-actor-task.${definition.language}`,
7693
+ `Actor task "${definition.taskName}"`
7694
+ );
7695
+ }
7696
+
7697
+ // src/runtime/sanitize.ts
7698
+ function isPlainObject2(value) {
7699
+ return typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype;
7700
+ }
7701
+ function sanitizeForJson(value, seen = /* @__PURE__ */ new WeakSet()) {
7702
+ if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
7703
+ return value ?? null;
7704
+ }
7705
+ if (typeof value === "bigint") {
7706
+ return value.toString();
7707
+ }
7708
+ if (typeof value === "function") {
7709
+ return `[Function ${value.name || "anonymous"}]`;
7710
+ }
7711
+ if (typeof value === "symbol") {
7712
+ return value.toString();
7713
+ }
7714
+ if (value instanceof Date) {
7715
+ return value.toISOString();
7716
+ }
7717
+ if (value instanceof Set) {
7718
+ return Array.from(value).map((entry) => sanitizeForJson(entry, seen));
7719
+ }
7720
+ if (value instanceof Map) {
7721
+ return Array.from(value.entries()).map(([key, entry]) => [
7722
+ sanitizeForJson(key, seen),
7723
+ sanitizeForJson(entry, seen)
7724
+ ]);
7725
+ }
7726
+ if (Array.isArray(value)) {
7727
+ return value.map((entry) => sanitizeForJson(entry, seen));
7728
+ }
7729
+ if (typeof value === "object") {
7730
+ if (seen.has(value)) {
7731
+ return "[Circular]";
7732
+ }
7733
+ seen.add(value);
7734
+ if (!isPlainObject2(value)) {
7735
+ const clone = {};
7736
+ for (const key of Object.keys(value)) {
7737
+ clone[key] = sanitizeForJson(
7738
+ value[key],
7739
+ seen
7740
+ );
7741
+ }
7742
+ clone.__type = value.constructor?.name ?? "Object";
7743
+ return clone;
7744
+ }
7745
+ const result = {};
7746
+ for (const [key, entry] of Object.entries(value)) {
7747
+ result[key] = sanitizeForJson(entry, seen);
7748
+ }
7749
+ return result;
7750
+ }
7751
+ return String(value);
7752
+ }
7753
+
7071
7754
  // src/Cadenza.ts
7072
7755
  var Cadenza = class {
7073
7756
  /**
@@ -7150,6 +7833,73 @@ var Cadenza = class {
7150
7833
  throw new Error("Task or Routine name must be a non-empty string.");
7151
7834
  }
7152
7835
  }
7836
+ static assertGraphMutationAllowed(operationName) {
7837
+ if (this.helperExecutionDepth > 0) {
7838
+ throw new Error(
7839
+ `${operationName} is not allowed during helper execution`
7840
+ );
7841
+ }
7842
+ }
7843
+ static executeHelper(helper, context, emit, inquire, progressCallback) {
7844
+ const helperContext = context && typeof context === "object" ? context : {};
7845
+ const tools = this.resolveToolsForOwner(
7846
+ helper,
7847
+ helperContext,
7848
+ emit,
7849
+ inquire,
7850
+ progressCallback
7851
+ );
7852
+ this.helperExecutionDepth += 1;
7853
+ try {
7854
+ return helper.helperFunction(
7855
+ helperContext,
7856
+ emit,
7857
+ inquire,
7858
+ tools,
7859
+ progressCallback
7860
+ );
7861
+ } finally {
7862
+ this.helperExecutionDepth = Math.max(0, this.helperExecutionDepth - 1);
7863
+ }
7864
+ }
7865
+ static resolveToolsForOwner(owner, context, emit, inquire, progressCallback) {
7866
+ const helpers = {};
7867
+ const globals = {};
7868
+ for (const [alias, helperName] of owner.helperAliases.entries()) {
7869
+ const helper = this.getHelper(helperName);
7870
+ if (!helper) {
7871
+ continue;
7872
+ }
7873
+ if (helper.isMeta !== owner.isMeta) {
7874
+ throw new Error(
7875
+ `Tool alias "${alias}" resolves across layer boundaries`
7876
+ );
7877
+ }
7878
+ helpers[alias] = (helperContext = context) => this.executeHelper(
7879
+ helper,
7880
+ helperContext,
7881
+ emit,
7882
+ inquire,
7883
+ progressCallback
7884
+ );
7885
+ }
7886
+ for (const [alias, globalName] of owner.globalAliases.entries()) {
7887
+ const globalDefinition = this.getGlobal(globalName);
7888
+ if (!globalDefinition) {
7889
+ continue;
7890
+ }
7891
+ if (globalDefinition.isMeta !== owner.isMeta) {
7892
+ throw new Error(
7893
+ `Global alias "${alias}" resolves across layer boundaries`
7894
+ );
7895
+ }
7896
+ globals[alias] = globalDefinition.value;
7897
+ }
7898
+ return {
7899
+ helpers,
7900
+ globals
7901
+ };
7902
+ }
7153
7903
  static resolveTaskOptionsForActorTask(func, options = {}) {
7154
7904
  const metadata = getActorTaskRuntimeMetadata(func);
7155
7905
  if (!metadata?.forceMeta) {
@@ -7166,6 +7916,22 @@ var Cadenza = class {
7166
7916
  static registerActor(actor) {
7167
7917
  this.actorCache.set(actor.spec.name, actor);
7168
7918
  }
7919
+ static getHelper(name) {
7920
+ return this.helperCache.get(name);
7921
+ }
7922
+ static getAllHelpers() {
7923
+ return Array.from(this.helperCache.values()).filter(
7924
+ (helper) => !helper.destroyed
7925
+ );
7926
+ }
7927
+ static getGlobal(name) {
7928
+ return this.globalCache.get(name);
7929
+ }
7930
+ static getAllGlobals() {
7931
+ return Array.from(this.globalCache.values()).filter(
7932
+ (globalDefinition) => !globalDefinition.destroyed
7933
+ );
7934
+ }
7169
7935
  /**
7170
7936
  * Executes the specified task or GraphRoutine with the given context using an internal runner.
7171
7937
  *
@@ -7228,6 +7994,9 @@ var Cadenza = class {
7228
7994
  static get(taskName) {
7229
7995
  return this.registry?.tasks.get(taskName) ?? this.taskCache.get(taskName);
7230
7996
  }
7997
+ static forgetTask(taskName) {
7998
+ this.taskCache.delete(taskName);
7999
+ }
7231
8000
  static getActor(actorName) {
7232
8001
  return this.actorCache.get(actorName);
7233
8002
  }
@@ -7235,9 +8004,10 @@ var Cadenza = class {
7235
8004
  return Array.from(this.actorCache.values());
7236
8005
  }
7237
8006
  static getRoutine(routineName) {
7238
- return this.registry?.routines.get(routineName);
8007
+ return this.registry?.routines.get(routineName) ?? this.routineCache.get(routineName);
7239
8008
  }
7240
8009
  static defineIntent(intent) {
8010
+ this.assertGraphMutationAllowed("Cadenza.defineIntent");
7241
8011
  this.inquiryBroker?.addIntent(intent);
7242
8012
  return intent;
7243
8013
  }
@@ -7391,6 +8161,7 @@ var Cadenza = class {
7391
8161
  * participate in the graph like any other task.
7392
8162
  */
7393
8163
  static createActor(spec, options = {}) {
8164
+ this.assertGraphMutationAllowed("Cadenza.createActor");
7394
8165
  this.bootstrap();
7395
8166
  const actor = new Actor(spec, options);
7396
8167
  this.registerActor(actor);
@@ -7506,6 +8277,7 @@ var Cadenza = class {
7506
8277
  * ```
7507
8278
  */
7508
8279
  static createTask(name, func, description, options = {}) {
8280
+ this.assertGraphMutationAllowed("Cadenza.createTask");
7509
8281
  this.bootstrap();
7510
8282
  this.validateName(name);
7511
8283
  const actorResolvedOptions = this.resolveTaskOptionsForActorTask(
@@ -7555,14 +8327,172 @@ var Cadenza = class {
7555
8327
  this.taskCache.set(name, createdTask);
7556
8328
  return createdTask;
7557
8329
  }
7558
- /**
7559
- * Creates a meta task with the specified name, functionality, description, and options.
7560
- * This is used for creating tasks that lives on the meta layer.
7561
- * The meta layer is a special layer that is executed separately from the business logic layer and is used for extending Cadenzas core functionality.
7562
- * See {@link Task} or {@link createTask} for more information.
7563
- *
7564
- * @param {string} name - The name of the meta task.
7565
- * @param {TaskFunction} func - The function to be executed by the meta task.
8330
+ static createTaskFromDefinition(definition) {
8331
+ this.bootstrap();
8332
+ this.validateName(definition.name);
8333
+ const existing = this.get(definition.name);
8334
+ if (existing) {
8335
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedTask(definition.name)) {
8336
+ throw new Error(
8337
+ `Task "${definition.name}" already exists and is not runtime-owned`
8338
+ );
8339
+ }
8340
+ existing.destroy();
8341
+ }
8342
+ const taskFunction = compileRuntimeTaskFunction(definition);
8343
+ const createdTask = definition.kind === "metaTask" ? this.createMetaTask(
8344
+ definition.name,
8345
+ taskFunction,
8346
+ definition.description ?? "",
8347
+ definition.options ?? {}
8348
+ ) : this.createTask(
8349
+ definition.name,
8350
+ taskFunction,
8351
+ definition.description ?? "",
8352
+ definition.options ?? {}
8353
+ );
8354
+ runtimeDefinitionRegistry.setTaskDefinition(definition);
8355
+ return createdTask;
8356
+ }
8357
+ static createHelper(name, func, description = "") {
8358
+ this.bootstrap();
8359
+ this.validateName(name);
8360
+ this.assertGraphMutationAllowed("Cadenza.createHelper");
8361
+ if (this.helperCache.has(name)) {
8362
+ throw new Error(`Helper "${name}" already exists`);
8363
+ }
8364
+ const helper = new HelperDefinition(name, func, description, false);
8365
+ this.helperCache.set(name, helper);
8366
+ this.emit("meta.helper.created", {
8367
+ data: {
8368
+ name,
8369
+ version: helper.version,
8370
+ description,
8371
+ functionString: func.toString(),
8372
+ isMeta: false
8373
+ }
8374
+ });
8375
+ return helper;
8376
+ }
8377
+ static createMetaHelper(name, func, description = "") {
8378
+ this.bootstrap();
8379
+ this.validateName(name);
8380
+ this.assertGraphMutationAllowed("Cadenza.createMetaHelper");
8381
+ if (this.helperCache.has(name)) {
8382
+ throw new Error(`Helper "${name}" already exists`);
8383
+ }
8384
+ const helper = new HelperDefinition(name, func, description, true);
8385
+ this.helperCache.set(name, helper);
8386
+ this.emit("meta.helper.created", {
8387
+ data: {
8388
+ name,
8389
+ version: helper.version,
8390
+ description,
8391
+ functionString: func.toString(),
8392
+ isMeta: true
8393
+ }
8394
+ });
8395
+ return helper;
8396
+ }
8397
+ static createHelperFromDefinition(definition) {
8398
+ this.bootstrap();
8399
+ this.validateName(definition.name);
8400
+ const existing = this.getHelper(definition.name);
8401
+ if (existing) {
8402
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedHelper(definition.name)) {
8403
+ throw new Error(
8404
+ `Helper "${definition.name}" already exists and is not runtime-owned`
8405
+ );
8406
+ }
8407
+ existing.destroy();
8408
+ this.helperCache.delete(definition.name);
8409
+ }
8410
+ const helperFunction = compileRuntimeHelperFunction(definition);
8411
+ const helper = definition.kind === "metaHelper" ? this.createMetaHelper(
8412
+ definition.name,
8413
+ helperFunction,
8414
+ definition.description ?? ""
8415
+ ) : this.createHelper(
8416
+ definition.name,
8417
+ helperFunction,
8418
+ definition.description ?? ""
8419
+ );
8420
+ runtimeDefinitionRegistry.setHelperDefinition(definition);
8421
+ return helper;
8422
+ }
8423
+ static createGlobal(name, value, description = "") {
8424
+ this.bootstrap();
8425
+ this.validateName(name);
8426
+ this.assertGraphMutationAllowed("Cadenza.createGlobal");
8427
+ if (this.globalCache.has(name)) {
8428
+ throw new Error(`Global "${name}" already exists`);
8429
+ }
8430
+ const globalDefinition = new GlobalDefinition(name, value, description, false);
8431
+ this.globalCache.set(name, globalDefinition);
8432
+ this.emit("meta.global.created", {
8433
+ data: {
8434
+ name,
8435
+ version: globalDefinition.version,
8436
+ description,
8437
+ isMeta: false,
8438
+ value: globalDefinition.value
8439
+ }
8440
+ });
8441
+ return globalDefinition;
8442
+ }
8443
+ static createMetaGlobal(name, value, description = "") {
8444
+ this.bootstrap();
8445
+ this.validateName(name);
8446
+ this.assertGraphMutationAllowed("Cadenza.createMetaGlobal");
8447
+ if (this.globalCache.has(name)) {
8448
+ throw new Error(`Global "${name}" already exists`);
8449
+ }
8450
+ const globalDefinition = new GlobalDefinition(name, value, description, true);
8451
+ this.globalCache.set(name, globalDefinition);
8452
+ this.emit("meta.global.created", {
8453
+ data: {
8454
+ name,
8455
+ version: globalDefinition.version,
8456
+ description,
8457
+ isMeta: true,
8458
+ value: globalDefinition.value
8459
+ }
8460
+ });
8461
+ return globalDefinition;
8462
+ }
8463
+ static createGlobalFromDefinition(definition) {
8464
+ this.bootstrap();
8465
+ this.validateName(definition.name);
8466
+ const existing = this.getGlobal(definition.name);
8467
+ if (existing) {
8468
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedGlobal(definition.name)) {
8469
+ throw new Error(
8470
+ `Global "${definition.name}" already exists and is not runtime-owned`
8471
+ );
8472
+ }
8473
+ existing.destroy();
8474
+ this.globalCache.delete(definition.name);
8475
+ }
8476
+ const globalDefinition = definition.kind === "metaGlobal" ? this.createMetaGlobal(
8477
+ definition.name,
8478
+ definition.value,
8479
+ definition.description ?? ""
8480
+ ) : this.createGlobal(
8481
+ definition.name,
8482
+ definition.value,
8483
+ definition.description ?? ""
8484
+ );
8485
+ runtimeDefinitionRegistry.setGlobalDefinition(definition);
8486
+ return globalDefinition;
8487
+ }
8488
+ /**
8489
+ * Creates a meta task with the specified name, functionality, description, and options.
8490
+ * This is used for creating tasks that lives on the meta layer.
8491
+ * The meta layer is a special layer that is executed separately from the business logic layer and is used for extending Cadenzas core functionality.
8492
+ * See {@link Task} or {@link createTask} for more information.
8493
+ *
8494
+ * @param {string} name - The name of the meta task.
8495
+ * @param {TaskFunction} func - The function to be executed by the meta task.
7566
8496
  * @param {string} [description] - An optional description of the meta task.
7567
8497
  * @param {TaskOptions} [options={}] - Additional optional task configuration. Automatically sets `isMeta` to true.
7568
8498
  * @return {Task} A task instance configured as a meta task.
@@ -7620,6 +8550,7 @@ var Cadenza = class {
7620
8550
  *
7621
8551
  */
7622
8552
  static createUniqueTask(name, func, description, options = {}) {
8553
+ this.assertGraphMutationAllowed("Cadenza.createUniqueTask");
7623
8554
  options.isUnique = true;
7624
8555
  return this.createTask(name, func, description, options);
7625
8556
  }
@@ -7668,6 +8599,7 @@ var Cadenza = class {
7668
8599
  * ```
7669
8600
  */
7670
8601
  static createThrottledTask(name, func, throttledIdGetter = () => "default", description, options = {}) {
8602
+ this.assertGraphMutationAllowed("Cadenza.createThrottledTask");
7671
8603
  options.concurrency = 1;
7672
8604
  options.getTagCallback = throttledIdGetter;
7673
8605
  return this.createTask(name, func, description, options);
@@ -7727,6 +8659,7 @@ var Cadenza = class {
7727
8659
  * ```
7728
8660
  */
7729
8661
  static createDebounceTask(name, func, description, debounceTime = 1e3, options = {}) {
8662
+ this.assertGraphMutationAllowed("Cadenza.createDebounceTask");
7730
8663
  this.bootstrap();
7731
8664
  this.validateName(name);
7732
8665
  const actorResolvedOptions = this.resolveTaskOptionsForActorTask(
@@ -7855,6 +8788,7 @@ var Cadenza = class {
7855
8788
  * ```
7856
8789
  */
7857
8790
  static createEphemeralTask(name, func, description, options = {}) {
8791
+ this.assertGraphMutationAllowed("Cadenza.createEphemeralTask");
7858
8792
  this.bootstrap();
7859
8793
  this.validateName(name);
7860
8794
  const actorResolvedOptions = this.resolveTaskOptionsForActorTask(
@@ -7951,12 +8885,46 @@ var Cadenza = class {
7951
8885
  * ```
7952
8886
  */
7953
8887
  static createRoutine(name, tasks, description = "") {
8888
+ this.assertGraphMutationAllowed("Cadenza.createRoutine");
7954
8889
  this.bootstrap();
7955
8890
  this.validateName(name);
7956
8891
  if (tasks.length === 0) {
7957
8892
  throw new Error(`Routine '${name}' created with no starting tasks.`);
7958
8893
  }
7959
- return new GraphRoutine(name, tasks, description);
8894
+ const createdRoutine = new GraphRoutine(name, tasks, description);
8895
+ this.routineCache.set(name, createdRoutine);
8896
+ return createdRoutine;
8897
+ }
8898
+ static createRoutineFromDefinition(definition) {
8899
+ const existing = this.getRoutine(definition.name);
8900
+ if (existing) {
8901
+ if (!runtimeDefinitionRegistry.isRuntimeOwnedRoutine(definition.name)) {
8902
+ throw new Error(
8903
+ `Routine "${definition.name}" already exists and is not runtime-owned`
8904
+ );
8905
+ }
8906
+ existing.destroy();
8907
+ }
8908
+ const startTasks = definition.startTaskNames.map((taskName) => {
8909
+ const task = this.get(taskName);
8910
+ if (!task) {
8911
+ throw new Error(
8912
+ `Routine "${definition.name}" references missing task "${taskName}"`
8913
+ );
8914
+ }
8915
+ return task;
8916
+ });
8917
+ const routine = definition.isMeta === true ? this.createMetaRoutine(
8918
+ definition.name,
8919
+ startTasks,
8920
+ definition.description ?? ""
8921
+ ) : this.createRoutine(
8922
+ definition.name,
8923
+ startTasks,
8924
+ definition.description ?? ""
8925
+ );
8926
+ runtimeDefinitionRegistry.setRoutineDefinition(definition);
8927
+ return routine;
7960
8928
  }
7961
8929
  /**
7962
8930
  * Creates a meta routine with a given name, tasks, and optional description.
@@ -7971,34 +8939,1418 @@ var Cadenza = class {
7971
8939
  * @throws {Error} If no starting tasks are provided.
7972
8940
  */
7973
8941
  static createMetaRoutine(name, tasks, description = "") {
8942
+ this.assertGraphMutationAllowed("Cadenza.createMetaRoutine");
7974
8943
  this.bootstrap();
7975
8944
  this.validateName(name);
7976
8945
  if (tasks.length === 0) {
7977
8946
  throw new Error(`Routine '${name}' created with no starting tasks.`);
7978
8947
  }
7979
- return new GraphRoutine(name, tasks, description, true);
8948
+ const createdRoutine = new GraphRoutine(name, tasks, description, true);
8949
+ this.routineCache.set(name, createdRoutine);
8950
+ return createdRoutine;
8951
+ }
8952
+ static snapshotRuntime() {
8953
+ const taskMap = /* @__PURE__ */ new Map();
8954
+ for (const task of this.taskCache.values()) {
8955
+ taskMap.set(task.name, task);
8956
+ }
8957
+ for (const task of this.registry?.tasks.values() ?? []) {
8958
+ taskMap.set(task.name, task);
8959
+ }
8960
+ const tasks = Array.from(taskMap.values()).map((task) => {
8961
+ const runtimeTaskDefinition = runtimeDefinitionRegistry.taskDefinitions.get(
8962
+ task.name
8963
+ );
8964
+ const runtimeActorTaskDefinition = runtimeDefinitionRegistry.actorTaskDefinitions.get(task.name);
8965
+ return {
8966
+ name: task.name,
8967
+ version: task.version,
8968
+ description: task.description,
8969
+ kind: runtimeActorTaskDefinition ? "actorTask" : task.isMeta ? "metaTask" : "task",
8970
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedTask(task.name) === true,
8971
+ language: runtimeTaskDefinition?.language ?? runtimeActorTaskDefinition?.language ?? null,
8972
+ handlerSource: runtimeTaskDefinition?.handlerSource ?? runtimeActorTaskDefinition?.handlerSource ?? null,
8973
+ concurrency: task.concurrency,
8974
+ timeout: task.timeout,
8975
+ retryCount: task.retryCount,
8976
+ retryDelay: task.retryDelay,
8977
+ retryDelayMax: task.retryDelayMax,
8978
+ retryDelayFactor: task.retryDelayFactor,
8979
+ validateInputContext: task.validateInputContext,
8980
+ validateOutputContext: task.validateOutputContext,
8981
+ inputContextSchema: sanitizeForJson(task.inputContextSchema),
8982
+ outputContextSchema: sanitizeForJson(task.outputContextSchema),
8983
+ nextTaskNames: Array.from(task.nextTasks).map((nextTask) => nextTask.name),
8984
+ predecessorTaskNames: Array.from(task.predecessorTasks).map(
8985
+ (predecessorTask) => predecessorTask.name
8986
+ ),
8987
+ signals: {
8988
+ emits: Array.from(task.emitsSignals),
8989
+ emitsAfter: Array.from(task.signalsToEmitAfter),
8990
+ emitsOnFail: Array.from(task.signalsToEmitOnFail),
8991
+ observed: Array.from(task.observedSignals)
8992
+ },
8993
+ intents: {
8994
+ handles: Array.from(task.handlesIntents),
8995
+ inquires: Array.from(task.inquiresIntents)
8996
+ },
8997
+ tools: {
8998
+ helpers: Object.fromEntries(task.helperAliases),
8999
+ globals: Object.fromEntries(task.globalAliases)
9000
+ },
9001
+ actorName: runtimeActorTaskDefinition?.actorName ?? null,
9002
+ actorMode: runtimeActorTaskDefinition?.mode ?? null
9003
+ };
9004
+ });
9005
+ const helpers = this.getAllHelpers().map((helper) => {
9006
+ const runtimeHelperDefinition = runtimeDefinitionRegistry.helperDefinitions.get(helper.name);
9007
+ return {
9008
+ name: helper.name,
9009
+ version: helper.version,
9010
+ description: helper.description,
9011
+ kind: helper.isMeta ? "metaHelper" : "helper",
9012
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedHelper(helper.name),
9013
+ language: runtimeHelperDefinition?.language ?? null,
9014
+ handlerSource: runtimeHelperDefinition?.handlerSource ?? null,
9015
+ tools: {
9016
+ helpers: Object.fromEntries(helper.helperAliases),
9017
+ globals: Object.fromEntries(helper.globalAliases)
9018
+ }
9019
+ };
9020
+ });
9021
+ const globals = this.getAllGlobals().map((globalDefinition) => ({
9022
+ name: globalDefinition.name,
9023
+ version: globalDefinition.version,
9024
+ description: globalDefinition.description,
9025
+ kind: globalDefinition.isMeta ? "metaGlobal" : "global",
9026
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedGlobal(
9027
+ globalDefinition.name
9028
+ ),
9029
+ value: sanitizeForJson(globalDefinition.value)
9030
+ }));
9031
+ const routineMap = /* @__PURE__ */ new Map();
9032
+ for (const routine of this.routineCache.values()) {
9033
+ routineMap.set(routine.name, routine);
9034
+ }
9035
+ for (const routine of this.registry?.routines.values() ?? []) {
9036
+ routineMap.set(routine.name, routine);
9037
+ }
9038
+ const routines = Array.from(routineMap.values()).map(
9039
+ (routine) => ({
9040
+ name: routine.name,
9041
+ version: routine.version,
9042
+ description: routine.description,
9043
+ isMeta: routine.isMeta,
9044
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedRoutine(routine.name) === true,
9045
+ startTaskNames: Array.from(routine.tasks).map((task) => task.name),
9046
+ observedSignals: Array.from(routine.observedSignals)
9047
+ })
9048
+ );
9049
+ const intents = Array.from(this.inquiryBroker?.intents.values() ?? []).map(
9050
+ (intent) => {
9051
+ const sanitizedIntent = sanitizeForJson(intent);
9052
+ return {
9053
+ ...sanitizedIntent,
9054
+ runtimeOwned: runtimeDefinitionRegistry.intentDefinitions.has(
9055
+ intent.name
9056
+ )
9057
+ };
9058
+ }
9059
+ );
9060
+ const signals = Array.from(
9061
+ this.signalBroker?.emittedSignalsRegistry.values() ?? []
9062
+ ).map((signalName) => ({
9063
+ name: signalName,
9064
+ metadata: sanitizeForJson(
9065
+ this.signalBroker?.signalMetadataRegistry.get(signalName) ?? null
9066
+ ) ?? null
9067
+ }));
9068
+ const actors = this.getAllActors().map((actor) => {
9069
+ const definition = actor.toDefinition();
9070
+ const actorKeys = actor.listActorKeys().map((actorKey) => ({
9071
+ actorKey,
9072
+ durableState: sanitizeForJson(actor.getDurableState(actorKey)),
9073
+ runtimeState: sanitizeForJson(actor.getRuntimeState(actorKey)),
9074
+ durableVersion: actor.getDurableVersion(actorKey),
9075
+ runtimeVersion: actor.getRuntimeVersion(actorKey)
9076
+ }));
9077
+ return {
9078
+ name: actor.spec.name,
9079
+ description: actor.spec.description ?? "",
9080
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedActor(
9081
+ actor.spec.name
9082
+ ),
9083
+ definition: sanitizeForJson(definition),
9084
+ actorKeys
9085
+ };
9086
+ });
9087
+ const actorTasks = Array.from(
9088
+ runtimeDefinitionRegistry.actorTaskDefinitions.values()
9089
+ ).map((definition) => ({
9090
+ actorName: definition.actorName,
9091
+ taskName: definition.taskName,
9092
+ description: definition.description ?? "",
9093
+ mode: definition.mode ?? "read",
9094
+ language: definition.language,
9095
+ handlerSource: definition.handlerSource,
9096
+ runtimeOwned: true
9097
+ }));
9098
+ const links = Array.from(runtimeDefinitionRegistry.taskLinks.values()).map(
9099
+ (link) => ({ ...link })
9100
+ );
9101
+ return {
9102
+ runtimeMode: "core",
9103
+ bootstrapped: this.isBootstrapped,
9104
+ mode: this.mode,
9105
+ tasks,
9106
+ helpers,
9107
+ globals,
9108
+ routines,
9109
+ intents,
9110
+ signals,
9111
+ actors,
9112
+ actorTasks,
9113
+ links
9114
+ };
7980
9115
  }
7981
9116
  static reset() {
7982
9117
  this.signalBroker?.reset();
7983
9118
  this.inquiryBroker?.reset();
7984
9119
  this.registry?.reset();
7985
9120
  this.taskCache.clear();
9121
+ this.routineCache.clear();
7986
9122
  this.actorCache.clear();
9123
+ this.helperCache.clear();
9124
+ this.globalCache.clear();
7987
9125
  this.runtimeInquiryDelegate = void 0;
7988
9126
  this.runtimeValidationPolicy = {};
7989
9127
  this.runtimeValidationScopes.clear();
7990
9128
  this.emittedMissingSchemaWarnings.clear();
9129
+ this.helperExecutionDepth = 0;
9130
+ runtimeDefinitionRegistry.reset();
7991
9131
  this.isBootstrapped = false;
7992
9132
  }
7993
9133
  };
7994
9134
  Cadenza.taskCache = /* @__PURE__ */ new Map();
9135
+ Cadenza.routineCache = /* @__PURE__ */ new Map();
7995
9136
  Cadenza.actorCache = /* @__PURE__ */ new Map();
9137
+ Cadenza.helperCache = /* @__PURE__ */ new Map();
9138
+ Cadenza.globalCache = /* @__PURE__ */ new Map();
7996
9139
  Cadenza.runtimeValidationPolicy = {};
7997
9140
  Cadenza.runtimeValidationScopes = /* @__PURE__ */ new Map();
7998
9141
  Cadenza.emittedMissingSchemaWarnings = /* @__PURE__ */ new Set();
9142
+ Cadenza.helperExecutionDepth = 0;
7999
9143
  Cadenza.isBootstrapped = false;
8000
9144
  Cadenza.mode = "production";
8001
9145
 
9146
+ // src/runtime/RuntimeSubscriptionManager.ts
9147
+ var import_uuid8 = require("uuid");
9148
+ function isObject3(value) {
9149
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9150
+ }
9151
+ function asStringOrNull(value) {
9152
+ return typeof value === "string" && value.length > 0 ? value : null;
9153
+ }
9154
+ function asNumberOrNull(value) {
9155
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
9156
+ }
9157
+ function normalizeEventContext(context) {
9158
+ const sanitized = sanitizeForJson(context);
9159
+ return isObject3(sanitized) ? sanitized : { value: sanitized };
9160
+ }
9161
+ function matchesSignalPattern(fullSignal, signalName, patterns) {
9162
+ return patterns.some((pattern) => {
9163
+ if (pattern === "*") {
9164
+ return true;
9165
+ }
9166
+ if (pattern === fullSignal || pattern === signalName) {
9167
+ return true;
9168
+ }
9169
+ if (!pattern.endsWith(".*")) {
9170
+ return false;
9171
+ }
9172
+ const prefix = pattern.slice(0, -2);
9173
+ return signalName === prefix || signalName.startsWith(`${prefix}.`);
9174
+ });
9175
+ }
9176
+ var RuntimeSubscriptionManagerError = class extends Error {
9177
+ constructor(code, message) {
9178
+ super(message);
9179
+ this.code = code;
9180
+ this.name = "RuntimeSubscriptionManagerError";
9181
+ }
9182
+ };
9183
+ var RuntimeSubscriptionManager = class {
9184
+ constructor() {
9185
+ this.subscriptions = /* @__PURE__ */ new Map();
9186
+ this.removeBrokerListener = null;
9187
+ this.nextSequence = 0;
9188
+ this.attach();
9189
+ }
9190
+ dispose() {
9191
+ this.reset();
9192
+ this.removeBrokerListener?.();
9193
+ this.removeBrokerListener = null;
9194
+ }
9195
+ subscribe(signalPatterns, maxQueueSize) {
9196
+ this.attach();
9197
+ const descriptor = {
9198
+ subscriptionId: (0, import_uuid8.v4)(),
9199
+ signalPatterns: [...signalPatterns],
9200
+ maxQueueSize,
9201
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
9202
+ pendingEvents: 0
9203
+ };
9204
+ this.subscriptions.set(descriptor.subscriptionId, {
9205
+ descriptor,
9206
+ events: [],
9207
+ nextWaiter: null
9208
+ });
9209
+ return { ...descriptor };
9210
+ }
9211
+ unsubscribe(subscriptionId) {
9212
+ const subscription = this.requireSubscription(subscriptionId);
9213
+ this.clearWaiter(
9214
+ subscription,
9215
+ new RuntimeSubscriptionManagerError(
9216
+ "not_found",
9217
+ `Subscription "${subscriptionId}" was closed`
9218
+ )
9219
+ );
9220
+ this.subscriptions.delete(subscriptionId);
9221
+ return { ...subscription.descriptor };
9222
+ }
9223
+ async nextEvent(subscriptionId, timeoutMs) {
9224
+ const subscription = this.requireSubscription(subscriptionId);
9225
+ if (subscription.events.length > 0) {
9226
+ const event = subscription.events.shift() ?? null;
9227
+ subscription.descriptor.pendingEvents = subscription.events.length;
9228
+ return {
9229
+ subscriptionId,
9230
+ event,
9231
+ timedOut: false,
9232
+ pendingEvents: subscription.events.length
9233
+ };
9234
+ }
9235
+ if (timeoutMs <= 0) {
9236
+ return {
9237
+ subscriptionId,
9238
+ event: null,
9239
+ timedOut: true,
9240
+ pendingEvents: 0
9241
+ };
9242
+ }
9243
+ if (subscription.nextWaiter) {
9244
+ throw new RuntimeSubscriptionManagerError(
9245
+ "conflict",
9246
+ `Subscription "${subscriptionId}" already has a pending nextEvent request`
9247
+ );
9248
+ }
9249
+ return new Promise((resolve, reject) => {
9250
+ const timer = setTimeout(() => {
9251
+ subscription.nextWaiter = null;
9252
+ resolve({
9253
+ subscriptionId,
9254
+ event: null,
9255
+ timedOut: true,
9256
+ pendingEvents: subscription.events.length
9257
+ });
9258
+ }, timeoutMs);
9259
+ subscription.nextWaiter = {
9260
+ resolve: (result) => {
9261
+ clearTimeout(timer);
9262
+ subscription.nextWaiter = null;
9263
+ resolve(result);
9264
+ },
9265
+ reject: (error) => {
9266
+ clearTimeout(timer);
9267
+ subscription.nextWaiter = null;
9268
+ reject(error);
9269
+ },
9270
+ timer
9271
+ };
9272
+ });
9273
+ }
9274
+ pollEvents(subscriptionId, limit) {
9275
+ const subscription = this.requireSubscription(subscriptionId);
9276
+ const events = subscription.events.splice(0, limit);
9277
+ subscription.descriptor.pendingEvents = subscription.events.length;
9278
+ return {
9279
+ subscriptionId,
9280
+ events,
9281
+ pendingEvents: subscription.events.length
9282
+ };
9283
+ }
9284
+ reset() {
9285
+ for (const subscription of this.subscriptions.values()) {
9286
+ this.clearWaiter(
9287
+ subscription,
9288
+ new RuntimeSubscriptionManagerError(
9289
+ "not_found",
9290
+ `Subscription "${subscription.descriptor.subscriptionId}" was reset`
9291
+ )
9292
+ );
9293
+ subscription.events.length = 0;
9294
+ subscription.descriptor.pendingEvents = 0;
9295
+ }
9296
+ this.subscriptions.clear();
9297
+ }
9298
+ attach() {
9299
+ if (this.removeBrokerListener) {
9300
+ return;
9301
+ }
9302
+ Cadenza.bootstrap();
9303
+ this.removeBrokerListener = Cadenza.signalBroker.addPassiveSignalListener(
9304
+ (signal, context, metadata) => this.captureSignal(signal, context, metadata)
9305
+ );
9306
+ }
9307
+ captureSignal(signal, context, metadata) {
9308
+ if (this.subscriptions.size === 0) {
9309
+ return;
9310
+ }
9311
+ const normalizedContext = normalizeEventContext(context);
9312
+ const emission = isObject3(normalizedContext.__signalEmission) ? normalizedContext.__signalEmission : {};
9313
+ const metadataObject = isObject3(normalizedContext.__metadata) ? normalizedContext.__metadata : {};
9314
+ const fullSignal = signal;
9315
+ const [baseSignalName, ...signalTagParts] = signal.split(":");
9316
+ const signalName = baseSignalName ?? signal;
9317
+ const signalTag = signalTagParts.length > 0 ? signalTagParts.join(":") : null;
9318
+ const eventTemplate = {
9319
+ type: "signal",
9320
+ signal: fullSignal,
9321
+ signalName,
9322
+ signalTag,
9323
+ emittedAt: asStringOrNull(emission.emittedAt),
9324
+ isMeta: emission.isMeta === true || signalName.startsWith("meta."),
9325
+ isSubMeta: normalizedContext.__isSubMeta === true || signalName.startsWith("sub_meta."),
9326
+ metadata: sanitizeForJson(metadata) ?? null,
9327
+ source: {
9328
+ taskName: asStringOrNull(emission.taskName),
9329
+ taskVersion: asNumberOrNull(emission.taskVersion),
9330
+ taskExecutionId: asStringOrNull(emission.taskExecutionId),
9331
+ routineName: asStringOrNull(normalizedContext.__routineName) ?? asStringOrNull(emission.routineName),
9332
+ routineVersion: asNumberOrNull(normalizedContext.__routineVersion) ?? asNumberOrNull(emission.routineVersion),
9333
+ routineExecutionId: asStringOrNull(normalizedContext.__routineExecId) ?? asStringOrNull(emission.routineExecutionId),
9334
+ executionTraceId: asStringOrNull(emission.executionTraceId) ?? asStringOrNull(normalizedContext.__executionTraceId) ?? asStringOrNull(metadataObject.__executionTraceId),
9335
+ consumed: emission.consumed === true,
9336
+ consumedBy: asStringOrNull(emission.consumedBy)
9337
+ },
9338
+ context: normalizedContext
9339
+ };
9340
+ for (const subscription of this.subscriptions.values()) {
9341
+ if (!matchesSignalPattern(
9342
+ fullSignal,
9343
+ signalName,
9344
+ subscription.descriptor.signalPatterns
9345
+ )) {
9346
+ continue;
9347
+ }
9348
+ const event = {
9349
+ id: (0, import_uuid8.v4)(),
9350
+ subscriptionId: subscription.descriptor.subscriptionId,
9351
+ sequence: ++this.nextSequence,
9352
+ ...eventTemplate
9353
+ };
9354
+ if (subscription.nextWaiter) {
9355
+ subscription.nextWaiter.resolve({
9356
+ subscriptionId: subscription.descriptor.subscriptionId,
9357
+ event,
9358
+ timedOut: false,
9359
+ pendingEvents: subscription.events.length
9360
+ });
9361
+ continue;
9362
+ }
9363
+ subscription.events.push(event);
9364
+ if (subscription.events.length > subscription.descriptor.maxQueueSize) {
9365
+ subscription.events.shift();
9366
+ }
9367
+ subscription.descriptor.pendingEvents = subscription.events.length;
9368
+ }
9369
+ }
9370
+ clearWaiter(subscription, error) {
9371
+ if (!subscription.nextWaiter) {
9372
+ return;
9373
+ }
9374
+ if (subscription.nextWaiter.timer) {
9375
+ clearTimeout(subscription.nextWaiter.timer);
9376
+ }
9377
+ subscription.nextWaiter.reject(error);
9378
+ subscription.nextWaiter = null;
9379
+ }
9380
+ requireSubscription(subscriptionId) {
9381
+ const subscription = this.subscriptions.get(subscriptionId);
9382
+ if (!subscription) {
9383
+ throw new RuntimeSubscriptionManagerError(
9384
+ "not_found",
9385
+ `No subscription named "${subscriptionId}" exists`
9386
+ );
9387
+ }
9388
+ return subscription;
9389
+ }
9390
+ };
9391
+
9392
+ // src/runtime/RuntimeHost.ts
9393
+ var SUPPORTED_OPERATIONS = [
9394
+ "runtime.bootstrap",
9395
+ "runtime.info",
9396
+ "runtime.detach",
9397
+ "runtime.shutdown",
9398
+ "runtime.reset",
9399
+ "runtime.snapshot",
9400
+ "runtime.subscribe",
9401
+ "runtime.unsubscribe",
9402
+ "runtime.nextEvent",
9403
+ "runtime.pollEvents",
9404
+ "task.upsert",
9405
+ "helper.upsert",
9406
+ "global.upsert",
9407
+ "task.link",
9408
+ "task.observeSignal",
9409
+ "task.emitSignal",
9410
+ "task.respondToIntent",
9411
+ "task.useHelper",
9412
+ "task.useGlobal",
9413
+ "helper.useHelper",
9414
+ "helper.useGlobal",
9415
+ "routine.upsert",
9416
+ "routine.observeSignal",
9417
+ "intent.upsert",
9418
+ "actor.upsert",
9419
+ "actorTask.upsert",
9420
+ "run",
9421
+ "emit",
9422
+ "inquire"
9423
+ ];
9424
+ var RuntimeProtocolException = class extends Error {
9425
+ constructor(code, message, details) {
9426
+ super(message);
9427
+ this.code = code;
9428
+ this.details = details;
9429
+ this.name = "RuntimeProtocolException";
9430
+ }
9431
+ };
9432
+ function isObject4(value) {
9433
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9434
+ }
9435
+ function assertObject(value, message) {
9436
+ if (!isObject4(value)) {
9437
+ throw new RuntimeProtocolException("invalid_payload", message);
9438
+ }
9439
+ }
9440
+ function assertString(value, fieldName) {
9441
+ if (typeof value !== "string" || !value.trim()) {
9442
+ throw new RuntimeProtocolException(
9443
+ "invalid_payload",
9444
+ `${fieldName} must be a non-empty string`
9445
+ );
9446
+ }
9447
+ return value;
9448
+ }
9449
+ function assertStringArray(value, fieldName) {
9450
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
9451
+ throw new RuntimeProtocolException(
9452
+ "invalid_payload",
9453
+ `${fieldName} must be an array of strings`
9454
+ );
9455
+ }
9456
+ return value;
9457
+ }
9458
+ function normalizeSignalDefinition2(signal) {
9459
+ if (typeof signal === "string") {
9460
+ return signal;
9461
+ }
9462
+ if (isObject4(signal) && typeof signal.name === "string" && signal.name.trim().length > 0) {
9463
+ return {
9464
+ name: signal.name,
9465
+ deliveryMode: signal.deliveryMode === "single" || signal.deliveryMode === "broadcast" ? signal.deliveryMode : void 0,
9466
+ broadcastFilter: signal.broadcastFilter && isObject4(signal.broadcastFilter) ? signal.broadcastFilter : null
9467
+ };
9468
+ }
9469
+ throw new RuntimeProtocolException(
9470
+ "invalid_payload",
9471
+ "signal must be a signal string or structured signal definition"
9472
+ );
9473
+ }
9474
+ var RuntimeHost = class {
9475
+ constructor(options = {}) {
9476
+ this.pendingControlAction = null;
9477
+ this.subscriptionManager = new RuntimeSubscriptionManager();
9478
+ this.runtimeSharing = options.runtimeSharing ?? "isolated";
9479
+ this.runtimeName = options.runtimeName ?? null;
9480
+ this.sessionId = options.sessionId ?? null;
9481
+ this.sessionRole = options.sessionRole ?? null;
9482
+ this.activeSessionCountProvider = options.activeSessionCountProvider ?? (() => 1);
9483
+ this.daemonProcessId = options.daemonProcessId ?? null;
9484
+ this.onResetRuntime = options.onResetRuntime ?? null;
9485
+ }
9486
+ dispose() {
9487
+ this.subscriptionManager.dispose();
9488
+ }
9489
+ resetSubscriptions() {
9490
+ this.subscriptionManager.reset();
9491
+ }
9492
+ consumeControlAction() {
9493
+ const action = this.pendingControlAction;
9494
+ this.pendingControlAction = null;
9495
+ return action;
9496
+ }
9497
+ handshake() {
9498
+ return {
9499
+ ready: true,
9500
+ protocol: "cadenza-runtime-jsonl",
9501
+ protocolVersion: "1",
9502
+ runtimeMode: "core",
9503
+ runtimeSharing: this.runtimeSharing,
9504
+ runtimeName: this.runtimeName,
9505
+ sessionId: this.sessionId,
9506
+ sessionRole: this.sessionRole,
9507
+ supportedOperations: [...SUPPORTED_OPERATIONS]
9508
+ };
9509
+ }
9510
+ async handle(request) {
9511
+ try {
9512
+ if (!request || typeof request !== "object") {
9513
+ throw new RuntimeProtocolException(
9514
+ "invalid_request",
9515
+ "Request must be an object"
9516
+ );
9517
+ }
9518
+ if (typeof request.operation !== "string" || !SUPPORTED_OPERATIONS.includes(
9519
+ request.operation
9520
+ )) {
9521
+ throw new RuntimeProtocolException(
9522
+ "unsupported_operation",
9523
+ `Unsupported operation: ${String(request.operation ?? "")}`
9524
+ );
9525
+ }
9526
+ const operation = request.operation;
9527
+ this.assertOperationAllowed(operation);
9528
+ const result = await this.dispatch(operation, request.payload);
9529
+ return {
9530
+ id: request.id,
9531
+ operation,
9532
+ ok: true,
9533
+ result: sanitizeForJson(result)
9534
+ };
9535
+ } catch (error) {
9536
+ const normalizedError = this.normalizeError(error);
9537
+ return {
9538
+ id: request?.id,
9539
+ operation: typeof request?.operation === "string" ? request.operation : "runtime.snapshot",
9540
+ ok: false,
9541
+ error: normalizedError
9542
+ };
9543
+ }
9544
+ }
9545
+ normalizeError(error) {
9546
+ if (error instanceof RuntimeSubscriptionManagerError) {
9547
+ return {
9548
+ code: error.code,
9549
+ message: error.message
9550
+ };
9551
+ }
9552
+ if (error instanceof RuntimeProtocolException) {
9553
+ return {
9554
+ code: error.code,
9555
+ message: error.message,
9556
+ details: error.details ? sanitizeForJson(error.details) : void 0
9557
+ };
9558
+ }
9559
+ if (error instanceof Error) {
9560
+ return {
9561
+ code: "runtime_error",
9562
+ message: error.message
9563
+ };
9564
+ }
9565
+ return {
9566
+ code: "runtime_error",
9567
+ message: String(error)
9568
+ };
9569
+ }
9570
+ async dispatch(operation, payload) {
9571
+ switch (operation) {
9572
+ case "runtime.bootstrap":
9573
+ return this.bootstrapRuntime(payload);
9574
+ case "runtime.info":
9575
+ return this.runtimeInfo();
9576
+ case "runtime.detach":
9577
+ return this.detachRuntime();
9578
+ case "runtime.shutdown":
9579
+ return this.shutdownRuntime();
9580
+ case "runtime.reset":
9581
+ return this.resetRuntime();
9582
+ case "runtime.snapshot":
9583
+ return Cadenza.snapshotRuntime();
9584
+ case "runtime.subscribe":
9585
+ return this.subscribe(payload);
9586
+ case "runtime.unsubscribe":
9587
+ return this.unsubscribe(payload);
9588
+ case "runtime.nextEvent":
9589
+ return this.nextEvent(payload);
9590
+ case "runtime.pollEvents":
9591
+ return this.pollEvents(payload);
9592
+ case "task.upsert":
9593
+ return this.upsertTask(payload);
9594
+ case "helper.upsert":
9595
+ return this.upsertHelper(payload);
9596
+ case "global.upsert":
9597
+ return this.upsertGlobal(payload);
9598
+ case "task.link":
9599
+ return this.linkTasks(payload);
9600
+ case "task.observeSignal":
9601
+ return this.observeTaskSignal(payload);
9602
+ case "task.emitSignal":
9603
+ return this.emitTaskSignal(payload);
9604
+ case "task.respondToIntent":
9605
+ return this.bindTaskIntent(payload);
9606
+ case "task.useHelper":
9607
+ return this.bindTaskHelper(payload);
9608
+ case "task.useGlobal":
9609
+ return this.bindTaskGlobal(payload);
9610
+ case "helper.useHelper":
9611
+ return this.bindHelperHelper(payload);
9612
+ case "helper.useGlobal":
9613
+ return this.bindHelperGlobal(payload);
9614
+ case "routine.upsert":
9615
+ return this.upsertRoutine(payload);
9616
+ case "routine.observeSignal":
9617
+ return this.observeRoutineSignal(payload);
9618
+ case "intent.upsert":
9619
+ return this.upsertIntent(payload);
9620
+ case "actor.upsert":
9621
+ return this.upsertActor(payload);
9622
+ case "actorTask.upsert":
9623
+ return this.upsertActorTask(payload);
9624
+ case "run":
9625
+ return this.runTarget(payload);
9626
+ case "emit":
9627
+ return this.emitSignal(payload);
9628
+ case "inquire":
9629
+ return this.inquireIntent(payload);
9630
+ }
9631
+ }
9632
+ assertOperationAllowed(operation) {
9633
+ if (!this.sessionRole) {
9634
+ return;
9635
+ }
9636
+ if (this.sessionRole === "owner") {
9637
+ return;
9638
+ }
9639
+ if (this.sessionRole === "writer") {
9640
+ if (operation === "runtime.reset" || operation === "runtime.shutdown") {
9641
+ throw new RuntimeProtocolException(
9642
+ "forbidden",
9643
+ `Session role "${this.sessionRole}" cannot perform ${operation}`
9644
+ );
9645
+ }
9646
+ return;
9647
+ }
9648
+ const observerOperations = /* @__PURE__ */ new Set([
9649
+ "runtime.info",
9650
+ "runtime.detach",
9651
+ "runtime.snapshot",
9652
+ "runtime.subscribe",
9653
+ "runtime.unsubscribe",
9654
+ "runtime.nextEvent",
9655
+ "runtime.pollEvents",
9656
+ "inquire"
9657
+ ]);
9658
+ if (!observerOperations.has(operation)) {
9659
+ throw new RuntimeProtocolException(
9660
+ "forbidden",
9661
+ `Session role "${this.sessionRole}" cannot perform ${operation}`
9662
+ );
9663
+ }
9664
+ }
9665
+ bootstrapRuntime(payload) {
9666
+ const mode = isObject4(payload) && typeof payload.mode === "string" ? payload.mode : void 0;
9667
+ if (mode) {
9668
+ Cadenza.setMode(mode);
9669
+ } else {
9670
+ Cadenza.bootstrap();
9671
+ }
9672
+ return {
9673
+ bootstrapped: true,
9674
+ mode: Cadenza.mode
9675
+ };
9676
+ }
9677
+ runtimeInfo() {
9678
+ return {
9679
+ runtimeMode: "core",
9680
+ runtimeSharing: this.runtimeSharing,
9681
+ runtimeName: this.runtimeName,
9682
+ sessionId: this.sessionId,
9683
+ sessionRole: this.sessionRole,
9684
+ activeSessionCount: this.activeSessionCountProvider(),
9685
+ daemonProcessId: this.daemonProcessId,
9686
+ bootstrapped: Cadenza.isBootstrapped,
9687
+ mode: Cadenza.mode
9688
+ };
9689
+ }
9690
+ detachRuntime() {
9691
+ this.pendingControlAction = "detach";
9692
+ return {
9693
+ detached: true,
9694
+ runtimeName: this.runtimeName,
9695
+ sessionId: this.sessionId
9696
+ };
9697
+ }
9698
+ shutdownRuntime() {
9699
+ this.pendingControlAction = "shutdown";
9700
+ return {
9701
+ shutdown: true,
9702
+ runtimeName: this.runtimeName
9703
+ };
9704
+ }
9705
+ resetRuntime() {
9706
+ if (this.onResetRuntime) {
9707
+ this.onResetRuntime();
9708
+ } else {
9709
+ Cadenza.reset();
9710
+ this.subscriptionManager.reset();
9711
+ }
9712
+ return {
9713
+ reset: true,
9714
+ bootstrapped: false
9715
+ };
9716
+ }
9717
+ subscribe(payload) {
9718
+ assertObject(payload, "runtime.subscribe payload must be an object");
9719
+ const signalPatterns = this.parseSignalPatterns(payload.signalPatterns);
9720
+ const maxQueueSize = this.parsePositiveInteger(
9721
+ payload.maxQueueSize,
9722
+ "maxQueueSize",
9723
+ 100
9724
+ );
9725
+ return {
9726
+ subscription: this.subscriptionManager.subscribe(signalPatterns, maxQueueSize)
9727
+ };
9728
+ }
9729
+ unsubscribe(payload) {
9730
+ assertObject(payload, "runtime.unsubscribe payload must be an object");
9731
+ const subscriptionId = assertString(payload.subscriptionId, "subscriptionId");
9732
+ return {
9733
+ unsubscribed: true,
9734
+ subscription: this.subscriptionManager.unsubscribe(subscriptionId)
9735
+ };
9736
+ }
9737
+ async nextEvent(payload) {
9738
+ assertObject(payload, "runtime.nextEvent payload must be an object");
9739
+ const subscriptionId = assertString(payload.subscriptionId, "subscriptionId");
9740
+ const timeoutMs = this.parseNonNegativeInteger(
9741
+ payload.timeoutMs,
9742
+ "timeoutMs",
9743
+ 0
9744
+ );
9745
+ return this.subscriptionManager.nextEvent(subscriptionId, timeoutMs);
9746
+ }
9747
+ pollEvents(payload) {
9748
+ assertObject(payload, "runtime.pollEvents payload must be an object");
9749
+ const subscriptionId = assertString(payload.subscriptionId, "subscriptionId");
9750
+ const limit = this.parsePositiveInteger(payload.limit, "limit", 50);
9751
+ return this.subscriptionManager.pollEvents(subscriptionId, limit);
9752
+ }
9753
+ upsertTask(payload) {
9754
+ assertObject(payload, "task.upsert payload must be an object");
9755
+ const definition = payload;
9756
+ definition.name = assertString(definition.name, "name");
9757
+ definition.handlerSource = assertString(
9758
+ definition.handlerSource,
9759
+ "handlerSource"
9760
+ );
9761
+ definition.language = definition.language === "js" || definition.language === "ts" ? definition.language : (() => {
9762
+ throw new RuntimeProtocolException(
9763
+ "invalid_payload",
9764
+ "language must be 'js' or 'ts'"
9765
+ );
9766
+ })();
9767
+ definition.kind = definition.kind === "metaTask" ? "metaTask" : "task";
9768
+ runtimeDefinitionRegistry.setTaskDefinition(definition);
9769
+ const task = Cadenza.createTaskFromDefinition(definition);
9770
+ this.applyTaskDecorations(definition.name);
9771
+ this.applyAllTaskLinks();
9772
+ this.rematerializeRoutinesStartingWith(definition.name);
9773
+ return {
9774
+ task: this.snapshotTask(task)
9775
+ };
9776
+ }
9777
+ upsertHelper(payload) {
9778
+ assertObject(payload, "helper.upsert payload must be an object");
9779
+ const definition = payload;
9780
+ definition.name = assertString(definition.name, "name");
9781
+ definition.handlerSource = assertString(
9782
+ definition.handlerSource,
9783
+ "handlerSource"
9784
+ );
9785
+ definition.language = definition.language === "js" || definition.language === "ts" ? definition.language : (() => {
9786
+ throw new RuntimeProtocolException(
9787
+ "invalid_payload",
9788
+ "language must be 'js' or 'ts'"
9789
+ );
9790
+ })();
9791
+ definition.kind = definition.kind === "metaHelper" ? "metaHelper" : "helper";
9792
+ runtimeDefinitionRegistry.setHelperDefinition(definition);
9793
+ compileRuntimeHelperFunction(definition);
9794
+ Cadenza.createHelperFromDefinition(definition);
9795
+ this.applyHelperDecorations(definition.name);
9796
+ return {
9797
+ helper: this.snapshotHelper(definition.name)
9798
+ };
9799
+ }
9800
+ upsertGlobal(payload) {
9801
+ assertObject(payload, "global.upsert payload must be an object");
9802
+ const definition = {
9803
+ name: assertString(payload.name, "name"),
9804
+ description: typeof payload.description === "string" ? payload.description : "",
9805
+ kind: payload.kind === "metaGlobal" ? "metaGlobal" : "global",
9806
+ value: payload.value
9807
+ };
9808
+ runtimeDefinitionRegistry.setGlobalDefinition(definition);
9809
+ Cadenza.createGlobalFromDefinition(definition);
9810
+ return {
9811
+ global: this.snapshotGlobal(definition.name)
9812
+ };
9813
+ }
9814
+ linkTasks(payload) {
9815
+ assertObject(payload, "task.link payload must be an object");
9816
+ const definition = {
9817
+ predecessorTaskName: assertString(
9818
+ payload.predecessorTaskName,
9819
+ "predecessorTaskName"
9820
+ ),
9821
+ successorTaskName: assertString(
9822
+ payload.successorTaskName,
9823
+ "successorTaskName"
9824
+ )
9825
+ };
9826
+ runtimeDefinitionRegistry.setTaskLink(definition);
9827
+ this.applyAllTaskLinks();
9828
+ return {
9829
+ linked: true,
9830
+ ...definition
9831
+ };
9832
+ }
9833
+ observeTaskSignal(payload) {
9834
+ assertObject(payload, "task.observeSignal payload must be an object");
9835
+ const definition = {
9836
+ taskName: assertString(payload.taskName, "taskName"),
9837
+ signal: normalizeSignalDefinition2(payload.signal)
9838
+ };
9839
+ runtimeDefinitionRegistry.setTaskSignalObservation(definition);
9840
+ this.requireTask(definition.taskName).doOn(definition.signal);
9841
+ return {
9842
+ observed: true,
9843
+ taskName: definition.taskName,
9844
+ signal: typeof definition.signal === "string" ? definition.signal : definition.signal.name
9845
+ };
9846
+ }
9847
+ emitTaskSignal(payload) {
9848
+ assertObject(payload, "task.emitSignal payload must be an object");
9849
+ const mode = payload.mode === "attach" || payload.mode === "onFail" ? payload.mode : "after";
9850
+ const definition = {
9851
+ taskName: assertString(payload.taskName, "taskName"),
9852
+ signal: normalizeSignalDefinition2(payload.signal),
9853
+ mode
9854
+ };
9855
+ runtimeDefinitionRegistry.setTaskSignalEmission(definition);
9856
+ const task = this.requireTask(definition.taskName);
9857
+ if (definition.mode === "attach") {
9858
+ task.attachSignal(definition.signal);
9859
+ } else if (definition.mode === "onFail") {
9860
+ task.emitsOnFail(definition.signal);
9861
+ } else {
9862
+ task.emits(definition.signal);
9863
+ }
9864
+ return {
9865
+ attached: true,
9866
+ taskName: definition.taskName,
9867
+ mode: definition.mode,
9868
+ signal: typeof definition.signal === "string" ? definition.signal : definition.signal.name
9869
+ };
9870
+ }
9871
+ bindTaskIntent(payload) {
9872
+ assertObject(payload, "task.respondToIntent payload must be an object");
9873
+ const taskName = assertString(payload.taskName, "taskName");
9874
+ const intentName = assertString(payload.intentName, "intentName");
9875
+ runtimeDefinitionRegistry.setTaskIntentBinding({
9876
+ taskName,
9877
+ intentName
9878
+ });
9879
+ this.requireTask(taskName).respondsTo(intentName);
9880
+ return {
9881
+ bound: true,
9882
+ taskName,
9883
+ intentName
9884
+ };
9885
+ }
9886
+ bindTaskHelper(payload) {
9887
+ assertObject(payload, "task.useHelper payload must be an object");
9888
+ const definition = {
9889
+ taskName: assertString(payload.taskName, "taskName"),
9890
+ alias: assertString(payload.alias, "alias"),
9891
+ helperName: assertString(payload.helperName, "helperName")
9892
+ };
9893
+ runtimeDefinitionRegistry.setTaskHelperBinding(definition);
9894
+ this.requireTask(definition.taskName).usesHelpers({
9895
+ [definition.alias]: Cadenza.getHelper(definition.helperName)
9896
+ });
9897
+ return {
9898
+ bound: true,
9899
+ ...definition
9900
+ };
9901
+ }
9902
+ bindTaskGlobal(payload) {
9903
+ assertObject(payload, "task.useGlobal payload must be an object");
9904
+ const definition = {
9905
+ taskName: assertString(payload.taskName, "taskName"),
9906
+ alias: assertString(payload.alias, "alias"),
9907
+ globalName: assertString(payload.globalName, "globalName")
9908
+ };
9909
+ runtimeDefinitionRegistry.setTaskGlobalBinding(definition);
9910
+ this.requireTask(definition.taskName).usesGlobals({
9911
+ [definition.alias]: Cadenza.getGlobal(definition.globalName)
9912
+ });
9913
+ return {
9914
+ bound: true,
9915
+ ...definition
9916
+ };
9917
+ }
9918
+ bindHelperHelper(payload) {
9919
+ assertObject(payload, "helper.useHelper payload must be an object");
9920
+ const definition = {
9921
+ helperName: assertString(payload.helperName, "helperName"),
9922
+ alias: assertString(payload.alias, "alias"),
9923
+ dependencyHelperName: assertString(
9924
+ payload.dependencyHelperName,
9925
+ "dependencyHelperName"
9926
+ )
9927
+ };
9928
+ runtimeDefinitionRegistry.setHelperHelperBinding(definition);
9929
+ const helper = Cadenza.getHelper(definition.helperName);
9930
+ if (!helper) {
9931
+ throw new RuntimeProtocolException(
9932
+ "not_found",
9933
+ `No helper named "${definition.helperName}" exists`
9934
+ );
9935
+ }
9936
+ helper.usesHelpers({
9937
+ [definition.alias]: Cadenza.getHelper(definition.dependencyHelperName)
9938
+ });
9939
+ return {
9940
+ bound: true,
9941
+ ...definition
9942
+ };
9943
+ }
9944
+ bindHelperGlobal(payload) {
9945
+ assertObject(payload, "helper.useGlobal payload must be an object");
9946
+ const definition = {
9947
+ helperName: assertString(payload.helperName, "helperName"),
9948
+ alias: assertString(payload.alias, "alias"),
9949
+ globalName: assertString(payload.globalName, "globalName")
9950
+ };
9951
+ runtimeDefinitionRegistry.setHelperGlobalBinding(definition);
9952
+ const helper = Cadenza.getHelper(definition.helperName);
9953
+ if (!helper) {
9954
+ throw new RuntimeProtocolException(
9955
+ "not_found",
9956
+ `No helper named "${definition.helperName}" exists`
9957
+ );
9958
+ }
9959
+ helper.usesGlobals({
9960
+ [definition.alias]: Cadenza.getGlobal(definition.globalName)
9961
+ });
9962
+ return {
9963
+ bound: true,
9964
+ ...definition
9965
+ };
9966
+ }
9967
+ upsertRoutine(payload) {
9968
+ assertObject(payload, "routine.upsert payload must be an object");
9969
+ const definition = {
9970
+ name: assertString(payload.name, "name"),
9971
+ description: typeof payload.description === "string" ? payload.description : "",
9972
+ startTaskNames: assertStringArray(payload.startTaskNames, "startTaskNames"),
9973
+ isMeta: payload.isMeta === true
9974
+ };
9975
+ if (definition.startTaskNames.length === 0) {
9976
+ throw new RuntimeProtocolException(
9977
+ "invalid_payload",
9978
+ "startTaskNames must contain at least one task name"
9979
+ );
9980
+ }
9981
+ runtimeDefinitionRegistry.setRoutineDefinition(definition);
9982
+ const routine = Cadenza.createRoutineFromDefinition(definition);
9983
+ this.applyRoutineDecorations(definition.name);
9984
+ return {
9985
+ routine: this.snapshotRoutine(routine)
9986
+ };
9987
+ }
9988
+ observeRoutineSignal(payload) {
9989
+ assertObject(payload, "routine.observeSignal payload must be an object");
9990
+ const routineName = assertString(payload.routineName, "routineName");
9991
+ const signal = assertString(payload.signal, "signal");
9992
+ runtimeDefinitionRegistry.setRoutineSignalObservation({
9993
+ routineName,
9994
+ signal
9995
+ });
9996
+ this.requireRoutine(routineName).doOn(signal);
9997
+ return {
9998
+ observed: true,
9999
+ routineName,
10000
+ signal
10001
+ };
10002
+ }
10003
+ upsertIntent(payload) {
10004
+ assertObject(payload, "intent.upsert payload must be an object");
10005
+ const intent = {
10006
+ name: assertString(payload.name, "name"),
10007
+ description: typeof payload.description === "string" ? payload.description : "",
10008
+ input: isObject4(payload.input) ? payload.input : { type: "object" },
10009
+ output: isObject4(payload.output) ? payload.output : { type: "object" }
10010
+ };
10011
+ runtimeDefinitionRegistry.setIntentDefinition(intent);
10012
+ Cadenza.defineIntent(intent);
10013
+ return {
10014
+ intent: sanitizeForJson(intent)
10015
+ };
10016
+ }
10017
+ upsertActor(payload) {
10018
+ assertObject(payload, "actor.upsert payload must be an object");
10019
+ const definition = payload;
10020
+ definition.name = assertString(definition.name, "name");
10021
+ definition.description = assertString(definition.description, "description");
10022
+ definition.defaultKey = assertString(definition.defaultKey, "defaultKey");
10023
+ runtimeDefinitionRegistry.setActorDefinition(definition);
10024
+ const actor = Cadenza.createActorFromDefinition(definition);
10025
+ this.rematerializeActorTasksFor(definition.name);
10026
+ return {
10027
+ actor: sanitizeForJson({
10028
+ name: actor.spec.name,
10029
+ description: actor.spec.description ?? "",
10030
+ defaultKey: actor.spec.defaultKey
10031
+ })
10032
+ };
10033
+ }
10034
+ upsertActorTask(payload) {
10035
+ assertObject(payload, "actorTask.upsert payload must be an object");
10036
+ const definition = {
10037
+ actorName: assertString(payload.actorName, "actorName"),
10038
+ taskName: assertString(payload.taskName, "taskName"),
10039
+ description: typeof payload.description === "string" ? payload.description : "",
10040
+ mode: payload.mode === "write" || payload.mode === "meta" ? payload.mode : "read",
10041
+ handlerSource: assertString(payload.handlerSource, "handlerSource"),
10042
+ language: payload.language === "js" || payload.language === "ts" ? payload.language : (() => {
10043
+ throw new RuntimeProtocolException(
10044
+ "invalid_payload",
10045
+ "language must be 'js' or 'ts'"
10046
+ );
10047
+ })(),
10048
+ options: isObject4(payload.options) ? { ...payload.options } : void 0
10049
+ };
10050
+ runtimeDefinitionRegistry.setActorTaskDefinition(definition);
10051
+ const task = this.materializeActorTask(definition.taskName);
10052
+ this.applyTaskDecorations(definition.taskName);
10053
+ this.applyAllTaskLinks();
10054
+ this.rematerializeRoutinesStartingWith(definition.taskName);
10055
+ return {
10056
+ actorTask: this.snapshotTask(task)
10057
+ };
10058
+ }
10059
+ async runTarget(payload) {
10060
+ assertObject(payload, "run payload must be an object");
10061
+ const targetName = assertString(payload.targetName, "targetName");
10062
+ const context = isObject4(payload.context) ? payload.context : {};
10063
+ let target = Cadenza.getRoutine(targetName);
10064
+ if (!target) {
10065
+ const routineDefinition = runtimeDefinitionRegistry.routineDefinitions.get(targetName);
10066
+ if (routineDefinition) {
10067
+ target = Cadenza.createRoutineFromDefinition(routineDefinition);
10068
+ this.applyRoutineDecorations(targetName);
10069
+ }
10070
+ }
10071
+ target = target ?? Cadenza.get(targetName);
10072
+ if (!target) {
10073
+ throw new RuntimeProtocolException(
10074
+ "not_found",
10075
+ `No task or routine named "${targetName}" exists`
10076
+ );
10077
+ }
10078
+ const runner = "isMeta" in target && target.isMeta ? Cadenza.metaRunner : Cadenza.runner;
10079
+ const runResult = runner.run(target, context);
10080
+ const completedRun = await Promise.resolve(runResult);
10081
+ return {
10082
+ targetName,
10083
+ run: completedRun.export()
10084
+ };
10085
+ }
10086
+ emitSignal(payload) {
10087
+ assertObject(payload, "emit payload must be an object");
10088
+ const signal = assertString(payload.signal, "signal");
10089
+ const context = isObject4(payload.context) ? payload.context : {};
10090
+ const options = isObject4(payload.options) ? payload.options : {};
10091
+ Cadenza.emit(signal, context, options);
10092
+ return {
10093
+ emitted: true,
10094
+ signal
10095
+ };
10096
+ }
10097
+ async inquireIntent(payload) {
10098
+ assertObject(payload, "inquire payload must be an object");
10099
+ const inquiry = assertString(payload.intent, "intent");
10100
+ const context = isObject4(payload.context) ? payload.context : {};
10101
+ const options = isObject4(payload.options) ? payload.options : {};
10102
+ const response = await Cadenza.inquire(inquiry, context, options);
10103
+ return {
10104
+ inquiry,
10105
+ response
10106
+ };
10107
+ }
10108
+ requireTask(taskName) {
10109
+ const task = Cadenza.get(taskName);
10110
+ if (!task) {
10111
+ throw new RuntimeProtocolException(
10112
+ "not_found",
10113
+ `No task named "${taskName}" exists`
10114
+ );
10115
+ }
10116
+ return task;
10117
+ }
10118
+ requireRoutine(routineName) {
10119
+ const routine = Cadenza.getRoutine(routineName);
10120
+ if (!routine) {
10121
+ throw new RuntimeProtocolException(
10122
+ "not_found",
10123
+ `No routine named "${routineName}" exists`
10124
+ );
10125
+ }
10126
+ return routine;
10127
+ }
10128
+ applyTaskDecorations(taskName) {
10129
+ const task = this.requireTask(taskName);
10130
+ for (const observation of runtimeDefinitionRegistry.taskSignalObservations.values()) {
10131
+ if (observation.taskName !== taskName) {
10132
+ continue;
10133
+ }
10134
+ task.doOn(observation.signal);
10135
+ }
10136
+ for (const emission of runtimeDefinitionRegistry.taskSignalEmissions.values()) {
10137
+ if (emission.taskName !== taskName) {
10138
+ continue;
10139
+ }
10140
+ if (emission.mode === "attach") {
10141
+ task.attachSignal(emission.signal);
10142
+ } else if (emission.mode === "onFail") {
10143
+ task.emitsOnFail(emission.signal);
10144
+ } else {
10145
+ task.emits(emission.signal);
10146
+ }
10147
+ }
10148
+ for (const binding of runtimeDefinitionRegistry.taskIntentBindings.values()) {
10149
+ if (binding.taskName !== taskName) {
10150
+ continue;
10151
+ }
10152
+ task.respondsTo(binding.intentName);
10153
+ }
10154
+ for (const binding of runtimeDefinitionRegistry.taskHelperBindings.values()) {
10155
+ if (binding.taskName !== taskName) {
10156
+ continue;
10157
+ }
10158
+ task.usesHelpers({
10159
+ [binding.alias]: Cadenza.getHelper(binding.helperName)
10160
+ });
10161
+ }
10162
+ for (const binding of runtimeDefinitionRegistry.taskGlobalBindings.values()) {
10163
+ if (binding.taskName !== taskName) {
10164
+ continue;
10165
+ }
10166
+ task.usesGlobals({
10167
+ [binding.alias]: Cadenza.getGlobal(binding.globalName)
10168
+ });
10169
+ }
10170
+ }
10171
+ applyHelperDecorations(helperName) {
10172
+ const helper = Cadenza.getHelper(helperName);
10173
+ if (!helper) {
10174
+ throw new RuntimeProtocolException(
10175
+ "not_found",
10176
+ `No helper named "${helperName}" exists`
10177
+ );
10178
+ }
10179
+ for (const binding of runtimeDefinitionRegistry.helperHelperBindings.values()) {
10180
+ if (binding.helperName !== helperName) {
10181
+ continue;
10182
+ }
10183
+ helper.usesHelpers({
10184
+ [binding.alias]: Cadenza.getHelper(binding.dependencyHelperName)
10185
+ });
10186
+ }
10187
+ for (const binding of runtimeDefinitionRegistry.helperGlobalBindings.values()) {
10188
+ if (binding.helperName !== helperName) {
10189
+ continue;
10190
+ }
10191
+ helper.usesGlobals({
10192
+ [binding.alias]: Cadenza.getGlobal(binding.globalName)
10193
+ });
10194
+ }
10195
+ }
10196
+ applyAllTaskLinks() {
10197
+ for (const link of runtimeDefinitionRegistry.taskLinks.values()) {
10198
+ const predecessor = Cadenza.get(link.predecessorTaskName);
10199
+ const successor = Cadenza.get(link.successorTaskName);
10200
+ if (!predecessor || !successor) {
10201
+ continue;
10202
+ }
10203
+ predecessor.then(successor);
10204
+ }
10205
+ }
10206
+ applyRoutineDecorations(routineName) {
10207
+ const routine = this.requireRoutine(routineName);
10208
+ for (const observation of runtimeDefinitionRegistry.routineSignalObservations.values()) {
10209
+ if (observation.routineName !== routineName) {
10210
+ continue;
10211
+ }
10212
+ routine.doOn(observation.signal);
10213
+ }
10214
+ }
10215
+ rematerializeRoutinesStartingWith(taskName) {
10216
+ for (const definition of runtimeDefinitionRegistry.routineDefinitions.values()) {
10217
+ if (!definition.startTaskNames.includes(taskName)) {
10218
+ continue;
10219
+ }
10220
+ const recreated = Cadenza.createRoutineFromDefinition(definition);
10221
+ this.applyRoutineDecorations(recreated.name);
10222
+ }
10223
+ }
10224
+ rematerializeActorTasksFor(actorName) {
10225
+ for (const definition of runtimeDefinitionRegistry.actorTaskDefinitions.values()) {
10226
+ if (definition.actorName !== actorName) {
10227
+ continue;
10228
+ }
10229
+ this.materializeActorTask(definition.taskName);
10230
+ this.applyTaskDecorations(definition.taskName);
10231
+ this.applyAllTaskLinks();
10232
+ this.rematerializeRoutinesStartingWith(definition.taskName);
10233
+ }
10234
+ }
10235
+ materializeActorTask(taskName) {
10236
+ const definition = runtimeDefinitionRegistry.actorTaskDefinitions.get(taskName);
10237
+ if (!definition) {
10238
+ throw new RuntimeProtocolException(
10239
+ "not_found",
10240
+ `No actor task definition named "${taskName}" exists`
10241
+ );
10242
+ }
10243
+ const actor = Cadenza.getActor(definition.actorName);
10244
+ if (!actor) {
10245
+ throw new RuntimeProtocolException(
10246
+ "not_found",
10247
+ `No actor named "${definition.actorName}" exists`
10248
+ );
10249
+ }
10250
+ const existingTask = Cadenza.get(definition.taskName);
10251
+ if (existingTask && !runtimeDefinitionRegistry.isRuntimeOwnedTask(existingTask.name)) {
10252
+ throw new RuntimeProtocolException(
10253
+ "conflict",
10254
+ `Task "${definition.taskName}" already exists and is not runtime-owned`
10255
+ );
10256
+ }
10257
+ existingTask?.destroy();
10258
+ const handler = compileRuntimeActorTaskHandler(definition);
10259
+ return Cadenza.createTask(
10260
+ definition.taskName,
10261
+ actor.task(handler, { mode: definition.mode }),
10262
+ definition.description ?? "",
10263
+ definition.options ?? {}
10264
+ );
10265
+ }
10266
+ snapshotTask(task) {
10267
+ const snapshot = Cadenza.snapshotRuntime();
10268
+ const existing = snapshot.tasks.find((entry) => entry.name === task.name);
10269
+ if (existing) {
10270
+ return existing;
10271
+ }
10272
+ const runtimeTaskDefinition = runtimeDefinitionRegistry.taskDefinitions.get(
10273
+ task.name
10274
+ );
10275
+ const runtimeActorTaskDefinition = runtimeDefinitionRegistry.actorTaskDefinitions.get(task.name);
10276
+ return {
10277
+ name: task.name,
10278
+ version: task.version,
10279
+ description: task.description,
10280
+ kind: runtimeActorTaskDefinition ? "actorTask" : task.isMeta ? "metaTask" : "task",
10281
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedTask(task.name),
10282
+ language: runtimeTaskDefinition?.language ?? runtimeActorTaskDefinition?.language ?? null,
10283
+ handlerSource: runtimeTaskDefinition?.handlerSource ?? runtimeActorTaskDefinition?.handlerSource ?? null,
10284
+ tools: {
10285
+ helpers: Object.fromEntries(task.helperAliases),
10286
+ globals: Object.fromEntries(task.globalAliases)
10287
+ }
10288
+ };
10289
+ }
10290
+ snapshotHelper(helperName) {
10291
+ const snapshot = Cadenza.snapshotRuntime();
10292
+ return snapshot.helpers.find((entry) => entry.name === helperName) ?? {
10293
+ name: helperName
10294
+ };
10295
+ }
10296
+ snapshotGlobal(globalName) {
10297
+ const snapshot = Cadenza.snapshotRuntime();
10298
+ return snapshot.globals.find((entry) => entry.name === globalName) ?? {
10299
+ name: globalName
10300
+ };
10301
+ }
10302
+ snapshotRoutine(routine) {
10303
+ const snapshot = Cadenza.snapshotRuntime();
10304
+ return snapshot.routines.find((entry) => entry.name === routine.name) ?? {
10305
+ name: routine.name,
10306
+ version: routine.version,
10307
+ description: routine.description,
10308
+ isMeta: routine.isMeta,
10309
+ runtimeOwned: runtimeDefinitionRegistry.isRuntimeOwnedRoutine(
10310
+ routine.name
10311
+ ),
10312
+ startTaskNames: Array.from(routine.tasks).map((task) => task.name),
10313
+ observedSignals: Array.from(routine.observedSignals)
10314
+ };
10315
+ }
10316
+ parseSignalPatterns(value) {
10317
+ if (value === void 0) {
10318
+ return ["*"];
10319
+ }
10320
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string" || entry.trim().length === 0)) {
10321
+ throw new RuntimeProtocolException(
10322
+ "invalid_payload",
10323
+ "signalPatterns must be an array of non-empty strings"
10324
+ );
10325
+ }
10326
+ return Array.from(new Set(value.map((entry) => entry.trim())));
10327
+ }
10328
+ parsePositiveInteger(value, fieldName, fallback) {
10329
+ if (value === void 0) {
10330
+ return fallback;
10331
+ }
10332
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
10333
+ throw new RuntimeProtocolException(
10334
+ "invalid_payload",
10335
+ `${fieldName} must be a positive integer`
10336
+ );
10337
+ }
10338
+ return value;
10339
+ }
10340
+ parseNonNegativeInteger(value, fieldName, fallback) {
10341
+ if (value === void 0) {
10342
+ return fallback;
10343
+ }
10344
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
10345
+ throw new RuntimeProtocolException(
10346
+ "invalid_payload",
10347
+ `${fieldName} must be a non-negative integer`
10348
+ );
10349
+ }
10350
+ return value;
10351
+ }
10352
+ };
10353
+
8002
10354
  // src/index.ts
8003
10355
  var index_default = Cadenza;
8004
10356
  // Annotate the CommonJS export names for ESM import in node:
@@ -8006,13 +10358,16 @@ var index_default = Cadenza;
8006
10358
  Actor,
8007
10359
  DebounceTask,
8008
10360
  EphemeralTask,
10361
+ GlobalDefinition,
8009
10362
  GraphContext,
8010
10363
  GraphRegistry,
8011
10364
  GraphRoutine,
8012
10365
  GraphRun,
8013
10366
  GraphRunner,
10367
+ HelperDefinition,
8014
10368
  InquiryBroker,
8015
10369
  META_ACTOR_SESSION_STATE_PERSIST_INTENT,
10370
+ RuntimeHost,
8016
10371
  SignalBroker,
8017
10372
  SignalEmitter,
8018
10373
  Task,