footprint-explainable-ui 0.18.0 → 0.19.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.
Files changed (90) hide show
  1. package/dist/adapters/fromRuntimeSnapshot.d.ts +33 -4
  2. package/dist/adapters/fromRuntimeSnapshot.d.ts.map +1 -1
  3. package/dist/adapters/fromRuntimeSnapshot.js +162 -33
  4. package/dist/adapters/fromRuntimeSnapshot.js.map +1 -1
  5. package/dist/components/ExplainableShell/ExplainableShell.d.ts +157 -14
  6. package/dist/components/ExplainableShell/ExplainableShell.d.ts.map +1 -1
  7. package/dist/components/ExplainableShell/ExplainableShell.js +676 -68
  8. package/dist/components/ExplainableShell/ExplainableShell.js.map +1 -1
  9. package/dist/components/ExplainableShell/index.d.ts +1 -1
  10. package/dist/components/ExplainableShell/index.d.ts.map +1 -1
  11. package/dist/components/FlowchartView/SubflowTree.d.ts +7 -14
  12. package/dist/components/FlowchartView/SubflowTree.d.ts.map +1 -1
  13. package/dist/components/FlowchartView/SubflowTree.js +56 -46
  14. package/dist/components/FlowchartView/SubflowTree.js.map +1 -1
  15. package/dist/components/FlowchartView/index.d.ts +32 -4
  16. package/dist/components/FlowchartView/index.d.ts.map +1 -1
  17. package/dist/components/FlowchartView/index.js +22 -2
  18. package/dist/components/FlowchartView/index.js.map +1 -1
  19. package/dist/components/FlowchartView/useSubflowNavigation.d.ts +41 -16
  20. package/dist/components/FlowchartView/useSubflowNavigation.d.ts.map +1 -1
  21. package/dist/components/FlowchartView/useSubflowNavigation.js +69 -50
  22. package/dist/components/FlowchartView/useSubflowNavigation.js.map +1 -1
  23. package/dist/components/GanttTimeline/GanttTimeline.d.ts.map +1 -1
  24. package/dist/components/GanttTimeline/GanttTimeline.js +5 -5
  25. package/dist/components/GanttTimeline/GanttTimeline.js.map +1 -1
  26. package/dist/components/MemoryInspector/MemoryInspector.d.ts.map +1 -1
  27. package/dist/components/MemoryInspector/MemoryInspector.js +36 -13
  28. package/dist/components/MemoryInspector/MemoryInspector.js.map +1 -1
  29. package/dist/components/NarrativeTrace/NarrativeTrace.d.ts.map +1 -1
  30. package/dist/components/NarrativeTrace/NarrativeTrace.js +24 -17
  31. package/dist/components/NarrativeTrace/NarrativeTrace.js.map +1 -1
  32. package/dist/components/ScopeDiff/ScopeDiff.js +3 -3
  33. package/dist/components/ScopeDiff/ScopeDiff.js.map +1 -1
  34. package/dist/components/StageNode/StageNode.d.ts +21 -0
  35. package/dist/components/StageNode/StageNode.d.ts.map +1 -1
  36. package/dist/components/StageNode/StageNode.js +189 -9
  37. package/dist/components/StageNode/StageNode.js.map +1 -1
  38. package/dist/components/TimeTravelControls/TimeTravelControls.d.ts.map +1 -1
  39. package/dist/components/TimeTravelControls/TimeTravelControls.js +19 -3
  40. package/dist/components/TimeTravelControls/TimeTravelControls.js.map +1 -1
  41. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.d.ts +19 -8
  42. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.d.ts.map +1 -1
  43. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.js +23 -8
  44. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.js.map +1 -1
  45. package/dist/flowchart.cjs +3485 -1340
  46. package/dist/flowchart.cjs.map +1 -1
  47. package/dist/flowchart.d.cts +1616 -177
  48. package/dist/flowchart.d.ts +1616 -177
  49. package/dist/flowchart.d.ts.map +1 -1
  50. package/dist/flowchart.js +3507 -1384
  51. package/dist/flowchart.js.map +1 -1
  52. package/dist/index.cjs +749 -557
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +276 -29
  55. package/dist/index.d.ts +276 -29
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +742 -547
  58. package/dist/index.js.map +1 -1
  59. package/dist/theme/ThemeProvider.d.ts +14 -0
  60. package/dist/theme/ThemeProvider.d.ts.map +1 -1
  61. package/dist/theme/ThemeProvider.js +15 -1
  62. package/dist/theme/ThemeProvider.js.map +1 -1
  63. package/dist/theme/index.d.ts +4 -2
  64. package/dist/theme/index.d.ts.map +1 -1
  65. package/dist/theme/index.js +3 -2
  66. package/dist/theme/index.js.map +1 -1
  67. package/dist/theme/presets.d.ts +3 -0
  68. package/dist/theme/presets.d.ts.map +1 -1
  69. package/dist/theme/presets.js +22 -0
  70. package/dist/theme/presets.js.map +1 -1
  71. package/dist/theme/tokens.d.ts +22 -1
  72. package/dist/theme/tokens.d.ts.map +1 -1
  73. package/dist/theme/tokens.js +23 -2
  74. package/dist/theme/tokens.js.map +1 -1
  75. package/dist/tsconfig.tsbuildinfo +1 -1
  76. package/dist/types.d.ts +25 -0
  77. package/dist/types.d.ts.map +1 -1
  78. package/package.json +4 -4
  79. package/dist/components/FlowchartView/FlowchartView.d.ts +0 -20
  80. package/dist/components/FlowchartView/FlowchartView.d.ts.map +0 -1
  81. package/dist/components/FlowchartView/FlowchartView.js +0 -80
  82. package/dist/components/FlowchartView/FlowchartView.js.map +0 -1
  83. package/dist/components/FlowchartView/TracedFlowchartView.d.ts +0 -20
  84. package/dist/components/FlowchartView/TracedFlowchartView.d.ts.map +0 -1
  85. package/dist/components/FlowchartView/TracedFlowchartView.js +0 -101
  86. package/dist/components/FlowchartView/TracedFlowchartView.js.map +0 -1
  87. package/dist/components/FlowchartView/specToReactFlow.d.ts +0 -56
  88. package/dist/components/FlowchartView/specToReactFlow.d.ts.map +0 -1
  89. package/dist/components/FlowchartView/specToReactFlow.js +0 -202
  90. package/dist/components/FlowchartView/specToReactFlow.js.map +0 -1
package/dist/index.js CHANGED
@@ -72,7 +72,14 @@ function useFootprintTheme() {
72
72
  }
73
73
  function FootprintTheme({ tokens = {}, children }) {
74
74
  const cssVars = tokensToCSSVars(tokens);
75
- return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: tokens, children: /* @__PURE__ */ jsx("div", { style: cssVars, className: "fp-theme-root", children }) });
75
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: tokens, children: /* @__PURE__ */ jsx(
76
+ "div",
77
+ {
78
+ style: { ...cssVars, display: "contents" },
79
+ className: "fp-theme-root",
80
+ children
81
+ }
82
+ ) });
76
83
  }
77
84
 
78
85
  // src/theme/styles.ts
@@ -2201,7 +2208,7 @@ function TimeTravelControls({
2201
2208
  }
2202
2209
 
2203
2210
  // src/components/ExplainableShell/ExplainableShell.tsx
2204
- import { memo as memo8, useState as useState12, useCallback as useCallback7, useMemo as useMemo12, useRef as useRef7, useEffect as useEffect8 } from "react";
2211
+ import { memo as memo8, useState as useState14, useCallback as useCallback9, useMemo as useMemo13, useRef as useRef9, useEffect as useEffect9 } from "react";
2205
2212
 
2206
2213
  // src/utils/narrativeSync.ts
2207
2214
  function buildEntryRangeIndex(entries) {
@@ -2703,7 +2710,6 @@ function NarrativePanel({
2703
2710
  snapshots,
2704
2711
  selectedIndex,
2705
2712
  narrativeEntries,
2706
- narrative: narrativeProp,
2707
2713
  runtimeSnapshot,
2708
2714
  spec,
2709
2715
  size = "default",
@@ -2714,14 +2720,13 @@ function NarrativePanel({
2714
2720
  const fs = fontSize[size];
2715
2721
  const pad = padding[size];
2716
2722
  const narrative = useMemo8(() => {
2717
- if (narrativeProp && narrativeProp.length > 0) return narrativeProp;
2718
2723
  const lines = [];
2719
2724
  for (const snap of snapshots) {
2720
2725
  const stageLines = (snap.narrative ?? "").split("\n").filter(Boolean);
2721
2726
  lines.push(...stageLines);
2722
2727
  }
2723
2728
  return lines;
2724
- }, [narrativeProp, snapshots]);
2729
+ }, [snapshots]);
2725
2730
  const revealedCount = useMemo8(() => {
2726
2731
  if (snapshots.length === 0 || narrative.length === 0) return narrative.length;
2727
2732
  const stageBoundaries = [];
@@ -2945,35 +2950,19 @@ function NarrativePanel({
2945
2950
  // src/components/FlowchartView/SubflowTree.tsx
2946
2951
  import { memo, useState as useState8, useCallback as useCallback5, useMemo as useMemo9 } from "react";
2947
2952
  import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
2948
- function specToTree(node) {
2949
- if (!node) return [];
2953
+ function graphToSubflowEntries(graph) {
2954
+ if (!graph?.nodes?.length) return [];
2950
2955
  const entries = [];
2951
- const seen = /* @__PURE__ */ new Set();
2952
- function walk(n) {
2953
- if (!n) return;
2954
- const id = n.name || n.id || "";
2955
- if (seen.has(id)) return;
2956
- seen.add(id);
2956
+ for (const node of graph.nodes) {
2957
+ if (!node.data?.isSubflow) continue;
2957
2958
  const entry = {
2958
- name: n.name,
2959
- description: n.description,
2960
- subflowId: n.subflowId,
2961
- isSubflow: !!n.isSubflowRoot
2959
+ name: typeof node.data.label === "string" ? node.data.label : node.id,
2960
+ isSubflow: true
2962
2961
  };
2963
- if (n.isSubflowRoot && n.subflowStructure) {
2964
- entry.children = specToTree(n.subflowStructure);
2965
- }
2962
+ if (typeof node.data.description === "string") entry.description = node.data.description;
2963
+ if (typeof node.data.subflowId === "string") entry.subflowId = node.data.subflowId;
2966
2964
  entries.push(entry);
2967
- if (n.children) {
2968
- for (const child of n.children) {
2969
- if (child) walk(child);
2970
- }
2971
- }
2972
- if (n.next) {
2973
- walk(n.next);
2974
- }
2975
2965
  }
2976
- walk(node);
2977
2966
  return entries;
2978
2967
  }
2979
2968
  var TreeNode = memo(function TreeNode2({
@@ -3117,7 +3106,7 @@ var SectionLabel = memo(function SectionLabel2({ children }) {
3117
3106
  );
3118
3107
  });
3119
3108
  var SubflowTree = memo(function SubflowTree2({
3120
- spec,
3109
+ graph,
3121
3110
  activeStage,
3122
3111
  doneStages,
3123
3112
  onNodeSelect,
@@ -3125,8 +3114,7 @@ var SubflowTree = memo(function SubflowTree2({
3125
3114
  className,
3126
3115
  style
3127
3116
  }) {
3128
- const tree = useMemo9(() => specToTree(spec), [spec]);
3129
- const subflowStages = useMemo9(() => tree.filter((e) => e.isSubflow), [tree]);
3117
+ const subflowStages = useMemo9(() => graphToSubflowEntries(graph), [graph]);
3130
3118
  if (subflowStages.length === 0) return null;
3131
3119
  return /* @__PURE__ */ jsxs13(
3132
3120
  "div",
@@ -3246,15 +3234,22 @@ var SubflowBreadcrumb = memo2(function SubflowBreadcrumb2({
3246
3234
  );
3247
3235
  });
3248
3236
 
3249
- // src/components/FlowchartView/TracedFlowchartView.tsx
3250
- import { useMemo as useMemo10, useCallback as useCallback6, useEffect as useEffect7 } from "react";
3237
+ // src/components/FlowchartView/TracedFlow.tsx
3238
+ import { useCallback as useCallback8, useMemo as useMemo11, useRef as useRef8, useState as useState10 } from "react";
3239
+ import {
3240
+ ReactFlow as ReactFlow2,
3241
+ Background as Background2,
3242
+ BackgroundVariant as BackgroundVariant2,
3243
+ MarkerType as MarkerType2
3244
+ } from "@xyflow/react";
3245
+
3246
+ // src/components/FlowchartView/TraceFlow.tsx
3247
+ import { useMemo as useMemo10, useCallback as useCallback6, useSyncExternalStore } from "react";
3251
3248
  import {
3252
3249
  ReactFlow,
3253
3250
  Background,
3254
3251
  BackgroundVariant,
3255
- useReactFlow,
3256
- useNodesState,
3257
- useEdgesState
3252
+ MarkerType
3258
3253
  } from "@xyflow/react";
3259
3254
 
3260
3255
  // src/components/StageNode/StageNode.tsx
@@ -3410,7 +3405,7 @@ function StageIcon({ type, color }) {
3410
3405
  var StageNode = memo3(function StageNode2({
3411
3406
  data
3412
3407
  }) {
3413
- const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description } = data;
3408
+ const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description, stageId, showStageId } = data;
3414
3409
  const effectiveIcon = icon || (isLazy ? "lazy" : void 0);
3415
3410
  const isLazyUnresolved = isLazy && !done && !active;
3416
3411
  const injectedRef = useRef6(false);
@@ -3584,6 +3579,23 @@ var StageNode = memo3(function StageNode2({
3584
3579
  },
3585
3580
  children: description
3586
3581
  }
3582
+ ),
3583
+ showStageId && stageId && /* @__PURE__ */ jsx16(
3584
+ "span",
3585
+ {
3586
+ style: {
3587
+ fontSize: 8,
3588
+ fontFamily: "ui-monospace, monospace",
3589
+ color: textColor,
3590
+ opacity: 0.55,
3591
+ whiteSpace: "nowrap",
3592
+ overflow: "hidden",
3593
+ textOverflow: "ellipsis",
3594
+ maxWidth: 100
3595
+ },
3596
+ title: `stageId: ${stageId}`,
3597
+ children: stageId
3598
+ }
3587
3599
  )
3588
3600
  ]
3589
3601
  }
@@ -3682,6 +3694,23 @@ var StageNode = memo3(function StageNode2({
3682
3694
  },
3683
3695
  children: description
3684
3696
  }
3697
+ ),
3698
+ showStageId && stageId && /* @__PURE__ */ jsx16(
3699
+ "span",
3700
+ {
3701
+ style: {
3702
+ fontSize: 9,
3703
+ fontFamily: "ui-monospace, monospace",
3704
+ color: textColor,
3705
+ opacity: 0.55,
3706
+ whiteSpace: "nowrap",
3707
+ overflow: "hidden",
3708
+ textOverflow: "ellipsis",
3709
+ maxWidth: 160
3710
+ },
3711
+ title: `stageId: ${stageId}`,
3712
+ children: stageId
3713
+ }
3685
3714
  )
3686
3715
  ]
3687
3716
  }
@@ -3712,326 +3741,488 @@ var StageNode = memo3(function StageNode2({
3712
3741
  ] });
3713
3742
  });
3714
3743
 
3715
- // src/components/FlowchartView/specToReactFlow.ts
3716
- import { MarkerType } from "@xyflow/react";
3717
- var DEFAULT_COLORS = {
3718
- edgeDefault: rawDefaults.colors.textMuted,
3719
- edgeExecuted: rawDefaults.colors.success,
3720
- edgeActive: rawDefaults.colors.primary,
3721
- edgeLoop: rawDefaults.colors.warning,
3722
- labelDefault: rawDefaults.colors.textSecondary,
3723
- labelExecuted: rawDefaults.colors.success,
3724
- labelLoop: rawDefaults.colors.warning,
3725
- pathGlow: `${rawDefaults.colors.success}4D`
3726
- // ~30% opacity hex
3727
- };
3744
+ // src/components/FlowchartView/TraceFlow.tsx
3745
+ import { jsx as jsx17 } from "react/jsx-runtime";
3728
3746
  var Y_STEP = 100;
3729
3747
  var X_SPREAD = 200;
3730
- function nid(n) {
3731
- return n.id || n.name || `spec-${Math.random()}`;
3732
- }
3733
- function registerNode(state, node) {
3734
- if (node.id && node.name) {
3735
- state.idToName.set(node.id, node.name);
3736
- }
3737
- }
3738
- function walkLayout(node, state, x, y) {
3739
- if (!node) return { lastIds: [], bottomY: y };
3740
- registerNode(state, node);
3741
- const id = nid(node);
3742
- if (state.seen.has(id)) {
3743
- return { lastIds: [id], bottomY: y };
3744
- }
3745
- state.seen.add(id);
3746
- const isDecider = node.type === "decider" || node.type === "selector" || !!node.hasDecider || !!node.hasSelector;
3747
- const isFork = node.type === "fork";
3748
- state.nodes.push({
3749
- id,
3750
- x,
3751
- y,
3752
- label: node.name,
3753
- isDecider,
3754
- isFork,
3755
- description: node.description,
3756
- icon: node.icon,
3757
- subflowId: node.subflowId,
3758
- isSubflow: !!node.isSubflowRoot,
3759
- isLazy: node.isLazy
3760
- });
3761
- let lastIds = [id];
3762
- let bottomY = y;
3763
- if (node.children && node.children.length > 0) {
3764
- const totalWidth = (node.children.length - 1) * X_SPREAD;
3765
- const startX = x - totalWidth / 2;
3766
- const childY = y + Y_STEP;
3767
- const childResults = [];
3768
- for (let i = 0; i < node.children.length; i++) {
3769
- const child = node.children[i];
3770
- if (!child) continue;
3771
- const childX = startX + i * X_SPREAD;
3772
- const edgeLabel = node.branchIds?.[i];
3773
- state.edgeCounter++;
3774
- state.edges.push({ id: `se${state.edgeCounter}`, source: id, target: nid(child), label: edgeLabel, isLoop: false });
3775
- const result = walkLayout(child, state, childX, childY);
3776
- childResults.push(result);
3748
+ var defaultTraceFlowLayout = (graph) => {
3749
+ if (graph.nodes.length === 0) return { nodes: [], edges: graph.edges };
3750
+ const branchChildrenOf = /* @__PURE__ */ new Map();
3751
+ const nextChildrenOf = /* @__PURE__ */ new Map();
3752
+ const hasIncomingForward = /* @__PURE__ */ new Set();
3753
+ for (const e of graph.edges) {
3754
+ const kind = e.data?.kind;
3755
+ if (kind === "loop") continue;
3756
+ hasIncomingForward.add(e.target);
3757
+ if (kind === "fork-branch" || kind === "decision-branch") {
3758
+ const arr = branchChildrenOf.get(e.source) ?? [];
3759
+ arr.push(e.target);
3760
+ branchChildrenOf.set(e.source, arr);
3761
+ } else {
3762
+ const arr = nextChildrenOf.get(e.source) ?? [];
3763
+ arr.push(e.target);
3764
+ nextChildrenOf.set(e.source, arr);
3777
3765
  }
3778
- lastIds = childResults.flatMap((r) => r.lastIds);
3779
- bottomY = Math.max(...childResults.map((r) => r.bottomY));
3780
3766
  }
3781
- if (node.loopTarget) {
3782
- state.edgeCounter++;
3783
- state.edges.push({ id: `se${state.edgeCounter}`, source: id, target: node.loopTarget, label: "loop", isLoop: true });
3784
- }
3785
- if (node.next) {
3786
- const rawNextId = nid(node.next);
3787
- const resolvedNextId = state.idToName.get(rawNextId) ?? rawNextId;
3788
- const isLoopRef = node.loopTarget && state.seen.has(resolvedNextId);
3789
- if (isLoopRef) {
3790
- for (const lid of lastIds) {
3791
- state.edgeCounter++;
3792
- state.edges.push({ id: `se${state.edgeCounter}`, source: lid, target: resolvedNextId, label: "loop", isLoop: true });
3767
+ const seed = graph.nodes.find((n) => !hasIncomingForward.has(n.id)) ?? graph.nodes[0];
3768
+ const positions = /* @__PURE__ */ new Map();
3769
+ function layoutSubtree(nodeId, x, y) {
3770
+ if (positions.has(nodeId)) {
3771
+ return positions.get(nodeId).y;
3772
+ }
3773
+ positions.set(nodeId, { x, y });
3774
+ let deepestBranchY = y;
3775
+ const branches = branchChildrenOf.get(nodeId) ?? [];
3776
+ if (branches.length > 0) {
3777
+ const childY = y + Y_STEP;
3778
+ const totalWidth = (branches.length - 1) * X_SPREAD;
3779
+ const startX = x - totalWidth / 2;
3780
+ for (let i = 0; i < branches.length; i++) {
3781
+ const childId = branches[i];
3782
+ const childX = startX + i * X_SPREAD;
3783
+ const subtreeBottom = layoutSubtree(childId, childX, childY);
3784
+ if (subtreeBottom > deepestBranchY) deepestBranchY = subtreeBottom;
3793
3785
  }
3794
- return { lastIds, bottomY };
3795
3786
  }
3796
- const nextY = bottomY + Y_STEP;
3797
- for (const lid of lastIds) {
3798
- state.edgeCounter++;
3799
- state.edges.push({ id: `se${state.edgeCounter}`, source: lid, target: resolvedNextId, isLoop: false });
3787
+ const nextChildren = nextChildrenOf.get(nodeId) ?? [];
3788
+ if (nextChildren.length > 0) {
3789
+ const nextY = branches.length > 0 ? deepestBranchY + Y_STEP : y + Y_STEP;
3790
+ const totalWidth = (nextChildren.length - 1) * X_SPREAD;
3791
+ const startX = x - totalWidth / 2;
3792
+ let deepestNextY = nextY;
3793
+ for (let i = 0; i < nextChildren.length; i++) {
3794
+ const childId = nextChildren[i];
3795
+ const childX = startX + i * X_SPREAD;
3796
+ const subtreeBottom = layoutSubtree(childId, childX, nextY);
3797
+ if (subtreeBottom > deepestNextY) deepestNextY = subtreeBottom;
3798
+ }
3799
+ return deepestNextY;
3800
3800
  }
3801
- return walkLayout(node.next, state, x, nextY);
3801
+ return deepestBranchY;
3802
3802
  }
3803
- return { lastIds, bottomY };
3804
- }
3805
- function specToLayout(spec) {
3806
- const state = {
3807
- nodes: [],
3808
- edges: [],
3809
- edgeCounter: 0,
3810
- seen: /* @__PURE__ */ new Set(),
3811
- idToName: /* @__PURE__ */ new Map()
3812
- };
3813
- walkLayout(spec, state, 300, 0);
3814
- return { nodes: state.nodes, edges: state.edges, idToName: state.idToName };
3815
- }
3816
- function applyOverlay(layout, overlay, colors) {
3817
- const c = { ...DEFAULT_COLORS, ...colors };
3818
- const o = overlay ?? null;
3819
- const nodes = layout.nodes.map((ln) => {
3820
- const isDone = o ? o.doneStages.has(ln.id) : false;
3821
- const isActive = o ? o.activeStage === ln.id : false;
3822
- const wasExecuted = o ? o.executedStages.has(ln.id) : false;
3823
- const dimmed = o && !wasExecuted;
3824
- let stepNumbers;
3825
- if (o?.executionOrder) {
3826
- const nums = [];
3827
- for (let i = 0; i < o.executionOrder.length; i++) {
3828
- if (o.executionOrder[i] === ln.id) nums.push(i + 1);
3829
- }
3830
- if (nums.length > 0) stepNumbers = nums;
3803
+ layoutSubtree(seed.id, 0, 0);
3804
+ let maxY = 0;
3805
+ for (const p of positions.values()) {
3806
+ if (p.y > maxY) maxY = p.y;
3807
+ }
3808
+ let orphanY = maxY + Y_STEP;
3809
+ for (const n of graph.nodes) {
3810
+ if (!positions.has(n.id)) {
3811
+ positions.set(n.id, { x: 0, y: orphanY });
3812
+ orphanY += Y_STEP;
3831
3813
  }
3814
+ }
3815
+ return {
3816
+ nodes: graph.nodes.map((n) => ({
3817
+ ...n,
3818
+ position: positions.get(n.id) ?? n.position
3819
+ })),
3820
+ edges: graph.edges
3821
+ };
3822
+ };
3823
+ var DEFAULT_EDGE_COLORS = {
3824
+ next: rawDefaults.colors.textMuted,
3825
+ forkBranch: rawDefaults.colors.textMuted,
3826
+ decisionBranch: rawDefaults.colors.primary,
3827
+ loop: rawDefaults.colors.warning
3828
+ };
3829
+
3830
+ // src/components/FlowchartView/createTraceRuntimeOverlay.ts
3831
+ function sliceOverlay(overlay, index) {
3832
+ const order = overlay.executionOrder;
3833
+ if (order.length === 0) {
3832
3834
  return {
3833
- id: ln.id,
3834
- position: { x: ln.x, y: ln.y },
3835
- data: {
3836
- label: ln.label,
3837
- active: isActive,
3838
- done: isDone,
3839
- error: false,
3840
- isDecider: ln.isDecider,
3841
- isFork: ln.isFork,
3842
- description: ln.description,
3843
- icon: ln.icon,
3844
- subflowId: ln.subflowId,
3845
- dimmed,
3846
- stepNumbers,
3847
- isSubflow: ln.isSubflow,
3848
- isLazy: ln.isLazy
3849
- },
3850
- type: "stage",
3851
- style: dimmed ? { opacity: 0.35 } : void 0
3835
+ doneStageIds: /* @__PURE__ */ new Set(),
3836
+ activeStageId: null,
3837
+ executedStageIds: /* @__PURE__ */ new Set(),
3838
+ executedOrderIds: [],
3839
+ errors: overlay.errors
3852
3840
  };
3853
- });
3854
- const edges = [];
3855
- for (const le of layout.edges) {
3856
- const executed = o && o.executedStages.has(le.source) && o.executedStages.has(le.target);
3857
- const isLeadingEdge = o && le.source === o.activeStage && !o.doneStages.has(le.target);
3858
- if (le.isLoop) {
3859
- let loopExecuted = false;
3860
- if (o?.executionOrder) {
3861
- if (le.source === le.target) {
3862
- const count = o.executionOrder.filter((id) => id === le.source).length;
3863
- loopExecuted = count > 1;
3864
- } else {
3865
- const lastSourceIdx = o.executionOrder.lastIndexOf(le.source);
3866
- if (lastSourceIdx >= 0) {
3867
- loopExecuted = o.executionOrder.slice(lastSourceIdx + 1).includes(le.target);
3868
- }
3869
- }
3870
- }
3871
- edges.push({
3872
- id: le.id,
3873
- source: le.source,
3874
- target: le.target,
3875
- sourceHandle: "loop-source",
3876
- targetHandle: "loop-target",
3877
- label: le.label ?? "loop",
3878
- type: "smoothstep",
3879
- pathOptions: { offset: 60, borderRadius: 20 },
3880
- markerEnd: { type: MarkerType.ArrowClosed, color: loopExecuted ? c.edgeActive : c.edgeLoop, width: 16, height: 16 },
3881
- style: {
3882
- stroke: loopExecuted ? c.edgeActive : c.edgeLoop,
3883
- strokeWidth: loopExecuted ? 4 : 2,
3884
- strokeDasharray: loopExecuted ? void 0 : "6 3",
3885
- opacity: o && !loopExecuted ? 0.35 : 1
3886
- },
3887
- labelStyle: { fontSize: 10, fontWeight: 700, fill: loopExecuted ? c.edgeActive : c.labelLoop },
3888
- animated: loopExecuted,
3889
- zIndex: 2
3890
- });
3891
- } else if (executed) {
3892
- edges.push({
3893
- id: `${le.id}-glow`,
3894
- source: le.source,
3895
- target: le.target,
3896
- style: { stroke: c.pathGlow, strokeWidth: 8, opacity: 0.4 },
3897
- zIndex: 0,
3898
- selectable: false,
3899
- focusable: false
3900
- });
3901
- edges.push({
3902
- id: le.id,
3903
- source: le.source,
3904
- target: le.target,
3905
- label: le.label,
3906
- style: {
3907
- stroke: isLeadingEdge ? c.edgeActive : c.edgeExecuted,
3908
- strokeWidth: 3.5
3909
- },
3910
- labelStyle: { fontSize: 10, fontWeight: 600, fill: c.labelExecuted },
3911
- animated: !!isLeadingEdge,
3912
- zIndex: 1
3913
- });
3914
- } else {
3915
- edges.push({
3916
- id: le.id,
3917
- source: le.source,
3918
- target: le.target,
3919
- label: le.label,
3920
- style: {
3921
- stroke: c.edgeDefault,
3922
- strokeWidth: 1.5,
3923
- opacity: o ? 0.3 : 1
3924
- },
3925
- labelStyle: { fontSize: 10, fill: c.labelDefault }
3926
- });
3841
+ }
3842
+ const clampedIndex = Math.max(0, Math.min(index, order.length - 1));
3843
+ const doneStageIds = /* @__PURE__ */ new Set();
3844
+ for (let i = 0; i < clampedIndex; i++) {
3845
+ doneStageIds.add(order[i].stageId);
3846
+ }
3847
+ const activeStep = order[clampedIndex];
3848
+ const activeStageId = activeStep ? activeStep.stageId : null;
3849
+ const executedStageIds = new Set(doneStageIds);
3850
+ if (activeStageId) executedStageIds.add(activeStageId);
3851
+ const executedOrderIds = order.slice(0, clampedIndex + 1).map((s) => s.stageId);
3852
+ return {
3853
+ doneStageIds,
3854
+ activeStageId,
3855
+ executedStageIds,
3856
+ executedOrderIds,
3857
+ errors: overlay.errors
3858
+ };
3859
+ }
3860
+
3861
+ // src/components/FlowchartView/_internal/subflowDrill.ts
3862
+ function filterGraphForDrill(graph, currentSubflowId) {
3863
+ if (graph.nodes.length === 0) return graph;
3864
+ const matchesScope = (subflowOf) => currentSubflowId === null ? subflowOf === void 0 : subflowOf === currentSubflowId;
3865
+ const visibleIds = /* @__PURE__ */ new Set();
3866
+ for (const n of graph.nodes) {
3867
+ if (matchesScope(n.data?.subflowOf)) visibleIds.add(n.id);
3868
+ }
3869
+ if (visibleIds.size === graph.nodes.length) return graph;
3870
+ return {
3871
+ nodes: graph.nodes.filter((n) => visibleIds.has(n.id)),
3872
+ edges: graph.edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target))
3873
+ };
3874
+ }
3875
+ function buildSubflowBreadcrumb(graph, currentSubflowId) {
3876
+ const out = [{ subflowId: null, label: "Chart" }];
3877
+ if (currentSubflowId !== null) {
3878
+ const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);
3879
+ out.push({
3880
+ subflowId: currentSubflowId,
3881
+ label: mount?.data?.label ?? currentSubflowId
3882
+ });
3883
+ }
3884
+ return out;
3885
+ }
3886
+
3887
+ // src/components/FlowchartView/_internal/overlayProjection.ts
3888
+ function leafId(id) {
3889
+ const i = id.lastIndexOf("/");
3890
+ return i >= 0 ? id.slice(i + 1) : id;
3891
+ }
3892
+ function normalizeSliceLeafIds(slice) {
3893
+ return {
3894
+ doneStageIds: new Set(Array.from(slice.doneStageIds).map(leafId)),
3895
+ activeStageId: slice.activeStageId ? leafId(slice.activeStageId) : null,
3896
+ executedStageIds: new Set(Array.from(slice.executedStageIds).map(leafId)),
3897
+ executedOrderIds: slice.executedOrderIds.map(leafId),
3898
+ errors: new Map(Array.from(slice.errors).map(([k, v2]) => [leafId(k), v2]))
3899
+ };
3900
+ }
3901
+ function aggregateMountStatus(slice, graph, currentSubflowId) {
3902
+ if (graph.nodes.length === 0) return slice;
3903
+ const mounts = graph.nodes.filter((n) => n.data?.isSubflow && n.data?.subflowId);
3904
+ if (mounts.length === 0) return slice;
3905
+ const doneIds = new Set(slice.doneStageIds);
3906
+ let activeId = slice.activeStageId;
3907
+ for (const mount of mounts) {
3908
+ const sfId = mount.data.subflowId;
3909
+ const members = graph.nodes.filter((n) => n.data?.subflowOf === sfId);
3910
+ if (members.length === 0) continue;
3911
+ const anyActive = members.some((m) => m.id === slice.activeStageId);
3912
+ const anyDone = members.some((m) => slice.doneStageIds.has(m.id));
3913
+ const allDone = members.every((m) => slice.doneStageIds.has(m.id));
3914
+ if (allDone) doneIds.add(mount.id);
3915
+ else if ((anyActive || anyDone) && currentSubflowId === null) {
3916
+ activeId = mount.id;
3927
3917
  }
3928
3918
  }
3929
- return { nodes, edges };
3919
+ return { ...slice, doneStageIds: doneIds, activeStageId: activeId };
3930
3920
  }
3931
3921
 
3932
- // src/components/FlowchartView/TracedFlowchartView.tsx
3933
- import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3934
- var defaultNodeTypes = { stage: StageNode };
3935
- function FitViewOnResize() {
3936
- const { fitView } = useReactFlow();
3922
+ // src/components/FlowchartView/_internal/useSubflowDrill.ts
3923
+ import { useCallback as useCallback7, useEffect as useEffect7, useRef as useRef7, useState as useState9 } from "react";
3924
+ function useSubflowDrill(graph, onSubflowChange) {
3925
+ const [currentSubflowId, setCurrentSubflowId] = useState9(null);
3926
+ const lastGraphRef = useRef7(null);
3927
+ if (lastGraphRef.current !== graph) {
3928
+ lastGraphRef.current = graph;
3929
+ if (currentSubflowId !== null && !graph.nodes.some((n) => n.data?.subflowId === currentSubflowId)) {
3930
+ queueMicrotask(() => setCurrentSubflowId(null));
3931
+ }
3932
+ }
3933
+ const lastNotifiedRef = useRef7(void 0);
3937
3934
  useEffect7(() => {
3938
- const handler = () => {
3939
- requestAnimationFrame(() => fitView({ padding: 0.3 }));
3935
+ if (lastNotifiedRef.current === currentSubflowId) return;
3936
+ lastNotifiedRef.current = currentSubflowId;
3937
+ if (currentSubflowId === null) {
3938
+ onSubflowChange?.(null);
3939
+ } else {
3940
+ const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);
3941
+ if (mount) onSubflowChange?.(mount.id);
3942
+ }
3943
+ }, [currentSubflowId, graph, onSubflowChange]);
3944
+ const drillInto = useCallback7((subflowId) => {
3945
+ setCurrentSubflowId(subflowId);
3946
+ }, []);
3947
+ const drillUp = useCallback7(() => {
3948
+ setCurrentSubflowId(null);
3949
+ }, []);
3950
+ return { currentSubflowId, drillInto, drillUp, setCurrentSubflowId };
3951
+ }
3952
+
3953
+ // src/components/FlowchartView/_internal/useChartAutoRefit.ts
3954
+ import { useEffect as useEffect8 } from "react";
3955
+ function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
3956
+ const duration = options.duration ?? 200;
3957
+ const padding2 = options.padding ?? 0.1;
3958
+ useEffect8(() => {
3959
+ const el = wrapperRef.current;
3960
+ if (!el || !rfInstance) return;
3961
+ let raf = 0;
3962
+ const refit = () => {
3963
+ cancelAnimationFrame(raf);
3964
+ raf = requestAnimationFrame(() => {
3965
+ rfInstance.fitView({ duration, padding: padding2 });
3966
+ });
3940
3967
  };
3941
- window.addEventListener("resize", handler);
3942
- const timer = setTimeout(handler, 50);
3968
+ const ro = new ResizeObserver(refit);
3969
+ ro.observe(el);
3970
+ window.addEventListener("resize", refit);
3943
3971
  return () => {
3944
- window.removeEventListener("resize", handler);
3945
- clearTimeout(timer);
3972
+ ro.disconnect();
3973
+ window.removeEventListener("resize", refit);
3974
+ cancelAnimationFrame(raf);
3946
3975
  };
3947
- }, [fitView]);
3948
- return null;
3976
+ }, [rfInstance, wrapperRef, duration, padding2]);
3949
3977
  }
3950
- function TracedFlowchartView({
3951
- spec,
3952
- snapshots,
3953
- snapshotIndex = 0,
3978
+
3979
+ // src/components/FlowchartView/SubflowBreadcrumbBar.tsx
3980
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3981
+ function SubflowBreadcrumbBar({ entries, onNavigate }) {
3982
+ return /* @__PURE__ */ jsx18(
3983
+ "div",
3984
+ {
3985
+ style: {
3986
+ display: "flex",
3987
+ alignItems: "center",
3988
+ gap: 6,
3989
+ padding: "6px 12px",
3990
+ fontSize: 11,
3991
+ background: rawDefaults.colors.bgSecondary,
3992
+ borderBottom: `1px solid ${rawDefaults.colors.border}`,
3993
+ flexShrink: 0
3994
+ },
3995
+ "aria-label": "Subflow breadcrumb",
3996
+ children: entries.map((entry, i) => {
3997
+ const isLast = i === entries.length - 1;
3998
+ return /* @__PURE__ */ jsxs16(
3999
+ "span",
4000
+ {
4001
+ style: { display: "inline-flex", alignItems: "center", gap: 6 },
4002
+ children: [
4003
+ /* @__PURE__ */ jsx18(
4004
+ "button",
4005
+ {
4006
+ type: "button",
4007
+ onClick: () => onNavigate(entry.subflowId),
4008
+ disabled: isLast,
4009
+ style: {
4010
+ background: "transparent",
4011
+ border: "none",
4012
+ padding: 0,
4013
+ fontSize: 11,
4014
+ fontWeight: isLast ? 600 : 500,
4015
+ color: isLast ? rawDefaults.colors.textPrimary : rawDefaults.colors.primary,
4016
+ cursor: isLast ? "default" : "pointer",
4017
+ textDecoration: isLast ? "none" : "underline",
4018
+ fontFamily: "inherit"
4019
+ },
4020
+ children: entry.label
4021
+ }
4022
+ ),
4023
+ !isLast && /* @__PURE__ */ jsx18("span", { style: { color: rawDefaults.colors.textMuted }, children: "\u203A" })
4024
+ ]
4025
+ },
4026
+ entry.subflowId ?? "__top__"
4027
+ );
4028
+ })
4029
+ }
4030
+ );
4031
+ }
4032
+
4033
+ // src/components/FlowchartView/TracedFlow.tsx
4034
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
4035
+ var DEFAULT_COLORS = {
4036
+ default: rawDefaults.colors.textMuted,
4037
+ done: rawDefaults.colors.success,
4038
+ active: rawDefaults.colors.primary,
4039
+ error: rawDefaults.colors.error,
4040
+ loop: rawDefaults.colors.warning
4041
+ };
4042
+ function toStageNodeWithOverlay(node, doneStageIds, activeStageId, errorMessage, executedOrderIds) {
4043
+ const isDone = doneStageIds.has(node.id);
4044
+ const isActive = activeStageId === node.id;
4045
+ const wasExecuted = isDone || isActive;
4046
+ const hasError = !!errorMessage;
4047
+ const dimmed = !wasExecuted && executedOrderIds.length > 0;
4048
+ let stepNumbers;
4049
+ if (executedOrderIds.length > 0) {
4050
+ const nums = [];
4051
+ for (let i = 0; i < executedOrderIds.length; i++) {
4052
+ if (executedOrderIds[i] === node.id) nums.push(i + 1);
4053
+ }
4054
+ if (nums.length > 0) stepNumbers = nums;
4055
+ }
4056
+ const stageData = {
4057
+ label: node.data.label,
4058
+ isDecider: node.data.isDecider,
4059
+ isFork: node.data.isFork,
4060
+ isSubflow: node.data.isSubflow,
4061
+ active: isActive,
4062
+ done: isDone,
4063
+ error: hasError,
4064
+ ...node.data.description !== void 0 && { description: node.data.description },
4065
+ ...node.data.icon !== void 0 && { icon: node.data.icon },
4066
+ ...node.data.subflowId !== void 0 && { subflowId: node.data.subflowId },
4067
+ ...node.data.isLazy === true && { isLazy: true },
4068
+ ...dimmed && { dimmed: true },
4069
+ ...stepNumbers && { stepNumbers },
4070
+ ...errorMessage && { errorMessage }
4071
+ };
4072
+ return {
4073
+ ...node,
4074
+ type: "stageNode",
4075
+ data: stageData,
4076
+ ...dimmed && { style: { opacity: 0.35 } }
4077
+ };
4078
+ }
4079
+ function styleEdgeWithOverlay(edge, doneStageIds, activeStageId, colors) {
4080
+ const kind = edge.data?.kind ?? "next";
4081
+ const sourceExecuted = doneStageIds.has(edge.source) || activeStageId === edge.source;
4082
+ const targetExecuted = doneStageIds.has(edge.target) || activeStageId === edge.target;
4083
+ const traversed = sourceExecuted && targetExecuted;
4084
+ const isLeadingEdge = activeStageId === edge.source && !doneStageIds.has(edge.target);
4085
+ let color = colors.default;
4086
+ if (kind === "loop") color = colors.loop;
4087
+ else if (isLeadingEdge) color = colors.active;
4088
+ else if (traversed) color = colors.done;
4089
+ const styled = {
4090
+ ...edge,
4091
+ type: "smoothstep",
4092
+ animated: isLeadingEdge,
4093
+ style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },
4094
+ markerEnd: { type: MarkerType2.ArrowClosed, color, width: 16, height: 16 }
4095
+ };
4096
+ if (kind === "loop") {
4097
+ styled.style = { ...styled.style, strokeDasharray: "4 3" };
4098
+ styled.data = {
4099
+ ...styled.data ?? {},
4100
+ pathOptions: { borderRadius: 14, offset: 36 }
4101
+ };
4102
+ styled.sourceHandle = "loop-source";
4103
+ styled.targetHandle = "loop-target";
4104
+ }
4105
+ return styled;
4106
+ }
4107
+ var nodeTypes = { stageNode: StageNode };
4108
+ function TracedFlow({
4109
+ graph,
4110
+ overlay,
4111
+ scrubIndex,
4112
+ layout: layoutProp,
4113
+ colors: colorOverrides,
3954
4114
  onNodeClick,
3955
- nodeTypes: customNodeTypes,
3956
- unstyled = false,
4115
+ onSubflowChange,
3957
4116
  className,
3958
4117
  style
3959
4118
  }) {
3960
- const nodeTypes = customNodeTypes ?? defaultNodeTypes;
3961
- const overlay = useMemo10(() => {
3962
- if (!snapshots || snapshots.length === 0) return void 0;
3963
- const executionOrder = snapshots.slice(0, snapshotIndex + 1).map((s) => s.stageLabel);
3964
- const doneStages = new Set(
3965
- snapshots.slice(0, snapshotIndex).map((s) => s.stageLabel)
3966
- );
3967
- const activeStage = snapshots[snapshotIndex]?.stageLabel ?? null;
3968
- const executedStages = /* @__PURE__ */ new Set([...doneStages]);
3969
- if (activeStage) executedStages.add(activeStage);
3970
- return { doneStages, activeStage, executedStages, executionOrder };
3971
- }, [snapshots, snapshotIndex]);
3972
- const layout = useMemo10(() => {
3973
- if (!spec) return null;
3974
- return specToLayout(spec);
3975
- }, [spec]);
3976
- const flowData = useMemo10(() => {
3977
- if (!layout) return { nodes: [], edges: [] };
3978
- return applyOverlay(layout, overlay);
3979
- }, [layout, overlay]);
3980
- const [nodes, setNodes, onNodesChange] = useNodesState(flowData.nodes);
3981
- const [edges, setEdges, onEdgesChange] = useEdgesState(flowData.edges);
3982
- useEffect7(() => {
3983
- setNodes(flowData.nodes);
3984
- setEdges(flowData.edges);
3985
- }, [flowData, setNodes, setEdges]);
3986
- const handleNodeClick = useCallback6(
4119
+ const layout = layoutProp ?? defaultTraceFlowLayout;
4120
+ const colors = useMemo11(
4121
+ () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
4122
+ [colorOverrides]
4123
+ );
4124
+ const drill = useSubflowDrill(graph, onSubflowChange);
4125
+ const filteredGraph = useMemo11(
4126
+ () => filterGraphForDrill(graph, drill.currentSubflowId),
4127
+ [graph, drill.currentSubflowId]
4128
+ );
4129
+ const breadcrumb = useMemo11(
4130
+ () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
4131
+ [graph, drill.currentSubflowId]
4132
+ );
4133
+ const positioned = useMemo11(
4134
+ () => layout === "passthrough" ? filteredGraph : layout(filteredGraph),
4135
+ [filteredGraph, layout]
4136
+ );
4137
+ const slice = useMemo11(() => {
4138
+ const empty = {
4139
+ doneStageIds: /* @__PURE__ */ new Set(),
4140
+ activeStageId: null,
4141
+ executedStageIds: /* @__PURE__ */ new Set(),
4142
+ executedOrderIds: [],
4143
+ errors: /* @__PURE__ */ new Map()
4144
+ };
4145
+ if (!overlay) return empty;
4146
+ const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);
4147
+ const normalized = normalizeSliceLeafIds(sliceOverlay(overlay, idx));
4148
+ return aggregateMountStatus(normalized, graph, drill.currentSubflowId);
4149
+ }, [overlay, scrubIndex, graph, drill.currentSubflowId]);
4150
+ const reactFlowNodes = useMemo11(
4151
+ () => positioned.nodes.map(
4152
+ (n) => toStageNodeWithOverlay(
4153
+ n,
4154
+ slice.doneStageIds,
4155
+ slice.activeStageId,
4156
+ slice.errors.get(n.id),
4157
+ slice.executedOrderIds
4158
+ )
4159
+ ),
4160
+ [positioned.nodes, slice]
4161
+ );
4162
+ const reactFlowEdges = useMemo11(
4163
+ () => positioned.edges.map(
4164
+ (e) => styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors)
4165
+ ),
4166
+ [positioned.edges, slice, colors]
4167
+ );
4168
+ const handleNodeClick = useCallback8(
3987
4169
  (_, node) => {
3988
- if (!onNodeClick) return;
3989
- onNodeClick(node.id);
4170
+ const data = node.data ?? {};
4171
+ if (data.isSubflow && data.subflowId) {
4172
+ drill.drillInto(data.subflowId);
4173
+ }
4174
+ onNodeClick?.(node.id);
3990
4175
  },
3991
- [onNodeClick]
4176
+ [drill, onNodeClick]
3992
4177
  );
3993
- return /* @__PURE__ */ jsx17(
4178
+ const wrapperRef = useRef8(null);
4179
+ const [rfInstance, setRfInstance] = useState10(null);
4180
+ useChartAutoRefit(wrapperRef, rfInstance);
4181
+ return /* @__PURE__ */ jsxs17(
3994
4182
  "div",
3995
4183
  {
4184
+ ref: wrapperRef,
3996
4185
  className,
3997
- style: { width: "100%", height: "100%", ...style },
3998
- "data-fp": "traced-flowchart",
3999
- children: /* @__PURE__ */ jsxs16(
4000
- ReactFlow,
4001
- {
4002
- nodes,
4003
- edges,
4004
- onNodesChange,
4005
- onEdgesChange,
4006
- onNodeClick: handleNodeClick,
4007
- nodeTypes,
4008
- fitView: true,
4009
- fitViewOptions: { padding: 0.3 },
4010
- proOptions: { hideAttribution: true },
4011
- panOnDrag: false,
4012
- zoomOnScroll: false,
4013
- zoomOnPinch: false,
4014
- zoomOnDoubleClick: false,
4015
- preventScrolling: false,
4016
- nodesDraggable: false,
4017
- nodesConnectable: false,
4018
- elementsSelectable: !!onNodeClick,
4019
- children: [
4020
- /* @__PURE__ */ jsx17(FitViewOnResize, {}),
4021
- !unstyled && /* @__PURE__ */ jsx17(Background, { variant: BackgroundVariant.Dots, gap: 16, size: 1 })
4022
- ]
4023
- }
4024
- )
4186
+ style: {
4187
+ width: "100%",
4188
+ height: "100%",
4189
+ minHeight: 300,
4190
+ display: "flex",
4191
+ flexDirection: "column",
4192
+ ...style
4193
+ },
4194
+ children: [
4195
+ breadcrumb.length > 1 && /* @__PURE__ */ jsx19(
4196
+ SubflowBreadcrumbBar,
4197
+ {
4198
+ entries: breadcrumb,
4199
+ onNavigate: drill.setCurrentSubflowId
4200
+ }
4201
+ ),
4202
+ /* @__PURE__ */ jsx19("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsx19(
4203
+ ReactFlow2,
4204
+ {
4205
+ nodes: reactFlowNodes,
4206
+ edges: reactFlowEdges,
4207
+ nodeTypes,
4208
+ onNodeClick: handleNodeClick,
4209
+ onInit: setRfInstance,
4210
+ fitView: true,
4211
+ proOptions: { hideAttribution: true },
4212
+ children: /* @__PURE__ */ jsx19(Background2, { variant: BackgroundVariant2.Dots, gap: 20, size: 1 })
4213
+ }
4214
+ ) })
4215
+ ]
4025
4216
  }
4026
4217
  );
4027
4218
  }
4028
4219
 
4029
4220
  // src/components/InspectorPanel/InspectorPanel.tsx
4030
- import { memo as memo5, useState as useState9 } from "react";
4221
+ import { memo as memo5, useState as useState11 } from "react";
4031
4222
 
4032
4223
  // src/components/DataTracePanel/DataTracePanel.tsx
4033
4224
  import { memo as memo4 } from "react";
4034
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
4225
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
4035
4226
  var DataTracePanel = memo4(function DataTracePanel2({
4036
4227
  frames,
4037
4228
  selectedStageId,
@@ -4039,8 +4230,8 @@ var DataTracePanel = memo4(function DataTracePanel2({
4039
4230
  fromStageName
4040
4231
  }) {
4041
4232
  if (frames.length === 0) {
4042
- return /* @__PURE__ */ jsxs17("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
4043
- /* @__PURE__ */ jsx18(
4233
+ return /* @__PURE__ */ jsxs18("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
4234
+ /* @__PURE__ */ jsx20(
4044
4235
  "div",
4045
4236
  {
4046
4237
  style: {
@@ -4054,13 +4245,13 @@ var DataTracePanel = memo4(function DataTracePanel2({
4054
4245
  children: "Backward causal chain"
4055
4246
  }
4056
4247
  ),
4057
- /* @__PURE__ */ jsx18("div", { style: { color: theme.textSecondary, marginBottom: 10 }, children: "Trace any value back to the stage that created it \u2014 and everything upstream that influenced it." }),
4058
- /* @__PURE__ */ jsx18("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
4248
+ /* @__PURE__ */ jsx20("div", { style: { color: theme.textSecondary, marginBottom: 10 }, children: "Trace any value back to the stage that created it \u2014 and everything upstream that influenced it." }),
4249
+ /* @__PURE__ */ jsx20("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
4059
4250
  ] });
4060
4251
  }
4061
- return /* @__PURE__ */ jsxs17("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
4062
- fromStageName && /* @__PURE__ */ jsxs17("div", { style: { padding: "4px 12px 8px" }, children: [
4063
- /* @__PURE__ */ jsxs17(
4252
+ return /* @__PURE__ */ jsxs18("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
4253
+ fromStageName && /* @__PURE__ */ jsxs18("div", { style: { padding: "4px 12px 8px" }, children: [
4254
+ /* @__PURE__ */ jsxs18(
4064
4255
  "div",
4065
4256
  {
4066
4257
  style: {
@@ -4076,7 +4267,7 @@ var DataTracePanel = memo4(function DataTracePanel2({
4076
4267
  ]
4077
4268
  }
4078
4269
  ),
4079
- /* @__PURE__ */ jsx18(
4270
+ /* @__PURE__ */ jsx20(
4080
4271
  "div",
4081
4272
  {
4082
4273
  style: {
@@ -4089,7 +4280,7 @@ var DataTracePanel = memo4(function DataTracePanel2({
4089
4280
  }
4090
4281
  )
4091
4282
  ] }),
4092
- frames.map((frame, i) => /* @__PURE__ */ jsx18(
4283
+ frames.map((frame, i) => /* @__PURE__ */ jsx20(
4093
4284
  DataTraceFrame,
4094
4285
  {
4095
4286
  frame,
@@ -4109,7 +4300,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4109
4300
  isSelected,
4110
4301
  onClick
4111
4302
  }) {
4112
- return /* @__PURE__ */ jsxs17(
4303
+ return /* @__PURE__ */ jsxs18(
4113
4304
  "button",
4114
4305
  {
4115
4306
  onClick: () => onClick?.(frame.runtimeStageId),
@@ -4126,9 +4317,9 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4126
4317
  fontSize: 13
4127
4318
  },
4128
4319
  children: [
4129
- /* @__PURE__ */ jsxs17("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4130
- !isFirst && /* @__PURE__ */ jsx18("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
4131
- /* @__PURE__ */ jsx18(
4320
+ /* @__PURE__ */ jsxs18("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4321
+ !isFirst && /* @__PURE__ */ jsx20("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
4322
+ /* @__PURE__ */ jsx20(
4132
4323
  "span",
4133
4324
  {
4134
4325
  style: {
@@ -4138,7 +4329,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4138
4329
  children: frame.stageName
4139
4330
  }
4140
4331
  ),
4141
- isLast && !isFirst && /* @__PURE__ */ jsx18(
4332
+ isLast && !isFirst && /* @__PURE__ */ jsx20(
4142
4333
  "span",
4143
4334
  {
4144
4335
  style: {
@@ -4150,7 +4341,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4150
4341
  }
4151
4342
  )
4152
4343
  ] }),
4153
- frame.keysWritten.length > 0 && /* @__PURE__ */ jsxs17(
4344
+ frame.keysWritten.length > 0 && /* @__PURE__ */ jsxs18(
4154
4345
  "div",
4155
4346
  {
4156
4347
  style: {
@@ -4162,11 +4353,11 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4162
4353
  children: [
4163
4354
  "wrote:",
4164
4355
  " ",
4165
- /* @__PURE__ */ jsx18("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
4356
+ /* @__PURE__ */ jsx20("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
4166
4357
  ]
4167
4358
  }
4168
4359
  ),
4169
- frame.linkedBy && /* @__PURE__ */ jsxs17(
4360
+ frame.linkedBy && /* @__PURE__ */ jsxs18(
4170
4361
  "div",
4171
4362
  {
4172
4363
  style: {
@@ -4187,7 +4378,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4187
4378
  });
4188
4379
 
4189
4380
  // src/components/InspectorPanel/InspectorPanel.tsx
4190
- import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
4381
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
4191
4382
  var InspectorPanel = memo5(function InspectorPanel2({
4192
4383
  snapshots,
4193
4384
  selectedIndex,
@@ -4195,9 +4386,9 @@ var InspectorPanel = memo5(function InspectorPanel2({
4195
4386
  selectedStageId,
4196
4387
  onNavigateToStage
4197
4388
  }) {
4198
- const [tab, setTab] = useState9("state");
4389
+ const [tab, setTab] = useState11("state");
4199
4390
  const currentSnapshot = snapshots[selectedIndex];
4200
- return /* @__PURE__ */ jsxs18(
4391
+ return /* @__PURE__ */ jsxs19(
4201
4392
  "div",
4202
4393
  {
4203
4394
  style: {
@@ -4207,7 +4398,7 @@ var InspectorPanel = memo5(function InspectorPanel2({
4207
4398
  overflow: "hidden"
4208
4399
  },
4209
4400
  children: [
4210
- /* @__PURE__ */ jsxs18(
4401
+ /* @__PURE__ */ jsxs19(
4211
4402
  "div",
4212
4403
  {
4213
4404
  style: {
@@ -4216,7 +4407,7 @@ var InspectorPanel = memo5(function InspectorPanel2({
4216
4407
  flexShrink: 0
4217
4408
  },
4218
4409
  children: [
4219
- /* @__PURE__ */ jsx19(
4410
+ /* @__PURE__ */ jsx21(
4220
4411
  TabButton,
4221
4412
  {
4222
4413
  active: tab === "state",
@@ -4224,7 +4415,7 @@ var InspectorPanel = memo5(function InspectorPanel2({
4224
4415
  label: "State"
4225
4416
  }
4226
4417
  ),
4227
- /* @__PURE__ */ jsx19(
4418
+ /* @__PURE__ */ jsx21(
4228
4419
  TabButton,
4229
4420
  {
4230
4421
  active: tab === "trace",
@@ -4236,15 +4427,15 @@ var InspectorPanel = memo5(function InspectorPanel2({
4236
4427
  ]
4237
4428
  }
4238
4429
  ),
4239
- /* @__PURE__ */ jsxs18("div", { style: { flex: 1, overflow: "auto" }, children: [
4240
- tab === "state" && /* @__PURE__ */ jsx19(
4430
+ /* @__PURE__ */ jsxs19("div", { style: { flex: 1, overflow: "auto" }, children: [
4431
+ tab === "state" && /* @__PURE__ */ jsx21(
4241
4432
  MemoryPanel,
4242
4433
  {
4243
4434
  snapshots,
4244
4435
  selectedIndex
4245
4436
  }
4246
4437
  ),
4247
- tab === "trace" && /* @__PURE__ */ jsx19(
4438
+ tab === "trace" && /* @__PURE__ */ jsx21(
4248
4439
  DataTracePanel,
4249
4440
  {
4250
4441
  frames: dataTraceFrames,
@@ -4264,7 +4455,7 @@ function TabButton({
4264
4455
  label,
4265
4456
  badge
4266
4457
  }) {
4267
- return /* @__PURE__ */ jsxs18(
4458
+ return /* @__PURE__ */ jsxs19(
4268
4459
  "button",
4269
4460
  {
4270
4461
  onClick,
@@ -4283,7 +4474,7 @@ function TabButton({
4283
4474
  },
4284
4475
  children: [
4285
4476
  label,
4286
- badge && /* @__PURE__ */ jsx19(
4477
+ badge && /* @__PURE__ */ jsx21(
4287
4478
  "span",
4288
4479
  {
4289
4480
  style: {
@@ -4303,28 +4494,28 @@ function TabButton({
4303
4494
  }
4304
4495
 
4305
4496
  // src/components/InsightPanel/InsightPanel.tsx
4306
- import { memo as memo6, useState as useState10 } from "react";
4307
- import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
4497
+ import { memo as memo6, useState as useState12 } from "react";
4498
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
4308
4499
  var InsightPanel = memo6(function InsightPanel2({
4309
4500
  insights,
4310
4501
  expandedId,
4311
4502
  mode
4312
4503
  }) {
4313
4504
  if (insights.length === 0) {
4314
- return /* @__PURE__ */ jsx20("div", { style: { padding: 12, color: theme.textMuted, fontSize: 13 }, children: "No insights available. Attach recorders to see data." });
4505
+ return /* @__PURE__ */ jsx22("div", { style: { padding: 12, color: theme.textMuted, fontSize: 13 }, children: "No insights available. Attach recorders to see data." });
4315
4506
  }
4316
4507
  if (mode === "grid") {
4317
- return /* @__PURE__ */ jsx20(InsightGrid, { insights });
4508
+ return /* @__PURE__ */ jsx22(InsightGrid, { insights });
4318
4509
  }
4319
- return /* @__PURE__ */ jsx20(InsightTabs, { insights, defaultId: expandedId });
4510
+ return /* @__PURE__ */ jsx22(InsightTabs, { insights, defaultId: expandedId });
4320
4511
  });
4321
4512
  var InsightTabs = memo6(function InsightTabs2({
4322
4513
  insights,
4323
4514
  defaultId
4324
4515
  }) {
4325
- const [activeId, setActiveId] = useState10(defaultId ?? insights[0]?.id);
4516
+ const [activeId, setActiveId] = useState12(defaultId ?? insights[0]?.id);
4326
4517
  const active = insights.find((i) => i.id === activeId) ?? insights[0];
4327
- return /* @__PURE__ */ jsxs19(
4518
+ return /* @__PURE__ */ jsxs20(
4328
4519
  "div",
4329
4520
  {
4330
4521
  style: {
@@ -4334,7 +4525,7 @@ var InsightTabs = memo6(function InsightTabs2({
4334
4525
  overflow: "hidden"
4335
4526
  },
4336
4527
  children: [
4337
- /* @__PURE__ */ jsx20(
4528
+ /* @__PURE__ */ jsx22(
4338
4529
  "div",
4339
4530
  {
4340
4531
  style: {
@@ -4343,7 +4534,7 @@ var InsightTabs = memo6(function InsightTabs2({
4343
4534
  flexShrink: 0,
4344
4535
  overflowX: "auto"
4345
4536
  },
4346
- children: insights.map((insight) => /* @__PURE__ */ jsx20(
4537
+ children: insights.map((insight) => /* @__PURE__ */ jsx22(
4347
4538
  "button",
4348
4539
  {
4349
4540
  onClick: () => setActiveId(insight.id),
@@ -4364,7 +4555,7 @@ var InsightTabs = memo6(function InsightTabs2({
4364
4555
  ))
4365
4556
  }
4366
4557
  ),
4367
- /* @__PURE__ */ jsx20("div", { style: { flex: 1, overflow: "auto" }, children: active?.render() })
4558
+ /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: "auto" }, children: active?.render() })
4368
4559
  ]
4369
4560
  }
4370
4561
  );
@@ -4373,7 +4564,7 @@ var InsightGrid = memo6(function InsightGrid2({
4373
4564
  insights
4374
4565
  }) {
4375
4566
  const cols = insights.length <= 2 ? 1 : 2;
4376
- return /* @__PURE__ */ jsx20(
4567
+ return /* @__PURE__ */ jsx22(
4377
4568
  "div",
4378
4569
  {
4379
4570
  style: {
@@ -4384,7 +4575,7 @@ var InsightGrid = memo6(function InsightGrid2({
4384
4575
  gap: 1,
4385
4576
  background: theme.border
4386
4577
  },
4387
- children: insights.map((insight) => /* @__PURE__ */ jsxs19(
4578
+ children: insights.map((insight) => /* @__PURE__ */ jsxs20(
4388
4579
  "div",
4389
4580
  {
4390
4581
  style: {
@@ -4394,7 +4585,7 @@ var InsightGrid = memo6(function InsightGrid2({
4394
4585
  overflow: "hidden"
4395
4586
  },
4396
4587
  children: [
4397
- /* @__PURE__ */ jsxs19(
4588
+ /* @__PURE__ */ jsxs20(
4398
4589
  "div",
4399
4590
  {
4400
4591
  style: {
@@ -4409,7 +4600,7 @@ var InsightGrid = memo6(function InsightGrid2({
4409
4600
  },
4410
4601
  children: [
4411
4602
  insight.name,
4412
- insight.summary && /* @__PURE__ */ jsx20(
4603
+ insight.summary && /* @__PURE__ */ jsx22(
4413
4604
  "span",
4414
4605
  {
4415
4606
  style: {
@@ -4424,7 +4615,7 @@ var InsightGrid = memo6(function InsightGrid2({
4424
4615
  ]
4425
4616
  }
4426
4617
  ),
4427
- /* @__PURE__ */ jsx20("div", { style: { flex: 1, overflow: "auto" }, children: insight.render() })
4618
+ /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: "auto" }, children: insight.render() })
4428
4619
  ]
4429
4620
  },
4430
4621
  insight.id
@@ -4434,17 +4625,17 @@ var InsightGrid = memo6(function InsightGrid2({
4434
4625
  });
4435
4626
 
4436
4627
  // src/components/CompactTimeline/CompactTimeline.tsx
4437
- import { memo as memo7, useState as useState11 } from "react";
4438
- import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
4628
+ import { memo as memo7, useState as useState13 } from "react";
4629
+ import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
4439
4630
  var CompactTimeline = memo7(function CompactTimeline2({
4440
4631
  snapshots,
4441
4632
  selectedIndex,
4442
4633
  defaultExpanded = false
4443
4634
  }) {
4444
- const [expanded, setExpanded] = useState11(defaultExpanded);
4635
+ const [expanded, setExpanded] = useState13(defaultExpanded);
4445
4636
  if (snapshots.length === 0) return null;
4446
- return /* @__PURE__ */ jsxs20("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
4447
- /* @__PURE__ */ jsxs20(
4637
+ return /* @__PURE__ */ jsxs21("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
4638
+ /* @__PURE__ */ jsxs21(
4448
4639
  "button",
4449
4640
  {
4450
4641
  onClick: () => setExpanded((e) => !e),
@@ -4464,13 +4655,13 @@ var CompactTimeline = memo7(function CompactTimeline2({
4464
4655
  letterSpacing: "0.5px"
4465
4656
  },
4466
4657
  children: [
4467
- /* @__PURE__ */ jsx21("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
4658
+ /* @__PURE__ */ jsx23("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
4468
4659
  "Timeline",
4469
- /* @__PURE__ */ jsxs20("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
4660
+ /* @__PURE__ */ jsxs21("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
4470
4661
  snapshots.length,
4471
4662
  " stages"
4472
4663
  ] }),
4473
- !expanded && /* @__PURE__ */ jsxs20(
4664
+ !expanded && /* @__PURE__ */ jsxs21(
4474
4665
  "div",
4475
4666
  {
4476
4667
  style: {
@@ -4481,7 +4672,7 @@ var CompactTimeline = memo7(function CompactTimeline2({
4481
4672
  marginLeft: 8
4482
4673
  },
4483
4674
  children: [
4484
- snapshots.map((snap, i) => /* @__PURE__ */ jsx21(
4675
+ snapshots.map((snap, i) => /* @__PURE__ */ jsx23(
4485
4676
  "div",
4486
4677
  {
4487
4678
  style: {
@@ -4496,7 +4687,7 @@ var CompactTimeline = memo7(function CompactTimeline2({
4496
4687
  },
4497
4688
  i
4498
4689
  )),
4499
- /* @__PURE__ */ jsx21(
4690
+ /* @__PURE__ */ jsx23(
4500
4691
  "div",
4501
4692
  {
4502
4693
  style: {
@@ -4514,7 +4705,7 @@ var CompactTimeline = memo7(function CompactTimeline2({
4514
4705
  ]
4515
4706
  }
4516
4707
  ),
4517
- expanded && /* @__PURE__ */ jsx21("div", { style: { padding: "0 12px 8px" }, children: /* @__PURE__ */ jsx21(
4708
+ expanded && /* @__PURE__ */ jsx23("div", { style: { padding: "0 12px 8px" }, children: /* @__PURE__ */ jsx23(
4518
4709
  GanttTimeline,
4519
4710
  {
4520
4711
  snapshots,
@@ -4525,21 +4716,21 @@ var CompactTimeline = memo7(function CompactTimeline2({
4525
4716
  });
4526
4717
 
4527
4718
  // src/components/ExplainableShell/ExplainableShell.tsx
4528
- import { Fragment as Fragment6, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
4719
+ import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
4529
4720
  var HLinePill = memo8(function HLinePill2({
4530
4721
  label,
4531
4722
  detail,
4532
4723
  expanded,
4533
4724
  onClick
4534
4725
  }) {
4535
- return /* @__PURE__ */ jsxs21("div", { style: {
4726
+ return /* @__PURE__ */ jsxs22("div", { style: {
4536
4727
  display: "flex",
4537
4728
  alignItems: "center",
4538
4729
  gap: 0,
4539
4730
  padding: "0"
4540
4731
  }, children: [
4541
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, height: 1, background: theme.border } }),
4542
- /* @__PURE__ */ jsxs21(
4732
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, height: 1, background: theme.border } }),
4733
+ /* @__PURE__ */ jsxs22(
4543
4734
  "button",
4544
4735
  {
4545
4736
  onClick,
@@ -4563,13 +4754,13 @@ var HLinePill = memo8(function HLinePill2({
4563
4754
  transition: "color 0.15s ease"
4564
4755
  },
4565
4756
  children: [
4566
- /* @__PURE__ */ jsx22("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
4757
+ /* @__PURE__ */ jsx24("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
4567
4758
  label,
4568
- detail && /* @__PURE__ */ jsx22("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
4759
+ detail && /* @__PURE__ */ jsx24("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
4569
4760
  ]
4570
4761
  }
4571
4762
  ),
4572
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, height: 1, background: theme.border } })
4763
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, height: 1, background: theme.border } })
4573
4764
  ] });
4574
4765
  });
4575
4766
  var VLinePill = memo8(function VLinePill2({
@@ -4579,15 +4770,15 @@ var VLinePill = memo8(function VLinePill2({
4579
4770
  onClick
4580
4771
  }) {
4581
4772
  const arrow = side === "right" ? expanded ? "\u25B6" : "\u25C0" : expanded ? "\u25C0" : "\u25B6";
4582
- return /* @__PURE__ */ jsxs21("div", { style: {
4773
+ return /* @__PURE__ */ jsxs22("div", { style: {
4583
4774
  display: "flex",
4584
4775
  flexDirection: "column",
4585
4776
  alignItems: "center",
4586
4777
  gap: 0,
4587
4778
  padding: "0"
4588
4779
  }, children: [
4589
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, width: 1, background: theme.border } }),
4590
- /* @__PURE__ */ jsxs21(
4780
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, width: 1, background: theme.border } }),
4781
+ /* @__PURE__ */ jsxs22(
4591
4782
  "button",
4592
4783
  {
4593
4784
  onClick,
@@ -4612,12 +4803,12 @@ var VLinePill = memo8(function VLinePill2({
4612
4803
  transition: "color 0.15s ease"
4613
4804
  },
4614
4805
  children: [
4615
- /* @__PURE__ */ jsx22("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
4806
+ /* @__PURE__ */ jsx24("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
4616
4807
  label
4617
4808
  ]
4618
4809
  }
4619
4810
  ),
4620
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, width: 1, background: theme.border } })
4811
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, width: 1, background: theme.border } })
4621
4812
  ] });
4622
4813
  });
4623
4814
  function detectKeyedSteps(data) {
@@ -4654,9 +4845,9 @@ function KeyedRecorderView({
4654
4845
  snapshots,
4655
4846
  selectedIndex
4656
4847
  }) {
4657
- const [showAggregate, setShowAggregate] = useState12(false);
4658
- const detected = useMemo12(() => detectKeyedSteps(data), [data]);
4659
- const visibleKeys = useMemo12(() => {
4848
+ const [showAggregate, setShowAggregate] = useState14(false);
4849
+ const detected = useMemo13(() => detectKeyedSteps(data), [data]);
4850
+ const visibleKeys = useMemo13(() => {
4660
4851
  const keys = /* @__PURE__ */ new Set();
4661
4852
  for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
4662
4853
  const snap = snapshots[i];
@@ -4671,7 +4862,7 @@ function KeyedRecorderView({
4671
4862
  }, [snapshots, selectedIndex, detected?.keyType]);
4672
4863
  const isAtEnd = selectedIndex >= snapshots.length - 1;
4673
4864
  if (!detected) {
4674
- return /* @__PURE__ */ jsx22("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
4865
+ return /* @__PURE__ */ jsx24("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
4675
4866
  }
4676
4867
  const steps = detected.steps;
4677
4868
  const hints = extractRenderHints(data);
@@ -4685,13 +4876,13 @@ function KeyedRecorderView({
4685
4876
  }
4686
4877
  }
4687
4878
  const grandTotal = hints?.grandTotal ?? 0;
4688
- return /* @__PURE__ */ jsxs21("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
4689
- description && /* @__PURE__ */ jsx22("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
4690
- /* @__PURE__ */ jsxs21("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
4879
+ return /* @__PURE__ */ jsxs22("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
4880
+ description && /* @__PURE__ */ jsx24("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
4881
+ /* @__PURE__ */ jsxs22("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
4691
4882
  preferredOperation === "aggregate" ? (
4692
4883
  /* AGGREGATE: collect silently during scrub, button at end to reveal total */
4693
- /* @__PURE__ */ jsxs21(Fragment6, { children: [
4694
- isAtEnd ? /* @__PURE__ */ jsx22("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ jsx22(
4884
+ /* @__PURE__ */ jsxs22(Fragment6, { children: [
4885
+ isAtEnd ? /* @__PURE__ */ jsx24("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ jsx24(
4695
4886
  "button",
4696
4887
  {
4697
4888
  onClick: () => setShowAggregate(true),
@@ -4709,35 +4900,35 @@ function KeyedRecorderView({
4709
4900
  },
4710
4901
  children: "Aggregate \u2014 Show Grand Total"
4711
4902
  }
4712
- ) : /* @__PURE__ */ jsxs21("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
4713
- /* @__PURE__ */ jsx22("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Aggregate \u2014 grand total" }),
4714
- numFieldKey && /* @__PURE__ */ jsxs21("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
4903
+ ) : /* @__PURE__ */ jsxs22("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
4904
+ /* @__PURE__ */ jsx24("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Aggregate \u2014 grand total" }),
4905
+ numFieldKey && /* @__PURE__ */ jsxs22("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
4715
4906
  grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1),
4716
- /* @__PURE__ */ jsxs21("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
4907
+ /* @__PURE__ */ jsxs22("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
4717
4908
  numFieldKey,
4718
4909
  " \xB7 ",
4719
4910
  allKeys.length,
4720
4911
  " steps"
4721
4912
  ] })
4722
4913
  ] })
4723
- ] }) }) : /* @__PURE__ */ jsxs21("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.textMuted} 6%, transparent)`, borderRadius: 6, marginBottom: 16, border: `1px dashed ${theme.border}` }, children: [
4724
- /* @__PURE__ */ jsx22("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
4725
- /* @__PURE__ */ jsxs21("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
4914
+ ] }) }) : /* @__PURE__ */ jsxs22("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.textMuted} 6%, transparent)`, borderRadius: 6, marginBottom: 16, border: `1px dashed ${theme.border}` }, children: [
4915
+ /* @__PURE__ */ jsx24("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
4916
+ /* @__PURE__ */ jsxs22("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
4726
4917
  visibleEntries.length,
4727
4918
  " of ",
4728
4919
  allKeys.length,
4729
4920
  " steps collected. Scrub to end to aggregate."
4730
4921
  ] })
4731
4922
  ] }),
4732
- /* @__PURE__ */ jsx22("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4923
+ /* @__PURE__ */ jsx24("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4733
4924
  ] })
4734
4925
  ) : preferredOperation === "accumulate" ? (
4735
4926
  /* ACCUMULATE: running total grows with slider — IS the total at end, no button */
4736
- /* @__PURE__ */ jsxs21(Fragment6, { children: [
4737
- numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ jsxs21("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
4738
- /* @__PURE__ */ jsx22("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4, fontWeight: 600 }, children: "Accumulate \u2014 running total up to this step" }),
4739
- /* @__PURE__ */ jsx22("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
4740
- /* @__PURE__ */ jsxs21("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
4927
+ /* @__PURE__ */ jsxs22(Fragment6, { children: [
4928
+ numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ jsxs22("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
4929
+ /* @__PURE__ */ jsx24("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4, fontWeight: 600 }, children: "Accumulate \u2014 running total up to this step" }),
4930
+ /* @__PURE__ */ jsx24("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
4931
+ /* @__PURE__ */ jsxs22("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
4741
4932
  numFieldKey,
4742
4933
  " \xB7 ",
4743
4934
  visibleEntries.length,
@@ -4746,23 +4937,23 @@ function KeyedRecorderView({
4746
4937
  " steps"
4747
4938
  ] })
4748
4939
  ] }),
4749
- /* @__PURE__ */ jsx22("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4940
+ /* @__PURE__ */ jsx24("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4750
4941
  ] })
4751
4942
  ) : (
4752
4943
  /* TRANSLATE: per-step entries prominent, no totals */
4753
- /* @__PURE__ */ jsx22("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
4944
+ /* @__PURE__ */ jsx24("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
4754
4945
  ),
4755
4946
  visibleEntries.map((key) => {
4756
4947
  const entry = steps[key];
4757
4948
  const label = entry.stageName ?? key;
4758
4949
  const numVal = numFieldKey ? entry[numFieldKey] : void 0;
4759
- return /* @__PURE__ */ jsxs21("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
4760
- /* @__PURE__ */ jsx22("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
4761
- /* @__PURE__ */ jsx22("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
4762
- numVal !== void 0 && /* @__PURE__ */ jsx22("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
4950
+ return /* @__PURE__ */ jsxs22("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
4951
+ /* @__PURE__ */ jsx24("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
4952
+ /* @__PURE__ */ jsx24("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
4953
+ numVal !== void 0 && /* @__PURE__ */ jsx24("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
4763
4954
  ] }, key);
4764
4955
  }),
4765
- visibleEntries.length === 0 && /* @__PURE__ */ jsx22("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
4956
+ visibleEntries.length === 0 && /* @__PURE__ */ jsx24("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
4766
4957
  ] })
4767
4958
  ] });
4768
4959
  }
@@ -4770,7 +4961,6 @@ var DetailsContent = memo8(function DetailsContent2({
4770
4961
  snapshots,
4771
4962
  selectedIndex,
4772
4963
  narrativeEntries,
4773
- narrative,
4774
4964
  size,
4775
4965
  fillHeight,
4776
4966
  extraViews
@@ -4779,27 +4969,27 @@ var DetailsContent = memo8(function DetailsContent2({
4779
4969
  {
4780
4970
  id: "memory",
4781
4971
  name: "Memory",
4782
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ jsx22(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
4972
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ jsx24(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
4783
4973
  },
4784
4974
  {
4785
4975
  id: "narrative",
4786
4976
  name: "Narrative",
4787
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ jsx22(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, narrative, size, style: fillHeight ? { height: "100%" } : void 0 })
4977
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ jsx24(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, size, style: fillHeight ? { height: "100%" } : void 0 })
4788
4978
  }
4789
4979
  ];
4790
4980
  const allViews = [...builtInViews, ...extraViews ?? []];
4791
- const [activeViewId, setActiveViewId] = useState12(allViews[0]?.id ?? "memory");
4981
+ const [activeViewId, setActiveViewId] = useState14(allViews[0]?.id ?? "memory");
4792
4982
  const viewIds = allViews.map((v2) => v2.id).join(",");
4793
- useEffect8(() => {
4983
+ useEffect9(() => {
4794
4984
  if (!allViews.find((v2) => v2.id === activeViewId)) {
4795
4985
  setActiveViewId(allViews[0]?.id ?? "memory");
4796
4986
  }
4797
4987
  }, [viewIds]);
4798
4988
  const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
4799
- return /* @__PURE__ */ jsxs21("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
4800
- /* @__PURE__ */ jsx22("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
4989
+ return /* @__PURE__ */ jsxs22("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
4990
+ /* @__PURE__ */ jsx24("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
4801
4991
  const active = view.id === activeViewId;
4802
- return /* @__PURE__ */ jsx22(
4992
+ return /* @__PURE__ */ jsx24(
4803
4993
  "button",
4804
4994
  {
4805
4995
  onClick: () => setActiveViewId(view.id),
@@ -4823,7 +5013,7 @@ var DetailsContent = memo8(function DetailsContent2({
4823
5013
  view.id
4824
5014
  );
4825
5015
  }) }),
4826
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
5016
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
4827
5017
  ] });
4828
5018
  });
4829
5019
  function resolveSubflowLevel(parentSpec, parentSnapshots, subflowNodeName, narrativeEntries) {
@@ -4907,19 +5097,18 @@ var RightPanel = memo8(function RightPanel2({
4907
5097
  activeTab,
4908
5098
  allTabs,
4909
5099
  activeNarrativeEntries,
4910
- activeNarrative,
4911
5100
  recorderViews,
4912
5101
  autoRecorderViews,
4913
5102
  size,
4914
5103
  onNavigateToStage
4915
5104
  }) {
4916
- return /* @__PURE__ */ jsxs21(Fragment6, { children: [
4917
- /* @__PURE__ */ jsx22("div", { style: {
5105
+ return /* @__PURE__ */ jsxs22(Fragment6, { children: [
5106
+ /* @__PURE__ */ jsx24("div", { style: {
4918
5107
  display: "flex",
4919
5108
  borderBottom: `1px solid ${theme.border}`,
4920
5109
  flexShrink: 0,
4921
5110
  background: theme.bgSecondary
4922
- }, children: ["insights", "what"].map((m) => /* @__PURE__ */ jsx22(
5111
+ }, children: ["insights", "what"].map((m) => /* @__PURE__ */ jsx24(
4923
5112
  "button",
4924
5113
  {
4925
5114
  onClick: () => onModeChange(m),
@@ -4941,7 +5130,7 @@ var RightPanel = memo8(function RightPanel2({
4941
5130
  },
4942
5131
  m
4943
5132
  )) }),
4944
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: "hidden" }, children: mode === "insights" ? /* @__PURE__ */ jsx22(
5133
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: "hidden" }, children: mode === "insights" ? /* @__PURE__ */ jsx24(
4945
5134
  InsightPanel,
4946
5135
  {
4947
5136
  mode: "tabs",
@@ -4950,16 +5139,16 @@ var RightPanel = memo8(function RightPanel2({
4950
5139
  id: tab.id,
4951
5140
  name: insightName(tab.name),
4952
5141
  render: () => {
4953
- if (tab.id === "narrative") return /* @__PURE__ */ jsx22(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, runtimeSnapshot, spec, size, style: { height: "100%" } });
5142
+ if (tab.id === "narrative") return /* @__PURE__ */ jsx24(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, runtimeSnapshot, spec, size, style: { height: "100%" } });
4954
5143
  const customView = recorderViews?.find((v2) => v2.id === tab.id);
4955
5144
  if (customView?.render) return customView.render({ snapshots, selectedIndex });
4956
5145
  const autoView = autoRecorderViews.find((v2) => v2.id === tab.id);
4957
- if (autoView) return /* @__PURE__ */ jsx22(KeyedRecorderView, { data: autoView.data, description: autoView.description, preferredOperation: autoView.preferredOperation, snapshots, selectedIndex });
5146
+ if (autoView) return /* @__PURE__ */ jsx24(KeyedRecorderView, { data: autoView.data, description: autoView.description, preferredOperation: autoView.preferredOperation, snapshots, selectedIndex });
4958
5147
  return null;
4959
5148
  }
4960
5149
  }))
4961
5150
  }
4962
- ) : /* @__PURE__ */ jsx22(
5151
+ ) : /* @__PURE__ */ jsx24(
4963
5152
  InspectorPanel,
4964
5153
  {
4965
5154
  snapshots,
@@ -4981,17 +5170,6 @@ function insightName(name) {
4981
5170
  };
4982
5171
  return map[name] ?? name;
4983
5172
  }
4984
- function defaultRenderFlowchart({ spec: s, snapshots: snaps, selectedIndex, onNodeClick }) {
4985
- return /* @__PURE__ */ jsx22(
4986
- TracedFlowchartView,
4987
- {
4988
- spec: s,
4989
- snapshots: snaps,
4990
- snapshotIndex: selectedIndex,
4991
- onNodeClick
4992
- }
4993
- );
4994
- }
4995
5173
  function ExplainableShell({
4996
5174
  snapshots: snapshotsProp,
4997
5175
  runtimeSnapshot,
@@ -4999,7 +5177,6 @@ function ExplainableShell({
4999
5177
  title,
5000
5178
  resultData: resultDataProp,
5001
5179
  logs = [],
5002
- narrative: narrativeProp,
5003
5180
  narrativeEntries,
5004
5181
  tabs = ["result", "explainable"],
5005
5182
  defaultTab,
@@ -5009,36 +5186,58 @@ function ExplainableShell({
5009
5186
  defaultExpanded,
5010
5187
  recorderViews,
5011
5188
  renderFlowchart,
5189
+ showStageId = false,
5190
+ traceGraph,
5191
+ runtimeOverlay,
5012
5192
  size = "default",
5013
5193
  unstyled = false,
5014
5194
  className,
5015
5195
  style
5016
5196
  }) {
5017
- const derivedFromRuntime = useMemo12(() => {
5197
+ const derivedFromRuntime = useMemo13(() => {
5018
5198
  if (!runtimeSnapshot) return null;
5019
5199
  try {
5020
5200
  const snaps = toVisualizationSnapshots(runtimeSnapshot, narrativeEntries);
5021
- const narr = [];
5022
- for (const snap of snaps) {
5023
- const lines = (snap.narrative ?? "").split("\n").filter(Boolean);
5024
- narr.push(...lines);
5025
- }
5026
- return { snapshots: snaps, resultData: runtimeSnapshot.sharedState, narrative: narr };
5201
+ return { snapshots: snaps, resultData: runtimeSnapshot.sharedState };
5027
5202
  } catch {
5028
5203
  return null;
5029
5204
  }
5030
5205
  }, [runtimeSnapshot, narrativeEntries]);
5031
5206
  const snapshots = snapshotsProp ?? derivedFromRuntime?.snapshots ?? [];
5032
5207
  const resultData = resultDataProp ?? derivedFromRuntime?.resultData ?? null;
5033
- const narrative = narrativeProp ?? derivedFromRuntime?.narrative;
5034
- const effectiveRenderFlowchart = renderFlowchart ?? (spec ? defaultRenderFlowchart : void 0);
5208
+ const tracedFlowRenderer = useMemo13(() => {
5209
+ if (!traceGraph) return void 0;
5210
+ return ({ selectedIndex, snapshots: snapshots2, onNodeClick }) => {
5211
+ const activeRsid = snapshots2[selectedIndex]?.runtimeStageId;
5212
+ let overlayIdx = selectedIndex;
5213
+ if (activeRsid && runtimeOverlay) {
5214
+ const i = runtimeOverlay.executionOrder.findIndex(
5215
+ (s) => s.runtimeStageId === activeRsid
5216
+ );
5217
+ if (i >= 0) overlayIdx = i;
5218
+ }
5219
+ return /* @__PURE__ */ jsx24(
5220
+ TracedFlow,
5221
+ {
5222
+ graph: traceGraph,
5223
+ overlay: runtimeOverlay ?? void 0,
5224
+ scrubIndex: overlayIdx,
5225
+ onNodeClick: (stageId) => onNodeClick?.(stageId),
5226
+ onSubflowChange: (mountId) => {
5227
+ if (mountId !== null) onNodeClick?.(mountId);
5228
+ }
5229
+ }
5230
+ );
5231
+ };
5232
+ }, [traceGraph, runtimeOverlay]);
5233
+ const effectiveRenderFlowchart = renderFlowchart ?? tracedFlowRenderer;
5035
5234
  const leftLabel = panelLabels?.topology ?? "Topology";
5036
5235
  const rightLabel = panelLabels?.details ?? "Details";
5037
5236
  const bottomLabel = panelLabels?.timeline ?? "Timeline";
5038
- const shellRef = useRef7(null);
5039
- const [isNarrow, setIsNarrow] = useState12(false);
5040
- const [isMedium, setIsMedium] = useState12(false);
5041
- useEffect8(() => {
5237
+ const shellRef = useRef9(null);
5238
+ const [isNarrow, setIsNarrow] = useState14(false);
5239
+ const [isMedium, setIsMedium] = useState14(false);
5240
+ useEffect9(() => {
5042
5241
  const el = shellRef.current;
5043
5242
  if (!el) return;
5044
5243
  const ro = new ResizeObserver(([entry]) => {
@@ -5050,14 +5249,14 @@ function ExplainableShell({
5050
5249
  ro.observe(el);
5051
5250
  return () => ro.disconnect();
5052
5251
  }, []);
5053
- const autoRecorderViews = useMemo12(() => {
5252
+ const autoRecorderViews = useMemo13(() => {
5054
5253
  const recorders = runtimeSnapshot?.recorders;
5055
5254
  if (!recorders?.length) return [];
5056
5255
  const explicitIds = new Set((recorderViews ?? []).map((v2) => v2.id));
5057
5256
  return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, description: r.description, preferredOperation: r.preferredOperation, data: r.data }));
5058
5257
  }, [runtimeSnapshot, recorderViews]);
5059
- const hasNarrative = !!(narrative?.length || narrativeEntries?.length);
5060
- const allTabs = useMemo12(() => {
5258
+ const hasNarrative = !!narrativeEntries?.length;
5259
+ const allTabs = useMemo13(() => {
5061
5260
  const tabs2 = [
5062
5261
  { id: "result", name: "Result", description: "Final output and console logs" },
5063
5262
  { id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
@@ -5076,38 +5275,38 @@ function ExplainableShell({
5076
5275
  }, [hasNarrative, recorderViews, autoRecorderViews, hideTabsProp]);
5077
5276
  const validTabIds = new Set(allTabs.map((t) => t.id));
5078
5277
  const resolvedDefault = defaultTab && validTabIds.has(defaultTab) ? defaultTab : allTabs[0]?.id ?? "result";
5079
- const [activeTab, setActiveTab] = useState12(resolvedDefault);
5080
- const [snapshotIdx, setSnapshotIdx] = useState12(0);
5081
- const [drillDownStack, setDrillDownStack] = useState12([]);
5082
- const [rightExpanded, setRightExpanded] = useState12(defaultExpanded?.details ?? true);
5083
- const [rightPanelMode, setRightPanelMode] = useState12("insights");
5084
- const [leftExpanded, setLeftExpanded] = useState12(defaultExpanded?.topology ?? false);
5085
- const [timelineExpanded, setTimelineExpanded] = useState12(defaultExpanded?.timeline ?? false);
5086
- useEffect8(() => {
5278
+ const [activeTab, setActiveTab] = useState14(resolvedDefault);
5279
+ const [snapshotIdx, setSnapshotIdx] = useState14(0);
5280
+ const [drillDownStack, setDrillDownStack] = useState14([]);
5281
+ const [rightExpanded, setRightExpanded] = useState14(defaultExpanded?.details ?? true);
5282
+ const [rightPanelMode, setRightPanelMode] = useState14("insights");
5283
+ const [leftExpanded, setLeftExpanded] = useState14(defaultExpanded?.topology ?? false);
5284
+ const [timelineExpanded, setTimelineExpanded] = useState14(defaultExpanded?.timeline ?? false);
5285
+ useEffect9(() => {
5087
5286
  if (isNarrow) {
5088
5287
  setLeftExpanded(false);
5089
5288
  setRightExpanded(false);
5090
5289
  setTimelineExpanded(false);
5091
5290
  }
5092
5291
  }, [isNarrow]);
5093
- const triggerReflow = useCallback7(() => {
5292
+ const triggerReflow = useCallback9(() => {
5094
5293
  requestAnimationFrame(() => window.dispatchEvent(new Event("resize")));
5095
5294
  setTimeout(() => window.dispatchEvent(new Event("resize")), 320);
5096
5295
  }, []);
5097
- const toggleLeft = useCallback7((v2) => {
5296
+ const toggleLeft = useCallback9((v2) => {
5098
5297
  setLeftExpanded(v2);
5099
5298
  triggerReflow();
5100
5299
  }, [triggerReflow]);
5101
- const toggleRight = useCallback7((v2) => {
5300
+ const toggleRight = useCallback9((v2) => {
5102
5301
  setRightExpanded(v2);
5103
5302
  triggerReflow();
5104
5303
  }, [triggerReflow]);
5105
- const toggleTimeline = useCallback7(() => {
5304
+ const toggleTimeline = useCallback9(() => {
5106
5305
  setTimelineExpanded((p) => !p);
5107
5306
  triggerReflow();
5108
5307
  }, [triggerReflow]);
5109
5308
  const isInSubflow = drillDownStack.length > 0;
5110
- const currentLevel = useMemo12(() => {
5309
+ const currentLevel = useMemo13(() => {
5111
5310
  if (drillDownStack.length > 0) {
5112
5311
  const top = drillDownStack[drillDownStack.length - 1];
5113
5312
  return { spec: top.spec, snapshots: top.snapshots };
@@ -5117,35 +5316,31 @@ function ExplainableShell({
5117
5316
  const activeSnapshots = currentLevel.snapshots;
5118
5317
  const activeSpec = currentLevel.spec;
5119
5318
  const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
5120
- const activeNarrative = useMemo12(() => {
5121
- if (!isInSubflow) return narrative;
5122
- const lines = [];
5123
- for (const snap of activeSnapshots) {
5124
- const stageLines = (snap.narrative ?? "").split("\n").filter(Boolean);
5125
- lines.push(...stageLines);
5126
- }
5127
- return lines.length > 0 ? lines : void 0;
5128
- }, [isInSubflow, narrative, activeSnapshots]);
5129
5319
  const activeNarrativeEntries = isInSubflow ? void 0 : narrativeEntries;
5130
- const breadcrumbs = useMemo12(() => {
5320
+ const breadcrumbs = useMemo13(() => {
5131
5321
  const root = { label: title || "Flowchart", spec, description: spec?.description };
5132
5322
  return [root, ...drillDownStack.map((e) => ({ label: e.label, spec: e.spec, description: void 0 }))];
5133
5323
  }, [spec, title, drillDownStack]);
5134
- const showTreeSidebar = useMemo12(() => !!spec && hasSubflowNodes(spec), [spec]);
5135
- const rootOverlay = useMemo12(() => {
5324
+ const showTreeSidebar = useMemo13(() => {
5325
+ if (traceGraph?.nodes?.length) {
5326
+ return traceGraph.nodes.some((n) => n.data?.isSubflow === true);
5327
+ }
5328
+ return !!spec && hasSubflowNodes(spec);
5329
+ }, [traceGraph, spec]);
5330
+ const rootOverlay = useMemo13(() => {
5136
5331
  if (isInSubflow || !snapshots.length) return { activeStage: void 0, doneStages: void 0 };
5137
5332
  const doneStages = new Set(snapshots.slice(0, safeIdx).map((s) => s.stageLabel));
5138
5333
  const activeStage = snapshots[safeIdx]?.stageLabel ?? null;
5139
5334
  return { activeStage, doneStages };
5140
5335
  }, [isInSubflow, snapshots, safeIdx]);
5141
- const handleTabChange = useCallback7((tab) => {
5336
+ const handleTabChange = useCallback9((tab) => {
5142
5337
  setActiveTab(tab);
5143
5338
  setDrillDownStack([]);
5144
5339
  }, []);
5145
- const handleSnapshotChange = useCallback7((idx) => {
5340
+ const handleSnapshotChange = useCallback9((idx) => {
5146
5341
  if (typeof idx === "number") setSnapshotIdx(idx);
5147
5342
  }, []);
5148
- const handleDrillDown = useCallback7(
5343
+ const handleDrillDown = useCallback9(
5149
5344
  (nodeName) => {
5150
5345
  if (!activeSpec) return;
5151
5346
  const entry = resolveSubflowLevel(activeSpec, activeSnapshots, nodeName, narrativeEntries);
@@ -5156,14 +5351,14 @@ function ExplainableShell({
5156
5351
  },
5157
5352
  [activeSpec, activeSnapshots, narrativeEntries, snapshotIdx]
5158
5353
  );
5159
- const handleBreadcrumbNavigate = useCallback7((level) => {
5354
+ const handleBreadcrumbNavigate = useCallback9((level) => {
5160
5355
  setDrillDownStack((prev) => {
5161
5356
  const popped = level === 0 ? prev[0] : prev[level];
5162
5357
  if (popped) setSnapshotIdx(popped.parentSnapshotIdx);
5163
5358
  return level === 0 ? [] : prev.slice(0, level);
5164
5359
  });
5165
5360
  }, []);
5166
- const handleNodeClick = useCallback7(
5361
+ const handleNodeClick = useCallback9(
5167
5362
  (indexOrId) => {
5168
5363
  if (typeof indexOrId === "number") {
5169
5364
  setSnapshotIdx(indexOrId);
@@ -5181,7 +5376,7 @@ function ExplainableShell({
5181
5376
  },
5182
5377
  [activeSpec, activeSnapshots, handleDrillDown]
5183
5378
  );
5184
- const handleTreeNodeSelect = useCallback7(
5379
+ const handleTreeNodeSelect = useCallback9(
5185
5380
  (name, isSubflow) => {
5186
5381
  if (isSubflow && spec) {
5187
5382
  setDrillDownStack([]);
@@ -5200,31 +5395,31 @@ function ExplainableShell({
5200
5395
  );
5201
5396
  const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
5202
5397
  if (unstyled) {
5203
- return /* @__PURE__ */ jsxs21("div", { className, style, "data-fp": "explainable-shell", children: [
5204
- /* @__PURE__ */ jsx22("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ jsx22("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
5205
- /* @__PURE__ */ jsxs21("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
5206
- activeTab === "result" && /* @__PURE__ */ jsx22(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
5207
- (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ jsxs21(Fragment6, { children: [
5208
- /* @__PURE__ */ jsx22(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
5209
- isInSubflow && /* @__PURE__ */ jsx22(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5210
- activeSpec && effectiveRenderFlowchart?.({ spec: activeSpec, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick }),
5211
- /* @__PURE__ */ jsx22(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
5212
- /* @__PURE__ */ jsx22(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, unstyled: true }),
5213
- /* @__PURE__ */ jsx22(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
5398
+ return /* @__PURE__ */ jsxs22("div", { className, style, "data-fp": "explainable-shell", children: [
5399
+ /* @__PURE__ */ jsx24("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ jsx24("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
5400
+ /* @__PURE__ */ jsxs22("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
5401
+ activeTab === "result" && /* @__PURE__ */ jsx24(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
5402
+ (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ jsxs22(Fragment6, { children: [
5403
+ /* @__PURE__ */ jsx24(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
5404
+ isInSubflow && /* @__PURE__ */ jsx24(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5405
+ activeSpec && effectiveRenderFlowchart?.({ spec: activeSpec, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId }),
5406
+ /* @__PURE__ */ jsx24(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
5407
+ /* @__PURE__ */ jsx24(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
5408
+ /* @__PURE__ */ jsx24(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
5214
5409
  ] })
5215
5410
  ] })
5216
5411
  ] });
5217
5412
  }
5218
5413
  const showTopology = !!effectiveRenderFlowchart && !!activeSpec;
5219
- const detailsContent = useMemo12(() => {
5414
+ const detailsContent = useMemo13(() => {
5220
5415
  if (activeTab === "result") {
5221
- return /* @__PURE__ */ jsx22(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
5416
+ return /* @__PURE__ */ jsx24(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
5222
5417
  }
5223
5418
  if (activeTab === "memory") {
5224
- return /* @__PURE__ */ jsx22(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
5419
+ return /* @__PURE__ */ jsx24(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
5225
5420
  }
5226
5421
  if (activeTab === "narrative") {
5227
- return /* @__PURE__ */ jsx22(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, size, style: { height: "100%" } });
5422
+ return /* @__PURE__ */ jsx24(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, size, style: { height: "100%" } });
5228
5423
  }
5229
5424
  const customView = recorderViews?.find((v2) => v2.id === activeTab);
5230
5425
  if (customView?.render) {
@@ -5232,7 +5427,7 @@ function ExplainableShell({
5232
5427
  }
5233
5428
  const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
5234
5429
  if (autoView) {
5235
- return /* @__PURE__ */ jsx22(
5430
+ return /* @__PURE__ */ jsx24(
5236
5431
  KeyedRecorderView,
5237
5432
  {
5238
5433
  data: autoView.data,
@@ -5244,9 +5439,9 @@ function ExplainableShell({
5244
5439
  );
5245
5440
  }
5246
5441
  return null;
5247
- }, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, activeNarrative, recorderViews, autoRecorderViews]);
5248
- const detailsPanel = /* @__PURE__ */ jsxs21("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
5249
- /* @__PURE__ */ jsx22("div", { style: {
5442
+ }, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, recorderViews, autoRecorderViews]);
5443
+ const detailsPanel = /* @__PURE__ */ jsxs22("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
5444
+ /* @__PURE__ */ jsx24("div", { style: {
5250
5445
  display: "flex",
5251
5446
  borderBottom: `1px solid ${theme.border}`,
5252
5447
  background: theme.bgSecondary,
@@ -5254,7 +5449,7 @@ function ExplainableShell({
5254
5449
  overflowX: "auto"
5255
5450
  }, children: allTabs.map((tab) => {
5256
5451
  const active = tab.id === activeTab;
5257
- return /* @__PURE__ */ jsx22(
5452
+ return /* @__PURE__ */ jsx24(
5258
5453
  "button",
5259
5454
  {
5260
5455
  onClick: () => handleTabChange(tab.id),
@@ -5278,9 +5473,9 @@ function ExplainableShell({
5278
5473
  tab.id
5279
5474
  );
5280
5475
  }) }),
5281
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
5476
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
5282
5477
  ] });
5283
- return /* @__PURE__ */ jsxs21(
5478
+ return /* @__PURE__ */ jsxs22(
5284
5479
  "div",
5285
5480
  {
5286
5481
  ref: shellRef,
@@ -5298,7 +5493,7 @@ function ExplainableShell({
5298
5493
  },
5299
5494
  "data-fp": "explainable-shell",
5300
5495
  children: [
5301
- /* @__PURE__ */ jsx22(
5496
+ /* @__PURE__ */ jsx24(
5302
5497
  TimeTravelControls,
5303
5498
  {
5304
5499
  snapshots: activeSnapshots,
@@ -5307,57 +5502,59 @@ function ExplainableShell({
5307
5502
  size
5308
5503
  }
5309
5504
  ),
5310
- isInSubflow && /* @__PURE__ */ jsx22(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5311
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
5505
+ isInSubflow && /* @__PURE__ */ jsx24(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5506
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
5312
5507
  /* ── Mobile: stacked vertical ── */
5313
- /* @__PURE__ */ jsxs21(Fragment6, { children: [
5314
- showTopology && /* @__PURE__ */ jsx22("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
5508
+ /* @__PURE__ */ jsxs22(Fragment6, { children: [
5509
+ showTopology && /* @__PURE__ */ jsx24("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
5315
5510
  spec: activeSpec,
5316
5511
  snapshots: activeSnapshots,
5317
5512
  selectedIndex: safeIdx,
5318
- onNodeClick: handleNodeClick
5513
+ onNodeClick: handleNodeClick,
5514
+ showStageId
5319
5515
  }) }),
5320
- showTreeSidebar && /* @__PURE__ */ jsxs21(Fragment6, { children: [
5321
- /* @__PURE__ */ jsx22(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
5322
- leftExpanded && /* @__PURE__ */ jsx22("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ jsx22(
5516
+ showTreeSidebar && /* @__PURE__ */ jsxs22(Fragment6, { children: [
5517
+ /* @__PURE__ */ jsx24(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
5518
+ leftExpanded && /* @__PURE__ */ jsx24("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ jsx24(
5323
5519
  SubflowTree,
5324
5520
  {
5325
- spec,
5521
+ graph: traceGraph ?? { nodes: [], edges: [] },
5326
5522
  activeStage: rootOverlay.activeStage,
5327
5523
  doneStages: rootOverlay.doneStages,
5328
5524
  onNodeSelect: handleTreeNodeSelect
5329
5525
  }
5330
5526
  ) })
5331
5527
  ] }),
5332
- /* @__PURE__ */ jsx22(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
5333
- rightExpanded && /* @__PURE__ */ jsx22("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
5334
- /* @__PURE__ */ jsx22(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
5335
- timelineExpanded && /* @__PURE__ */ jsx22("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx22(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
5528
+ /* @__PURE__ */ jsx24(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
5529
+ rightExpanded && /* @__PURE__ */ jsx24("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
5530
+ /* @__PURE__ */ jsx24(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
5531
+ timelineExpanded && /* @__PURE__ */ jsx24("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx24(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
5336
5532
  ] })
5337
5533
  ) : (
5338
5534
  /* ── Desktop: two-column — Flowchart | Right Panel ── */
5339
- /* @__PURE__ */ jsxs21(Fragment6, { children: [
5340
- /* @__PURE__ */ jsxs21("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
5341
- showTreeSidebar && (leftExpanded ? /* @__PURE__ */ jsxs21("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
5342
- /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ jsx22(
5535
+ /* @__PURE__ */ jsxs22(Fragment6, { children: [
5536
+ /* @__PURE__ */ jsxs22("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
5537
+ showTreeSidebar && (leftExpanded ? /* @__PURE__ */ jsxs22("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
5538
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ jsx24(
5343
5539
  SubflowTree,
5344
5540
  {
5345
- spec,
5541
+ graph: traceGraph ?? { nodes: [], edges: [] },
5346
5542
  activeStage: rootOverlay.activeStage,
5347
5543
  doneStages: rootOverlay.doneStages,
5348
5544
  onNodeSelect: handleTreeNodeSelect
5349
5545
  }
5350
5546
  ) }),
5351
- /* @__PURE__ */ jsx22(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
5352
- ] }) : /* @__PURE__ */ jsx22(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
5353
- showTopology ? /* @__PURE__ */ jsx22("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
5547
+ /* @__PURE__ */ jsx24(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
5548
+ ] }) : /* @__PURE__ */ jsx24(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
5549
+ showTopology ? /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
5354
5550
  spec: activeSpec,
5355
5551
  snapshots: activeSnapshots,
5356
5552
  selectedIndex: safeIdx,
5357
- onNodeClick: handleNodeClick
5358
- }) }) : /* @__PURE__ */ jsx22("div", { style: { flex: 1 } }),
5359
- /* @__PURE__ */ jsx22(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
5360
- rightExpanded && /* @__PURE__ */ jsx22("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsx22(
5553
+ onNodeClick: handleNodeClick,
5554
+ showStageId
5555
+ }) }) : /* @__PURE__ */ jsx24("div", { style: { flex: 1 } }),
5556
+ /* @__PURE__ */ jsx24(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
5557
+ rightExpanded && /* @__PURE__ */ jsx24("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsx24(
5361
5558
  RightPanel,
5362
5559
  {
5363
5560
  mode: rightPanelMode,
@@ -5369,7 +5566,6 @@ function ExplainableShell({
5369
5566
  activeTab,
5370
5567
  allTabs,
5371
5568
  activeNarrativeEntries,
5372
- activeNarrative,
5373
5569
  recorderViews,
5374
5570
  autoRecorderViews,
5375
5571
  size,
@@ -5380,7 +5576,7 @@ function ExplainableShell({
5380
5576
  }
5381
5577
  ) })
5382
5578
  ] }),
5383
- /* @__PURE__ */ jsx22(
5579
+ /* @__PURE__ */ jsx24(
5384
5580
  CompactTimeline,
5385
5581
  {
5386
5582
  snapshots: activeSnapshots,
@@ -5397,8 +5593,8 @@ function ExplainableShell({
5397
5593
 
5398
5594
  // src/components/TraceViewer/TraceViewer.tsx
5399
5595
  import * as React from "react";
5400
- import { useMemo as useMemo13 } from "react";
5401
- import { jsx as jsx23 } from "react/jsx-runtime";
5596
+ import { useMemo as useMemo14 } from "react";
5597
+ import { jsx as jsx25 } from "react/jsx-runtime";
5402
5598
  function parseTrace(input) {
5403
5599
  if (input == null) {
5404
5600
  return {
@@ -5461,11 +5657,11 @@ function TraceViewer({
5461
5657
  recorderViews,
5462
5658
  renderFlowchart
5463
5659
  }) {
5464
- const parsed = useMemo13(() => parseTrace(trace), [trace]);
5660
+ const parsed = useMemo14(() => parseTrace(trace), [trace]);
5465
5661
  React.useEffect(() => {
5466
5662
  if (!parsed.ok && onError) onError(parsed.error);
5467
5663
  }, [parsed, onError]);
5468
- const snapshots = useMemo13(() => {
5664
+ const snapshots = useMemo14(() => {
5469
5665
  if (!parsed.ok || !parsed.trace.snapshot) return [];
5470
5666
  try {
5471
5667
  return toVisualizationSnapshots(
@@ -5479,12 +5675,11 @@ function TraceViewer({
5479
5675
  if (!parsed.ok || snapshots.length === 0) {
5480
5676
  return fallback ?? null;
5481
5677
  }
5482
- return /* @__PURE__ */ jsx23(
5678
+ return /* @__PURE__ */ jsx25(
5483
5679
  ExplainableShell,
5484
5680
  {
5485
5681
  snapshots,
5486
5682
  spec: parsed.trace.spec,
5487
- narrative: parsed.trace.narrative,
5488
5683
  narrativeEntries: parsed.trace.narrativeEntries,
5489
5684
  tabs,
5490
5685
  defaultTab,