footprint-explainable-ui 0.22.0 → 0.24.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.d.cts CHANGED
@@ -868,6 +868,9 @@ declare const SubflowTree: react.NamedExoticComponent<SubflowTreeProps>;
868
868
  */
869
869
  interface RuntimeStageSnapshot {
870
870
  id: string;
871
+ /** `stageId#executionIndex` — the universal per-execution key. Joins this
872
+ * tree node to its commit-log bundles for cumulative-memory replay. */
873
+ runtimeStageId?: string;
871
874
  name?: string;
872
875
  isDecider?: boolean;
873
876
  isFork?: boolean;
@@ -898,6 +901,31 @@ interface RuntimeSnapshot {
898
901
  recorders?: RecorderSnapshot[];
899
902
  }
900
903
 
904
+ /**
905
+ * Deep-merges a net-change write PATCH into a base value for the
906
+ * cumulative-memory VIEW — the visualization-side mirror of footprintjs's
907
+ * `deepSmartMerge` (the `merge`-verb arm of `applySmartMerge`).
908
+ *
909
+ * Semantics:
910
+ * - plain objects: object-spread per level — patch keys win, base
911
+ * siblings survive (the gap this helper closes)
912
+ * - **arrays: REPLACE, not union-merge.** Deliberate divergence from
913
+ * footprintjs's `deepSmartMerge` (which unions non-empty arrays with
914
+ * reference-equality dedup). A memory VIEW should show the array a
915
+ * consumer would read at that moment: the dominant array-write path
916
+ * (TypedScope copy-on-write push / `$batchArray`) commits as a `set`
917
+ * of the full final array anyway, and union-replay of the rare
918
+ * `merge`-verb array delta can fabricate element mixes (reference
919
+ * dedup never dedupes deep-equal objects) that the display has no
920
+ * way to reconcile. Replace is predictable and loses nothing the
921
+ * patch didn't carry.
922
+ * - summary markers (`__writeSummary`/`__readSummary`): atomic — a marker
923
+ * patch replaces the key wholesale, and nothing merges INTO a marker
924
+ * - primitives / null / type mismatches: patch wins
925
+ *
926
+ * Pure: never mutates `base` or `patch`; merged branches are fresh objects.
927
+ */
928
+ declare function mergeWritePatch(base: unknown, patch: unknown): unknown;
901
929
  /**
902
930
  * Converts a FootPrint RuntimeSnapshot into a flat array of StageSnapshots
903
931
  * suitable for visualization components.
@@ -1066,4 +1094,4 @@ interface CompactTimelineProps {
1066
1094
  }
1067
1095
  declare const CompactTimeline: react.NamedExoticComponent<CompactTimelineProps>;
1068
1096
 
1069
- export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
1097
+ export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, mergeWritePatch, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
package/dist/index.d.ts CHANGED
@@ -868,6 +868,9 @@ declare const SubflowTree: react.NamedExoticComponent<SubflowTreeProps>;
868
868
  */
869
869
  interface RuntimeStageSnapshot {
870
870
  id: string;
871
+ /** `stageId#executionIndex` — the universal per-execution key. Joins this
872
+ * tree node to its commit-log bundles for cumulative-memory replay. */
873
+ runtimeStageId?: string;
871
874
  name?: string;
872
875
  isDecider?: boolean;
873
876
  isFork?: boolean;
@@ -898,6 +901,31 @@ interface RuntimeSnapshot {
898
901
  recorders?: RecorderSnapshot[];
899
902
  }
900
903
 
904
+ /**
905
+ * Deep-merges a net-change write PATCH into a base value for the
906
+ * cumulative-memory VIEW — the visualization-side mirror of footprintjs's
907
+ * `deepSmartMerge` (the `merge`-verb arm of `applySmartMerge`).
908
+ *
909
+ * Semantics:
910
+ * - plain objects: object-spread per level — patch keys win, base
911
+ * siblings survive (the gap this helper closes)
912
+ * - **arrays: REPLACE, not union-merge.** Deliberate divergence from
913
+ * footprintjs's `deepSmartMerge` (which unions non-empty arrays with
914
+ * reference-equality dedup). A memory VIEW should show the array a
915
+ * consumer would read at that moment: the dominant array-write path
916
+ * (TypedScope copy-on-write push / `$batchArray`) commits as a `set`
917
+ * of the full final array anyway, and union-replay of the rare
918
+ * `merge`-verb array delta can fabricate element mixes (reference
919
+ * dedup never dedupes deep-equal objects) that the display has no
920
+ * way to reconcile. Replace is predictable and loses nothing the
921
+ * patch didn't carry.
922
+ * - summary markers (`__writeSummary`/`__readSummary`): atomic — a marker
923
+ * patch replaces the key wholesale, and nothing merges INTO a marker
924
+ * - primitives / null / type mismatches: patch wins
925
+ *
926
+ * Pure: never mutates `base` or `patch`; merged branches are fresh objects.
927
+ */
928
+ declare function mergeWritePatch(base: unknown, patch: unknown): unknown;
901
929
  /**
902
930
  * Converts a FootPrint RuntimeSnapshot into a flat array of StageSnapshots
903
931
  * suitable for visualization components.
@@ -1066,4 +1094,4 @@ interface CompactTimelineProps {
1066
1094
  }
1067
1095
  declare const CompactTimeline: react.NamedExoticComponent<CompactTimelineProps>;
1068
1096
 
1069
- export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
1097
+ export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, mergeWritePatch, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
package/dist/index.js CHANGED
@@ -2286,11 +2286,103 @@ function extractSubflowNarrative(entries, subflowId, subflowName) {
2286
2286
  }
2287
2287
 
2288
2288
  // src/adapters/fromRuntimeSnapshot.ts
2289
+ var COMMIT_PATH_DELIM = "";
2290
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
2291
+ function isSummaryMarker(value) {
2292
+ return value !== null && typeof value === "object" && (value.__writeSummary === true || value.__readSummary === true);
2293
+ }
2294
+ function isPlainRecord(value) {
2295
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2296
+ }
2297
+ function mergeWritePatch(base, patch) {
2298
+ if (isSummaryMarker(patch)) return patch;
2299
+ if (patch === null || typeof patch !== "object") return patch;
2300
+ if (Array.isArray(patch)) return patch;
2301
+ if (isSummaryMarker(base) || !isPlainRecord(base)) {
2302
+ base = {};
2303
+ }
2304
+ const out = { ...base };
2305
+ for (const [key, value] of Object.entries(patch)) {
2306
+ if (UNSAFE_KEYS.has(key)) continue;
2307
+ out[key] = mergeWritePatch(out[key], value);
2308
+ }
2309
+ return out;
2310
+ }
2311
+ function getPath(root, segs) {
2312
+ let cur = root;
2313
+ for (const seg of segs) {
2314
+ if (!isPlainRecord(cur) && !Array.isArray(cur)) return void 0;
2315
+ cur = cur[seg];
2316
+ }
2317
+ return cur;
2318
+ }
2319
+ function setPath(memory, segs, value) {
2320
+ if (segs.some((s) => UNSAFE_KEYS.has(s))) return;
2321
+ let obj = memory;
2322
+ for (let i = 0; i < segs.length - 1; i++) {
2323
+ const cur = obj[segs[i]];
2324
+ const next = Array.isArray(cur) ? cur.slice() : isPlainRecord(cur) && !isSummaryMarker(cur) ? { ...cur } : {};
2325
+ obj[segs[i]] = next;
2326
+ obj = next;
2327
+ }
2328
+ const last = segs[segs.length - 1];
2329
+ if (value === void 0) {
2330
+ delete obj[last];
2331
+ } else {
2332
+ obj[last] = value;
2333
+ }
2334
+ }
2335
+ function applyCommitBundle(memory, bundle) {
2336
+ const trace = Array.isArray(bundle.trace) ? bundle.trace : void 0;
2337
+ if (trace) {
2338
+ for (const op of trace) {
2339
+ if (!op || typeof op.path !== "string") continue;
2340
+ const segs = op.path.split(COMMIT_PATH_DELIM);
2341
+ if (op.verb === "merge") {
2342
+ setPath(memory, segs, mergeWritePatch(getPath(memory, segs), getPath(bundle.updates, segs)));
2343
+ } else if (op.verb === "append") {
2344
+ const tail = getPath(bundle.overwrite, segs);
2345
+ const current = getPath(memory, segs);
2346
+ setPath(memory, segs, Array.isArray(current) && Array.isArray(tail) ? [...current, ...tail] : tail);
2347
+ } else if (op.verb === "delete") {
2348
+ setPath(memory, segs, void 0);
2349
+ } else {
2350
+ setPath(memory, segs, getPath(bundle.overwrite, segs));
2351
+ }
2352
+ }
2353
+ return;
2354
+ }
2355
+ if (isPlainRecord(bundle.overwrite)) {
2356
+ for (const [key, value] of Object.entries(bundle.overwrite)) setPath(memory, [key], value);
2357
+ }
2358
+ if (isPlainRecord(bundle.updates)) {
2359
+ for (const [key, value] of Object.entries(bundle.updates)) {
2360
+ setPath(memory, [key], mergeWritePatch(memory[key], value));
2361
+ }
2362
+ }
2363
+ }
2364
+ function indexCommitLog(commitLog) {
2365
+ const index = /* @__PURE__ */ new Map();
2366
+ if (!Array.isArray(commitLog)) return index;
2367
+ for (const entry of commitLog) {
2368
+ if (!isPlainRecord(entry)) continue;
2369
+ const bundle = entry;
2370
+ if (typeof bundle.runtimeStageId !== "string" || bundle.runtimeStageId.length === 0) continue;
2371
+ if (!isPlainRecord(bundle.overwrite) && !isPlainRecord(bundle.updates) && !Array.isArray(bundle.trace)) {
2372
+ continue;
2373
+ }
2374
+ const list = index.get(bundle.runtimeStageId);
2375
+ if (list) list.push(bundle);
2376
+ else index.set(bundle.runtimeStageId, [bundle]);
2377
+ }
2378
+ return index;
2379
+ }
2289
2380
  function toVisualizationSnapshots(runtime, narrativeEntries) {
2290
2381
  const stageNarrativeMap = narrativeEntries?.length ? buildStageNarrativeMap(narrativeEntries) : /* @__PURE__ */ new Map();
2291
2382
  const stageTimings = extractStageTimings(runtime.recorders);
2383
+ const commitIndex = indexCommitLog(runtime.commitLog);
2292
2384
  const snapshots = [];
2293
- flattenTree(runtime.executionTree, snapshots, runtime.sharedState, 0, runtime.subflowResults, {}, stageNarrativeMap, stageTimings);
2385
+ flattenTree(runtime.executionTree, snapshots, runtime.sharedState, 0, runtime.subflowResults, {}, stageNarrativeMap, stageTimings, commitIndex);
2294
2386
  return snapshots;
2295
2387
  }
2296
2388
  function extractStageTimings(recorders) {
@@ -2334,7 +2426,7 @@ function buildStageNarrativeMap(entries) {
2334
2426
  }
2335
2427
  return map;
2336
2428
  }
2337
- function flattenTree(node, out, sharedState, accumulatedMs = 0, subflowResults, cumulativeMemory = {}, stageNarrativeMap = /* @__PURE__ */ new Map(), stageTimings = /* @__PURE__ */ new Map()) {
2429
+ function flattenTree(node, out, sharedState, accumulatedMs = 0, subflowResults, cumulativeMemory = {}, stageNarrativeMap = /* @__PURE__ */ new Map(), stageTimings = /* @__PURE__ */ new Map(), commitIndex = /* @__PURE__ */ new Map()) {
2338
2430
  const stageName = node.name ?? node.id;
2339
2431
  const durationMs = (stageName ? stageTimings.get(stageName) : void 0) ?? (typeof node.metrics?.durationMs === "number" ? node.metrics.durationMs : 0);
2340
2432
  const startMs = accumulatedMs;
@@ -2354,12 +2446,16 @@ function flattenTree(node, out, sharedState, accumulatedMs = 0, subflowResults,
2354
2446
  narrative = parts.join("\n");
2355
2447
  }
2356
2448
  const memory = { ...cumulativeMemory };
2357
- if (node.stageWrites) {
2449
+ const bundles = node.runtimeStageId ? commitIndex.get(node.runtimeStageId) : void 0;
2450
+ if (bundles && bundles.length > 0) {
2451
+ for (const bundle of bundles) applyCommitBundle(memory, bundle);
2452
+ } else if (node.stageWrites) {
2358
2453
  for (const [key, value] of Object.entries(node.stageWrites)) {
2454
+ if (UNSAFE_KEYS.has(key)) continue;
2359
2455
  if (value === void 0) {
2360
2456
  delete memory[key];
2361
2457
  } else {
2362
- memory[key] = value;
2458
+ memory[key] = mergeWritePatch(memory[key], value);
2363
2459
  }
2364
2460
  }
2365
2461
  }
@@ -2381,13 +2477,13 @@ function flattenTree(node, out, sharedState, accumulatedMs = 0, subflowResults,
2381
2477
  if (node.children && node.children.length > 0) {
2382
2478
  let maxChildEnd = nextMs;
2383
2479
  for (const child of node.children) {
2384
- const childEnd = flattenTree(child, out, sharedState, nextMs, subflowResults, memory, stageNarrativeMap, stageTimings);
2480
+ const childEnd = flattenTree(child, out, sharedState, nextMs, subflowResults, memory, stageNarrativeMap, stageTimings, commitIndex);
2385
2481
  maxChildEnd = Math.max(maxChildEnd, childEnd);
2386
2482
  }
2387
2483
  nextMs = maxChildEnd;
2388
2484
  }
2389
2485
  if (node.next) {
2390
- nextMs = flattenTree(node.next, out, sharedState, nextMs, subflowResults, memory, stageNarrativeMap, stageTimings);
2486
+ nextMs = flattenTree(node.next, out, sharedState, nextMs, subflowResults, memory, stageNarrativeMap, stageTimings, commitIndex);
2391
2487
  }
2392
2488
  return nextMs;
2393
2489
  }
@@ -6233,6 +6329,7 @@ export {
6233
6329
  createSnapshots,
6234
6330
  defaultTokens,
6235
6331
  extractSubflowNarrative,
6332
+ mergeWritePatch,
6236
6333
  rawDefaults,
6237
6334
  subflowResultToSnapshots,
6238
6335
  themePresets,