@mojir/dvala 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/cli/cli.js +71 -23
  2. package/dist/cli/src/evaluator/effectTypes.d.ts +19 -1
  3. package/dist/cli/src/evaluator/suspension.d.ts +6 -0
  4. package/dist/cli/src/evaluator/trampoline.d.ts +5 -0
  5. package/dist/debug.esm.js +1 -1
  6. package/dist/debug.esm.js.map +1 -1
  7. package/dist/debug.js +1 -1
  8. package/dist/debug.js.map +1 -1
  9. package/dist/dvala.iife.js +1 -1
  10. package/dist/dvala.iife.js.map +1 -1
  11. package/dist/full.esm.js +1 -1
  12. package/dist/full.esm.js.map +1 -1
  13. package/dist/full.js +1 -1
  14. package/dist/full.js.map +1 -1
  15. package/dist/index.esm.js +1 -1
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/mcp-server/server.js +116 -69
  20. package/dist/mcp-server/src/evaluator/effectTypes.d.ts +19 -1
  21. package/dist/mcp-server/src/evaluator/suspension.d.ts +6 -0
  22. package/dist/mcp-server/src/evaluator/trampoline.d.ts +5 -0
  23. package/dist/modules/src/evaluator/effectTypes.d.ts +19 -1
  24. package/dist/modules/src/evaluator/suspension.d.ts +6 -0
  25. package/dist/modules/src/evaluator/trampoline.d.ts +5 -0
  26. package/dist/modules/src/index.d.ts +2 -0
  27. package/dist/modules/src/retrigger.d.ts +39 -0
  28. package/dist/src/evaluator/effectTypes.d.ts +19 -1
  29. package/dist/src/evaluator/suspension.d.ts +6 -0
  30. package/dist/src/evaluator/trampoline.d.ts +5 -0
  31. package/dist/src/index.d.ts +2 -0
  32. package/dist/src/retrigger.d.ts +39 -0
  33. package/dist/testFramework.esm.js +1 -1
  34. package/dist/testFramework.esm.js.map +1 -1
  35. package/dist/testFramework.js +1 -1
  36. package/dist/testFramework.js.map +1 -1
  37. package/package.json +1 -1
package/dist/cli/cli.js CHANGED
@@ -7,7 +7,7 @@ var readline = require('node:readline');
7
7
  var os = require('node:os');
8
8
  var process$1 = require('node:process');
9
9
 
10
- var version = "0.0.9";
10
+ var version = "0.0.10";
11
11
 
12
12
  function getCodeMarker(sourceCodeInfo) {
13
13
  if (!sourceCodeInfo.position || !sourceCodeInfo.code)
@@ -8708,6 +8708,8 @@ class SuspensionSignal {
8708
8708
  snapshots;
8709
8709
  nextSnapshotIndex;
8710
8710
  meta;
8711
+ effectName;
8712
+ effectArgs;
8711
8713
  _brand = 'SuspensionSignal';
8712
8714
  constructor(
8713
8715
  /** The captured continuation stack at the point of suspension. */
@@ -8717,11 +8719,17 @@ class SuspensionSignal {
8717
8719
  /** High-water mark for snapshot indices at the point of suspension. */
8718
8720
  nextSnapshotIndex,
8719
8721
  /** Optional domain metadata passed through to RunResult. */
8720
- meta) {
8722
+ meta,
8723
+ /** The effect name being handled when suspend() was called. */
8724
+ effectName,
8725
+ /** The effect arguments being handled when suspend() was called. */
8726
+ effectArgs) {
8721
8727
  this.k = k;
8722
8728
  this.snapshots = snapshots;
8723
8729
  this.nextSnapshotIndex = nextSnapshotIndex;
8724
8730
  this.meta = meta;
8731
+ this.effectName = effectName;
8732
+ this.effectArgs = effectArgs;
8725
8733
  }
8726
8734
  }
8727
8735
  function isSuspensionSignal(value) {
@@ -11897,6 +11905,12 @@ function dispatchPerform(effect, args, k, sourceCodeInfo, handlers, signal, snap
11897
11905
  function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sourceCodeInfo, snapshotState) {
11898
11906
  const effectSignal = signal ?? new AbortController().signal;
11899
11907
  const argsArray = Array.from(args);
11908
+ // If the abort signal already fired before the handler was called, auto-suspend immediately.
11909
+ // This happens when a parallel group aborts (e.g. another branch suspended) before this
11910
+ // branch's dispatchHostHandler runs.
11911
+ if (effectSignal.aborted) {
11912
+ throwSuspension(k, undefined, effectName, argsArray);
11913
+ }
11900
11914
  function resolveOutcome(o, nextIndex) {
11901
11915
  switch (o.kind) {
11902
11916
  case 'step': return o.step;
@@ -11912,9 +11926,20 @@ function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sour
11912
11926
  const message = typeof argsArray[0] === 'string' ? argsArray[0] : String(argsArray[0] ?? 'Unknown error');
11913
11927
  throw new UserDefinedError(message, sourceCodeInfo);
11914
11928
  }
11929
+ // dvala.checkpoint resolves to null when all handlers call next() without resuming.
11930
+ if (effectName === 'dvala.checkpoint') {
11931
+ return { type: 'Value', value: null, k };
11932
+ }
11915
11933
  throw new DvalaError(`Unhandled effect: '${effectName}'`, sourceCodeInfo);
11916
11934
  }
11917
- const [, handler] = matchingHandlers[index];
11935
+ const [pattern, handler] = matchingHandlers[index];
11936
+ // Before trying a "*" catch-all, fall back to standard effects.
11937
+ if (pattern === '*') {
11938
+ const standardHandler = getStandardEffectHandler(effectName);
11939
+ if (standardHandler) {
11940
+ return standardHandler(args, k, sourceCodeInfo);
11941
+ }
11942
+ }
11918
11943
  let outcome;
11919
11944
  let settled = false;
11920
11945
  function assertNotSettled(operation) {
@@ -11945,7 +11970,7 @@ function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sour
11945
11970
  assertNotSettled('suspend');
11946
11971
  outcome = {
11947
11972
  kind: 'throw',
11948
- error: new SuspensionSignal(k, snapshotState ? snapshotState.snapshots : [], snapshotState ? snapshotState.nextSnapshotIndex : 0, meta),
11973
+ error: new SuspensionSignal(k, snapshotState ? snapshotState.snapshots : [], snapshotState ? snapshotState.nextSnapshotIndex : 0, meta, effectName, argsArray),
11949
11974
  };
11950
11975
  },
11951
11976
  next: () => {
@@ -12032,9 +12057,20 @@ function dispatchHostHandler(effectName, matchingHandlers, args, k, signal, sour
12032
12057
  * Throw a SuspensionSignal. Factored out to a helper so ESLint's
12033
12058
  * `only-throw-literal` rule can be suppressed in one place.
12034
12059
  */
12035
- function throwSuspension(k, meta) {
12060
+ /** Combine two AbortSignals: aborts when either fires (or already aborted). */
12061
+ function combineSignals(a, b) {
12062
+ const controller = new AbortController();
12063
+ if (a.aborted || b.aborted) {
12064
+ controller.abort();
12065
+ return controller.signal;
12066
+ }
12067
+ a.addEventListener('abort', () => controller.abort(), { once: true });
12068
+ b.addEventListener('abort', () => controller.abort(), { once: true });
12069
+ return controller.signal;
12070
+ }
12071
+ function throwSuspension(k, meta, effectName, effectArgs) {
12036
12072
  // eslint-disable-next-line ts/no-throw-literal -- SuspensionSignal is a signaling mechanism, not an error
12037
- throw new SuspensionSignal(k, [], 0, meta);
12073
+ throw new SuspensionSignal(k, [], 0, meta, effectName, effectArgs);
12038
12074
  }
12039
12075
  /**
12040
12076
  * Run a single trampoline branch to completion with effect handler support.
@@ -12064,31 +12100,41 @@ async function runBranch(node, env, handlers, signal) {
12064
12100
  * but errors take priority)
12065
12101
  */
12066
12102
  async function executeParallelBranches(branches, env, k, handlers, signal) {
12067
- const effectSignal = signal ?? new AbortController().signal;
12068
- // Run all branches concurrently
12069
- const branchPromises = branches.map(branch => runBranch(branch, env, handlers, effectSignal));
12103
+ // AbortController for this parallel group — aborted when any branch suspends,
12104
+ // which signals remaining effect handlers to auto-suspend via ctx.signal.
12105
+ const parallelAbort = new AbortController();
12106
+ const effectSignal = signal
12107
+ ? combineSignals(signal, parallelAbort.signal)
12108
+ : parallelAbort.signal;
12109
+ // Run all branches concurrently; abort the group when a branch suspends
12110
+ const branchPromises = branches.map(async (branch, i) => {
12111
+ const result = await runBranch(branch, env, handlers, effectSignal);
12112
+ if (result.type === 'suspended') {
12113
+ parallelAbort.abort();
12114
+ }
12115
+ return { index: i, result };
12116
+ });
12070
12117
  const results = await Promise.allSettled(branchPromises);
12071
12118
  // Collect outcomes
12072
12119
  const completedBranches = [];
12073
12120
  const suspendedBranches = [];
12074
12121
  const errors = [];
12075
- for (let i = 0; i < results.length; i++) {
12076
- const result = results[i];
12077
- if (result.status === 'rejected') {
12078
- // runEffectLoop should never reject, but handle defensively
12079
- errors.push(new DvalaError(`${result.reason}`, undefined));
12122
+ for (const settled of results) {
12123
+ if (settled.status === 'rejected') {
12124
+ // branchPromises should never reject, but handle defensively
12125
+ errors.push(new DvalaError(`${settled.reason}`, undefined));
12080
12126
  }
12081
12127
  else {
12082
- const r = result.value;
12083
- switch (r.type) {
12128
+ const { index, result } = settled.value;
12129
+ switch (result.type) {
12084
12130
  case 'completed':
12085
- completedBranches.push({ index: i, value: r.value });
12131
+ completedBranches.push({ index, value: result.value });
12086
12132
  break;
12087
12133
  case 'suspended':
12088
- suspendedBranches.push({ index: i, snapshot: r.snapshot });
12134
+ suspendedBranches.push({ index, snapshot: result.snapshot });
12089
12135
  break;
12090
12136
  case 'error':
12091
- errors.push(r.error);
12137
+ errors.push(result.error);
12092
12138
  break;
12093
12139
  }
12094
12140
  }
@@ -12107,9 +12153,9 @@ async function executeParallelBranches(branches, env, k, handlers, signal) {
12107
12153
  suspendedBranches: suspendedBranches.slice(1), // remaining after the first
12108
12154
  };
12109
12155
  const resumeK = [parallelResumeFrame, ...k];
12110
- // Throw SuspensionSignal with the first suspended branch's meta
12156
+ // Throw SuspensionSignal with the first suspended branch's meta and effect info
12111
12157
  const firstSuspended = suspendedBranches[0];
12112
- return throwSuspension(resumeK, firstSuspended.snapshot.meta);
12158
+ return throwSuspension(resumeK, firstSuspended.snapshot.meta, firstSuspended.snapshot.effectName, firstSuspended.snapshot.effectArgs);
12113
12159
  }
12114
12160
  // All branches completed — build the result array in original order
12115
12161
  const resultArray = Array.from({ length: branches.length });
@@ -12262,7 +12308,7 @@ function handleParallelResume(step, _handlers, _signal) {
12262
12308
  suspendedBranches: remaining,
12263
12309
  };
12264
12310
  const resumeK = [parallelResumeFrame, ...k];
12265
- return throwSuspension(resumeK, nextSuspended.snapshot.meta);
12311
+ return throwSuspension(resumeK, nextSuspended.snapshot.meta, nextSuspended.snapshot.effectName, nextSuspended.snapshot.effectArgs);
12266
12312
  }
12267
12313
  // All branches now completed — build the result array in original order
12268
12314
  const resultArray = Array.from({ length: branchCount });
@@ -12725,6 +12771,8 @@ async function runEffectLoop(initial, handlers, signal, initialSnapshotState, ma
12725
12771
  index: snapshotState.nextSnapshotIndex++,
12726
12772
  runId: snapshotState.runId,
12727
12773
  meta: error.meta,
12774
+ effectName: error.effectName,
12775
+ effectArgs: error.effectArgs,
12728
12776
  };
12729
12777
  return { type: 'suspended', snapshot };
12730
12778
  }
@@ -35118,7 +35166,7 @@ function specialExpressionDocsToReference() {
35118
35166
  }
35119
35167
  const specialExpressionsReference = specialExpressionDocsToReference();
35120
35168
  function isFunctionReference(ref) {
35121
- return 'returns' in ref && 'args' in ref && 'variants' in ref;
35169
+ return 'returns' in ref && 'args' in ref && 'variants' in ref && !('effect' in ref);
35122
35170
  }
35123
35171
  const normalExpressionReference = {
35124
35172
  // Core categories — all derived from co-located docs
@@ -23,6 +23,16 @@ export interface Snapshot {
23
23
  readonly runId: string;
24
24
  /** Optional domain metadata from the perform call or suspend call. */
25
25
  readonly meta?: Any;
26
+ /**
27
+ * The name of the effect that was being handled when the program suspended.
28
+ * Undefined when suspension occurred outside of an effect handler (e.g. in parallel/race branches).
29
+ */
30
+ readonly effectName?: string;
31
+ /**
32
+ * The arguments passed to the suspended effect's perform call.
33
+ * Undefined when suspension occurred outside of an effect handler.
34
+ */
35
+ readonly effectArgs?: Any[];
26
36
  }
27
37
  /**
28
38
  * Generate a UUID for identifying a run() or resume() call.
@@ -144,6 +154,10 @@ export declare class SuspensionSignal {
144
154
  readonly nextSnapshotIndex: number;
145
155
  /** Optional domain metadata passed through to RunResult. */
146
156
  readonly meta?: Any | undefined;
157
+ /** The effect name being handled when suspend() was called. */
158
+ readonly effectName?: string | undefined;
159
+ /** The effect arguments being handled when suspend() was called. */
160
+ readonly effectArgs?: Any[] | undefined;
147
161
  readonly _brand: "SuspensionSignal";
148
162
  constructor(
149
163
  /** The captured continuation stack at the point of suspension. */
@@ -153,7 +167,11 @@ export declare class SuspensionSignal {
153
167
  /** High-water mark for snapshot indices at the point of suspension. */
154
168
  nextSnapshotIndex: number,
155
169
  /** Optional domain metadata passed through to RunResult. */
156
- meta?: Any | undefined);
170
+ meta?: Any | undefined,
171
+ /** The effect name being handled when suspend() was called. */
172
+ effectName?: string | undefined,
173
+ /** The effect arguments being handled when suspend() was called. */
174
+ effectArgs?: Any[] | undefined);
157
175
  }
158
176
  export declare function isSuspensionSignal(value: unknown): value is SuspensionSignal;
159
177
  /**
@@ -83,4 +83,10 @@ export declare function deserializeFromObject(blobData: unknown, options?: Deser
83
83
  snapshots: Snapshot[];
84
84
  nextSnapshotIndex: number;
85
85
  };
86
+ /**
87
+ * Extract checkpoint snapshots from a serialized continuation blob,
88
+ * expanding any pool references so each snapshot is a self-contained blob
89
+ * that can be passed directly to `resume()`.
90
+ */
91
+ export declare function extractCheckpointSnapshots(continuation: unknown): Snapshot[];
86
92
  export {};
@@ -131,3 +131,8 @@ export declare function resumeWithEffects(k: ContinuationStack, value: Any, hand
131
131
  nextSnapshotIndex: number;
132
132
  maxSnapshots?: number;
133
133
  }, deserializeOptions?: DeserializeOptions): Promise<RunResult>;
134
+ export declare function retriggerWithEffects(k: ContinuationStack, effectName: string, effectArgs: Any[], handlers?: Handlers, initialSnapshotState?: {
135
+ snapshots: Snapshot[];
136
+ nextSnapshotIndex: number;
137
+ maxSnapshots?: number;
138
+ }, deserializeOptions?: DeserializeOptions, outerSignal?: AbortSignal): Promise<RunResult>;