footprintjs 4.0.1 → 4.0.3

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 (42) hide show
  1. package/dist/advanced.js +1 -1
  2. package/dist/esm/advanced.js +1 -1
  3. package/dist/esm/lib/builder/FlowChartBuilder.js +2 -2
  4. package/dist/esm/lib/builder/types.js +1 -1
  5. package/dist/esm/lib/engine/graph/StageNode.js +1 -1
  6. package/dist/esm/lib/engine/handlers/RuntimeStructureManager.js +7 -3
  7. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +11 -29
  8. package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +2 -3
  9. package/dist/esm/lib/engine/types.js +1 -1
  10. package/dist/esm/lib/reactive/createTypedScope.js +11 -1
  11. package/dist/esm/lib/reactive/types.js +2 -1
  12. package/dist/esm/lib/runner/ExecutionRuntime.js +1 -29
  13. package/dist/esm/lib/runner/FlowChartExecutor.js +1 -1
  14. package/dist/esm/lib/runner/getSubtreeSnapshot.js +9 -2
  15. package/dist/esm/lib/runner/index.js +1 -1
  16. package/dist/lib/builder/FlowChartBuilder.js +2 -2
  17. package/dist/lib/builder/types.js +1 -1
  18. package/dist/lib/engine/graph/StageNode.js +1 -1
  19. package/dist/lib/engine/handlers/RuntimeStructureManager.js +7 -3
  20. package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +11 -29
  21. package/dist/lib/engine/traversal/FlowchartTraverser.js +2 -3
  22. package/dist/lib/engine/types.js +1 -1
  23. package/dist/lib/reactive/createTypedScope.js +11 -1
  24. package/dist/lib/reactive/types.js +2 -1
  25. package/dist/lib/runner/ExecutionRuntime.js +1 -29
  26. package/dist/lib/runner/FlowChartExecutor.js +1 -1
  27. package/dist/lib/runner/getSubtreeSnapshot.js +9 -2
  28. package/dist/lib/runner/index.js +1 -1
  29. package/dist/types/advanced.d.ts +1 -1
  30. package/dist/types/lib/builder/types.d.ts +6 -2
  31. package/dist/types/lib/engine/graph/StageNode.d.ts +5 -1
  32. package/dist/types/lib/engine/handlers/RuntimeStructureManager.d.ts +1 -1
  33. package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +6 -8
  34. package/dist/types/lib/engine/types.d.ts +1 -1
  35. package/dist/types/lib/reactive/types.d.ts +23 -0
  36. package/dist/types/lib/runner/ExecutionRuntime.d.ts +1 -10
  37. package/dist/types/lib/runner/FlowChartExecutor.d.ts +7 -1
  38. package/dist/types/lib/runner/index.d.ts +1 -1
  39. package/package.json +1 -1
  40. package/dist/esm/lib/engine/narrative/CombinedNarrativeBuilder.js +0 -2
  41. package/dist/lib/engine/narrative/CombinedNarrativeBuilder.js +0 -3
  42. package/dist/types/lib/engine/narrative/CombinedNarrativeBuilder.d.ts +0 -5
@@ -10,4 +10,4 @@ Object.defineProperty(exports, "getSubtreeSnapshot", { enumerable: true, get: fu
10
10
  Object.defineProperty(exports, "listSubflowPaths", { enumerable: true, get: function () { return getSubtreeSnapshot_js_1.listSubflowPaths; } });
11
11
  var RunContext_js_1 = require("./RunContext.js");
12
12
  Object.defineProperty(exports, "RunContext", { enumerable: true, get: function () { return RunContext_js_1.RunContext; } });
13
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3J1bm5lci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSw2REFBeUQ7QUFBaEQsdUhBQUEsZ0JBQWdCLE9BQUE7QUFFekIsK0RBQTJEO0FBQWxELHlIQUFBLGlCQUFpQixPQUFBO0FBRTFCLGlFQUErRTtBQUF0RSwySEFBQSxrQkFBa0IsT0FBQTtBQUFFLHlIQUFBLGdCQUFnQixPQUFBO0FBRTdDLGlEQUE2QztBQUFwQywyR0FBQSxVQUFVLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBpc3RhbmJ1bCBpZ25vcmUgZmlsZSAqL1xuZXhwb3J0IHR5cGUgeyBDb21wb3NhYmxlUnVubmVyIH0gZnJvbSAnLi9Db21wb3NhYmxlUnVubmVyLmpzJztcbmV4cG9ydCB0eXBlIHsgTmFycmF0aXZlRW50cnksIFJlY29yZGVyU25hcHNob3QsIFJ1bnRpbWVTbmFwc2hvdCB9IGZyb20gJy4vRXhlY3V0aW9uUnVudGltZS5qcyc7XG5leHBvcnQgeyBFeGVjdXRpb25SdW50aW1lIH0gZnJvbSAnLi9FeGVjdXRpb25SdW50aW1lLmpzJztcbmV4cG9ydCB0eXBlIHsgRmxvd0NoYXJ0RXhlY3V0b3JPcHRpb25zIH0gZnJvbSAnLi9GbG93Q2hhcnRFeGVjdXRvci5qcyc7XG5leHBvcnQgeyBGbG93Q2hhcnRFeGVjdXRvciB9IGZyb20gJy4vRmxvd0NoYXJ0RXhlY3V0b3IuanMnO1xuZXhwb3J0IHR5cGUgeyBTdWJ0cmVlU25hcHNob3QgfSBmcm9tICcuL2dldFN1YnRyZWVTbmFwc2hvdC5qcyc7XG5leHBvcnQgeyBnZXRTdWJ0cmVlU25hcHNob3QsIGxpc3RTdWJmbG93UGF0aHMgfSBmcm9tICcuL2dldFN1YnRyZWVTbmFwc2hvdC5qcyc7XG5leHBvcnQgdHlwZSB7IFJ1blJlc3VsdCB9IGZyb20gJy4vUnVuQ29udGV4dC5qcyc7XG5leHBvcnQgeyBSdW5Db250ZXh0IH0gZnJvbSAnLi9SdW5Db250ZXh0LmpzJztcbmV4cG9ydCB0eXBlIHsgUnVubmFibGVGbG93Q2hhcnQgfSBmcm9tICcuL1J1bm5hYmxlQ2hhcnQuanMnO1xuIl19
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3J1bm5lci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSw2REFBeUQ7QUFBaEQsdUhBQUEsZ0JBQWdCLE9BQUE7QUFFekIsK0RBQTJEO0FBQWxELHlIQUFBLGlCQUFpQixPQUFBO0FBRTFCLGlFQUErRTtBQUF0RSwySEFBQSxrQkFBa0IsT0FBQTtBQUFFLHlIQUFBLGdCQUFnQixPQUFBO0FBRTdDLGlEQUE2QztBQUFwQywyR0FBQSxVQUFVLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBpc3RhbmJ1bCBpZ25vcmUgZmlsZSAqL1xuZXhwb3J0IHR5cGUgeyBDb21wb3NhYmxlUnVubmVyIH0gZnJvbSAnLi9Db21wb3NhYmxlUnVubmVyLmpzJztcbmV4cG9ydCB0eXBlIHsgUmVjb3JkZXJTbmFwc2hvdCwgUnVudGltZVNuYXBzaG90IH0gZnJvbSAnLi9FeGVjdXRpb25SdW50aW1lLmpzJztcbmV4cG9ydCB7IEV4ZWN1dGlvblJ1bnRpbWUgfSBmcm9tICcuL0V4ZWN1dGlvblJ1bnRpbWUuanMnO1xuZXhwb3J0IHR5cGUgeyBGbG93Q2hhcnRFeGVjdXRvck9wdGlvbnMgfSBmcm9tICcuL0Zsb3dDaGFydEV4ZWN1dG9yLmpzJztcbmV4cG9ydCB7IEZsb3dDaGFydEV4ZWN1dG9yIH0gZnJvbSAnLi9GbG93Q2hhcnRFeGVjdXRvci5qcyc7XG5leHBvcnQgdHlwZSB7IFN1YnRyZWVTbmFwc2hvdCB9IGZyb20gJy4vZ2V0U3VidHJlZVNuYXBzaG90LmpzJztcbmV4cG9ydCB7IGdldFN1YnRyZWVTbmFwc2hvdCwgbGlzdFN1YmZsb3dQYXRocyB9IGZyb20gJy4vZ2V0U3VidHJlZVNuYXBzaG90LmpzJztcbmV4cG9ydCB0eXBlIHsgUnVuUmVzdWx0IH0gZnJvbSAnLi9SdW5Db250ZXh0LmpzJztcbmV4cG9ydCB7IFJ1bkNvbnRleHQgfSBmcm9tICcuL1J1bkNvbnRleHQuanMnO1xuZXhwb3J0IHR5cGUgeyBSdW5uYWJsZUZsb3dDaGFydCB9IGZyb20gJy4vUnVubmFibGVDaGFydC5qcyc7XG4iXX0=
@@ -34,7 +34,7 @@ export { createErrorMessage, createProtectedScope, ScopeFacade } from './lib/sco
34
34
  export { attachScopeMethods, isSubclassOfScopeFacade, looksLikeClassCtor, looksLikeFactory, makeClassProvider, makeFactoryProvider, registerScopeResolver, resolveScopeProvider, toScopeFactory, } from './lib/scope/index.js';
35
35
  export type { AggregatedMetrics, DebugEntry, DebugRecorderOptions, DebugVerbosity, DefineScopeOptions, RecorderContext, StageEvent, StageMetrics, } from './lib/scope/index.js';
36
36
  export { createScopeProxyFromZod, defineScopeSchema, isScopeSchema, ZodScopeResolver } from './lib/scope/index.js';
37
- export type { NarrativeEntry, RuntimeSnapshot } from './lib/runner/index.js';
37
+ export type { RuntimeSnapshot } from './lib/runner/index.js';
38
38
  export { ExecutionRuntime } from './lib/runner/index.js';
39
39
  export type { ReactiveOptions, ReactiveTarget } from './lib/reactive/index.js';
40
40
  export { BREAK_SETTER, buildNestedPatch, createArrayProxy, joinPath, SCOPE_METHOD_NAMES, shouldWrapWithProxy, } from './lib/reactive/index.js';
@@ -19,7 +19,7 @@ export type { ScopeProtectionMode };
19
19
  export interface SerializedPipelineStructure {
20
20
  name: string;
21
21
  id: string;
22
- type: 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow';
22
+ type: 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow' | 'loop';
23
23
  /** Semantic icon hint for visualization (e.g., "llm", "tool", "rag", "agent", "start") */
24
24
  icon?: string;
25
25
  description?: string;
@@ -47,12 +47,14 @@ export interface SerializedPipelineStructure {
47
47
  iterationCount?: number;
48
48
  /** True when this subflow uses lazy resolution (deferred until execution). */
49
49
  isLazy?: boolean;
50
+ /** True when this node is a back-edge reference created by loopTo() — not an executable stage. */
51
+ isLoopReference?: boolean;
50
52
  }
51
53
  export interface FlowChartSpec {
52
54
  name: string;
53
55
  id: string;
54
56
  /** Node type — matches `SerializedPipelineStructure.type` for visualization alignment. */
55
- type?: 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow';
57
+ type?: 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow' | 'loop';
56
58
  /** Semantic icon hint for visualization (e.g., "llm", "tool", "rag", "agent", "start") */
57
59
  icon?: string;
58
60
  description?: string;
@@ -69,6 +71,8 @@ export interface FlowChartSpec {
69
71
  isSubflowRoot?: boolean;
70
72
  subflowId?: string;
71
73
  subflowName?: string;
74
+ /** True when this node is a back-edge reference created by loopTo() — not an executable stage. */
75
+ isLoopReference?: boolean;
72
76
  }
73
77
  /** Metadata provided to the build-time extractor for each node. */
74
78
  export type BuildTimeNodeMetadata = FlowChartSpec;
@@ -55,7 +55,11 @@ export type StageNode<TOut = any, TScope = any> = {
55
55
  subflowMountOptions?: SubflowMountOptions;
56
56
  /** When true, parallel children use fail-fast semantics (reject on first error) */
57
57
  failFast?: boolean;
58
- /** True if this node is a back-edge reference created by loopTo() */
58
+ /**
59
+ * True if this node is a back-edge reference created by loopTo() — not an executable stage.
60
+ * Serialization equivalent: `SerializedPipelineStructure.isLoopReference` (different name
61
+ * to distinguish runtime graph field from the JSON-safe spec field).
62
+ */
59
63
  isLoopRef?: boolean;
60
64
  /** Inline subflow definition for dynamic subflow attachment.
61
65
  * When `root` is omitted, the subflow is structural-only:
@@ -13,7 +13,7 @@ import type { SerializedPipelineStructure } from '../types.js';
13
13
  * Compute the node type from node properties.
14
14
  * Shared by RuntimeStructureManager (serialization) and ExtractorRunner (metadata).
15
15
  */
16
- export declare function computeNodeType(node: StageNode): 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow';
16
+ export declare function computeNodeType(node: StageNode): 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow' | 'loop';
17
17
  export declare class RuntimeStructureManager {
18
18
  private runtimePipelineStructure?;
19
19
  private structureNodeMap;
@@ -24,16 +24,14 @@ export declare class CombinedNarrativeRecorder implements FlowRecorder, Recorder
24
24
  readonly id: string;
25
25
  private entries;
26
26
  /**
27
- * Pending scope ops keyed by stageId (stable identifier). Populated at buffer time
28
- * using the stageName→stageId mapping; falls back to stageName when stageId is unknown.
29
- * Keying by stageId prevents ops from merging when two stages share the same name.
27
+ * Pending scope ops keyed by stageName. Flushed in onStageExecuted/onDecision.
28
+ *
29
+ * Name collisions (two stages with the same name, different IDs) are prevented by
30
+ * the event ordering contract: scope events (onRead/onWrite) for stage N are always
31
+ * flushed by onStageExecuted for stage N before stage N+1's scope events begin.
32
+ * So the key is always uniquely bound to the currently-executing stage.
30
33
  */
31
34
  private pendingOps;
32
- /**
33
- * Maps stageName → stageId as we learn them from onStageExecuted/onDecision.
34
- * Allows bufferOp() to use stageId as the key while scope events only carry stageName.
35
- */
36
- private stageNameToId;
37
35
  /** Per-subflow stage counters. Key '' = root flow. */
38
36
  private stageCounters;
39
37
  /** Per-subflow first-stage flags. Key '' = root flow. */
@@ -154,7 +154,7 @@ export interface RunOptions {
154
154
  }
155
155
  export type { FlowControlType, FlowMessage };
156
156
  export interface RuntimeStructureMetadata {
157
- type: 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow';
157
+ type: 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow' | 'loop';
158
158
  subflowId?: string;
159
159
  isSubflowRoot?: boolean;
160
160
  subflowName?: string;
@@ -46,6 +46,29 @@ export interface ScopeMethods {
46
46
  $attachRecorder(recorder: Recorder): void;
47
47
  $detachRecorder(recorderId: string): void;
48
48
  $getRecorders(): Recorder[];
49
+ /**
50
+ * Batch-mutate an array key in a single clone+write cycle.
51
+ *
52
+ * Every `scope.items.push(x)` clones the entire array and commits it — O(N) per call.
53
+ * For N mutations on an M-length array that is O(N×M). Use `$batchArray` to clone once,
54
+ * apply all mutations inside `fn`, then commit once — O(M) total.
55
+ *
56
+ * ```typescript
57
+ * // Before: 1000 clones × growing array = O(N²)
58
+ * for (let i = 0; i < 1000; i++) scope.items.push(i);
59
+ *
60
+ * // After: 1 clone + 1 commit = O(N)
61
+ * scope.$batchArray('items', (arr) => {
62
+ * for (let i = 0; i < 1000; i++) arr.push(i);
63
+ * });
64
+ * ```
65
+ *
66
+ * `fn` receives a plain (non-proxy) mutable copy of the current array. Mutations
67
+ * inside `fn` are NOT tracked individually — only the final committed array appears
68
+ * in the narrative as a single write. If the key does not exist or is not an array,
69
+ * `fn` receives an empty array and the result is committed as the new value.
70
+ */
71
+ $batchArray(key: string, fn: (arr: unknown[]) => void): void;
49
72
  $break(): void;
50
73
  $toRaw(): ReactiveTarget;
51
74
  }
@@ -12,14 +12,7 @@
12
12
  import { EventLog } from '../memory/EventLog.js';
13
13
  import { SharedMemory } from '../memory/SharedMemory.js';
14
14
  import { StageContext } from '../memory/StageContext.js';
15
- import type { CommitBundle, FlowMessage, StageSnapshot } from '../memory/types.js';
16
- export interface NarrativeEntry {
17
- stageId: string;
18
- stageName: string;
19
- stageMessages: string[];
20
- flowMessage?: FlowMessage;
21
- timeIndex: number;
22
- }
15
+ import type { CommitBundle, StageSnapshot } from '../memory/types.js';
23
16
  /** Snapshot of a single recorder's collected data. */
24
17
  export interface RecorderSnapshot {
25
18
  id: string;
@@ -43,6 +36,4 @@ export declare class ExecutionRuntime {
43
36
  getPipelines(): string[];
44
37
  setRootObject(path: string[], key: string, value: unknown): void;
45
38
  getSnapshot(): RuntimeSnapshot;
46
- getFullNarrative(): NarrativeEntry[];
47
- private walkContextTree;
48
39
  }
@@ -45,7 +45,13 @@ import { type RuntimeSnapshot } from './ExecutionRuntime.js';
45
45
  export interface FlowChartExecutorOptions<TScope = any> {
46
46
  /** Custom scope factory. Defaults to TypedScope or ScopeFacade auto-detection. */
47
47
  scopeFactory?: ScopeFactory<TScope>;
48
- /** Whether to enrich snapshots with scope state (enables `getSnapshot()`). */
48
+ /**
49
+ * Attach a per-stage scope snapshot to each extractor result. When `true`, the
50
+ * extraction callback receives the full shared state at the point that stage
51
+ * committed — useful for debugging multi-stage state transitions. Defaults to
52
+ * `false` (no scope snapshot attached). Can also be set on the chart via
53
+ * `flowChart(...).enrichSnapshots(true)`.
54
+ */
49
55
  enrichSnapshots?: boolean;
50
56
  /**
51
57
  * Default values pre-populated into the shared context before **each** stage
@@ -1,5 +1,5 @@
1
1
  export type { ComposableRunner } from './ComposableRunner.js';
2
- export type { NarrativeEntry, RecorderSnapshot, RuntimeSnapshot } from './ExecutionRuntime.js';
2
+ export type { RecorderSnapshot, RuntimeSnapshot } from './ExecutionRuntime.js';
3
3
  export { ExecutionRuntime } from './ExecutionRuntime.js';
4
4
  export type { FlowChartExecutorOptions } from './FlowChartExecutor.js';
5
5
  export { FlowChartExecutor } from './FlowChartExecutor.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "footprintjs",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "description": "Explainable backend flows — automatic causal traces, decision evidence, and MCP tool generation for AI agents",
5
5
  "license": "MIT",
6
6
  "author": "Sanjay Krishna Anbalagan",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29tYmluZWROYXJyYXRpdmVCdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9lbmdpbmUvbmFycmF0aXZlL0NvbWJpbmVkTmFycmF0aXZlQnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAZGVwcmVjYXRlZCBVc2UgYG5hcnJhdGl2ZVR5cGVzLnRzYCBpbnN0ZWFkLiBUaGlzIGZpbGUgaXMga2VwdCBmb3IgaW50ZXJuYWxcbiAqIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiBhIGZ1dHVyZSB2ZXJzaW9uLlxuICovXG5leHBvcnQgdHlwZSB7IENvbWJpbmVkTmFycmF0aXZlRW50cnksIENvbWJpbmVkTmFycmF0aXZlT3B0aW9ucyB9IGZyb20gJy4vbmFycmF0aXZlVHlwZXMuanMnO1xuIl19
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29tYmluZWROYXJyYXRpdmVCdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9lbmdpbmUvbmFycmF0aXZlL0NvbWJpbmVkTmFycmF0aXZlQnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAZGVwcmVjYXRlZCBVc2UgYG5hcnJhdGl2ZVR5cGVzLnRzYCBpbnN0ZWFkLiBUaGlzIGZpbGUgaXMga2VwdCBmb3IgaW50ZXJuYWxcbiAqIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiBhIGZ1dHVyZSB2ZXJzaW9uLlxuICovXG5leHBvcnQgdHlwZSB7IENvbWJpbmVkTmFycmF0aXZlRW50cnksIENvbWJpbmVkTmFycmF0aXZlT3B0aW9ucyB9IGZyb20gJy4vbmFycmF0aXZlVHlwZXMuanMnO1xuIl19
@@ -1,5 +0,0 @@
1
- /**
2
- * @deprecated Use `narrativeTypes.ts` instead. This file is kept for internal
3
- * backward compatibility and will be removed in a future version.
4
- */
5
- export type { CombinedNarrativeEntry, CombinedNarrativeOptions } from './narrativeTypes.js';