footprint-explainable-ui 0.25.5 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -624,6 +624,19 @@ interface RecorderView {
624
624
  selectedIndex: number;
625
625
  }) => React.ReactNode;
626
626
  }
627
+ /**
628
+ * The Trace flowchart's two-colour theme (footprintjs level). `mode` selects
629
+ * the neutral base (unvisited / edges) for dark or light; `visited` and
630
+ * `current` are the two semantic colours. All optional — sensible per-mode
631
+ * defaults are used for anything omitted.
632
+ */
633
+ interface TraceTheme {
634
+ mode?: "dark" | "light";
635
+ /** Executed / done nodes. */
636
+ visited?: string;
637
+ /** The node at the current cursor position ("now"). */
638
+ current?: string;
639
+ }
627
640
  interface ExplainableShellProps extends BaseComponentProps {
628
641
  /**
629
642
  * Pre-converted visualization snapshots. Use when you've already called
@@ -636,10 +649,9 @@ interface ExplainableShellProps extends BaseComponentProps {
636
649
  * and `resultData` are derived automatically. Pair with
637
650
  * `narrativeEntries` for rich per-stage narrative.
638
651
  *
639
- * Usage: `<ExplainableShell runtimeSnapshot={executor.getSnapshot()} narrativeEntries={executor.getNarrativeEntries()} spec={spec} />`
652
+ * Usage: `<ExplainableShell runtimeSnapshot={executor.getSnapshot()} narrativeEntries={executor.getNarrativeEntries()} traceGraph={graph} runtimeOverlay={overlay} />`
640
653
  */
641
654
  runtimeSnapshot?: RuntimeSnapshotInput | null;
642
- spec?: SpecNode | null;
643
655
  /**
644
656
  * Build-time graph captured live via `createTraceStructureRecorder`.
645
657
  * REQUIRED for chart rendering (v6+) — the legacy `spec` →
@@ -662,6 +674,15 @@ interface ExplainableShellProps extends BaseComponentProps {
662
674
  * time-travel trace UI.
663
675
  */
664
676
  runtimeOverlay?: RuntimeOverlay | null;
677
+ /**
678
+ * Trace flowchart theme — the footprintjs-LEVEL **two-colour** scheme:
679
+ * `visited` (executed nodes) + `current` (the cursor node). `mode` picks the
680
+ * neutral base (unvisited nodes / edges follow dark/light; the background is
681
+ * transparent, so it inherits your container). Colours are optional — omit to
682
+ * use the per-mode defaults. The agent-semantic three-colour theme belongs to
683
+ * `<Lens>`, not here.
684
+ */
685
+ traceTheme?: TraceTheme;
665
686
  title?: string;
666
687
  resultData?: Record<string, unknown> | null;
667
688
  logs?: string[];
@@ -714,7 +735,7 @@ interface ExplainableShellProps extends BaseComponentProps {
714
735
  */
715
736
  showStageId?: boolean;
716
737
  }
717
- declare function ExplainableShell({ snapshots: snapshotsProp, runtimeSnapshot, spec, title, resultData: resultDataProp, logs, narrativeEntries, tabs, defaultTab, hideConsole, hideTabs: hideTabsProp, panelLabels, defaultExpanded, recorderViews, renderFlowchart, showStageId, traceGraph, runtimeOverlay, size, unstyled, className, style, }: ExplainableShellProps): react.JSX.Element;
738
+ declare function ExplainableShell({ snapshots: snapshotsProp, runtimeSnapshot, title, resultData: resultDataProp, logs, narrativeEntries, tabs, defaultTab, hideConsole, hideTabs: hideTabsProp, panelLabels, defaultExpanded, recorderViews, renderFlowchart, showStageId, traceGraph, runtimeOverlay, traceTheme, size, unstyled, className, style, }: ExplainableShellProps): react.JSX.Element;
718
739
 
719
740
  /**
720
741
  * TraceViewer — drop-in component that renders an `agentfootprint.exportTrace()`
@@ -1101,4 +1122,4 @@ interface CompactTimelineProps {
1101
1122
  }
1102
1123
  declare const CompactTimeline: react.NamedExoticComponent<CompactTimelineProps>;
1103
1124
 
1104
- export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, mergeWritePatch, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
1125
+ export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, type TraceTheme, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, mergeWritePatch, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
package/dist/index.d.ts CHANGED
@@ -624,6 +624,19 @@ interface RecorderView {
624
624
  selectedIndex: number;
625
625
  }) => React.ReactNode;
626
626
  }
627
+ /**
628
+ * The Trace flowchart's two-colour theme (footprintjs level). `mode` selects
629
+ * the neutral base (unvisited / edges) for dark or light; `visited` and
630
+ * `current` are the two semantic colours. All optional — sensible per-mode
631
+ * defaults are used for anything omitted.
632
+ */
633
+ interface TraceTheme {
634
+ mode?: "dark" | "light";
635
+ /** Executed / done nodes. */
636
+ visited?: string;
637
+ /** The node at the current cursor position ("now"). */
638
+ current?: string;
639
+ }
627
640
  interface ExplainableShellProps extends BaseComponentProps {
628
641
  /**
629
642
  * Pre-converted visualization snapshots. Use when you've already called
@@ -636,10 +649,9 @@ interface ExplainableShellProps extends BaseComponentProps {
636
649
  * and `resultData` are derived automatically. Pair with
637
650
  * `narrativeEntries` for rich per-stage narrative.
638
651
  *
639
- * Usage: `<ExplainableShell runtimeSnapshot={executor.getSnapshot()} narrativeEntries={executor.getNarrativeEntries()} spec={spec} />`
652
+ * Usage: `<ExplainableShell runtimeSnapshot={executor.getSnapshot()} narrativeEntries={executor.getNarrativeEntries()} traceGraph={graph} runtimeOverlay={overlay} />`
640
653
  */
641
654
  runtimeSnapshot?: RuntimeSnapshotInput | null;
642
- spec?: SpecNode | null;
643
655
  /**
644
656
  * Build-time graph captured live via `createTraceStructureRecorder`.
645
657
  * REQUIRED for chart rendering (v6+) — the legacy `spec` →
@@ -662,6 +674,15 @@ interface ExplainableShellProps extends BaseComponentProps {
662
674
  * time-travel trace UI.
663
675
  */
664
676
  runtimeOverlay?: RuntimeOverlay | null;
677
+ /**
678
+ * Trace flowchart theme — the footprintjs-LEVEL **two-colour** scheme:
679
+ * `visited` (executed nodes) + `current` (the cursor node). `mode` picks the
680
+ * neutral base (unvisited nodes / edges follow dark/light; the background is
681
+ * transparent, so it inherits your container). Colours are optional — omit to
682
+ * use the per-mode defaults. The agent-semantic three-colour theme belongs to
683
+ * `<Lens>`, not here.
684
+ */
685
+ traceTheme?: TraceTheme;
665
686
  title?: string;
666
687
  resultData?: Record<string, unknown> | null;
667
688
  logs?: string[];
@@ -714,7 +735,7 @@ interface ExplainableShellProps extends BaseComponentProps {
714
735
  */
715
736
  showStageId?: boolean;
716
737
  }
717
- declare function ExplainableShell({ snapshots: snapshotsProp, runtimeSnapshot, spec, title, resultData: resultDataProp, logs, narrativeEntries, tabs, defaultTab, hideConsole, hideTabs: hideTabsProp, panelLabels, defaultExpanded, recorderViews, renderFlowchart, showStageId, traceGraph, runtimeOverlay, size, unstyled, className, style, }: ExplainableShellProps): react.JSX.Element;
738
+ declare function ExplainableShell({ snapshots: snapshotsProp, runtimeSnapshot, title, resultData: resultDataProp, logs, narrativeEntries, tabs, defaultTab, hideConsole, hideTabs: hideTabsProp, panelLabels, defaultExpanded, recorderViews, renderFlowchart, showStageId, traceGraph, runtimeOverlay, traceTheme, size, unstyled, className, style, }: ExplainableShellProps): react.JSX.Element;
718
739
 
719
740
  /**
720
741
  * TraceViewer — drop-in component that renders an `agentfootprint.exportTrace()`
@@ -1101,4 +1122,4 @@ interface CompactTimelineProps {
1101
1122
  }
1102
1123
  declare const CompactTimeline: react.NamedExoticComponent<CompactTimelineProps>;
1103
1124
 
1104
- export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, mergeWritePatch, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
1125
+ export { type NarrativeEntry as AdapterNarrativeEntry, type AgentfootprintTrace, type BaseComponentProps, type CausalFrame, CompactTimeline, type CompactTimelineProps, type DarkModeTokensOptions, DataTracePanel, type DataTracePanelProps, type DefaultExpanded, type DiffEntry, type EntryRangeIndex, ExplainableShell, type ExplainableShellProps, FootprintTheme, GanttTimeline, type GanttTimelineProps, type InsightConfig, InsightPanel, type InsightPanelProps, InspectorPanel, type InspectorPanelProps, type MemoryChange, MemoryInspector, type MemoryInspectorProps, MemoryPanel, type MemoryPanelProps, type NarrativeEntry, NarrativeLog, type NarrativeLogProps, NarrativePanel, type NarrativePanelProps, NarrativeTrace, type NarrativeTraceProps, type PanelLabels, type RecorderView, ResultPanel, type ResultPanelProps, type RuntimeSnapshotInput, ScopeDiff, type ScopeDiffProps, type ShellTab, type Size, SnapshotPanel, type SnapshotPanelProps, type StageDetailMode, StageDetailPanel, type StageDetailPanelProps, type StageSnapshot, StoryNarrative, type StoryNarrativeProps, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, type ThemePresetName, type ThemeTokens, TimeTravelControls, type TimeTravelControlsProps, type TraceParseError, type TraceTheme, TraceViewer, type TraceViewerProps, buildEntryRangeIndex, computeRevealedEntryCount, coolDark, coolLight, createSnapshots, defaultTokens, extractSubflowNarrative, mergeWritePatch, rawDefaults, subflowResultToSnapshots, themePresets, toVisualizationSnapshots, tokensToCSSVars, useDarkModeTokens, useFootprintTheme, warmDark, warmLight };
package/dist/index.js CHANGED
@@ -5927,42 +5927,19 @@ var DetailsContent = memo8(function DetailsContent2({
5927
5927
  /* @__PURE__ */ jsx26("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
5928
5928
  ] });
5929
5929
  });
5930
- function resolveSubflowLevel(parentSpec, parentSnapshots, subflowNodeName, narrativeEntries) {
5931
- const specNode = findSubflowSpecNode(parentSpec, subflowNodeName);
5932
- if (!specNode?.subflowStructure) return null;
5933
- const parentSnap = parentSnapshots.find(
5934
- (s) => s.stageName === subflowNodeName || s.stageLabel === subflowNodeName
5935
- );
5930
+ function resolveSubflowFromRuntime(parentSnapshots, subflowId, narrativeEntries) {
5931
+ const localId = subflowId.split("/").pop() ?? subflowId;
5932
+ const parentSnap = parentSnapshots.find((s) => {
5933
+ if (!s.subflowResult) return false;
5934
+ const sfStageId = s.runtimeStageId?.split("#")[0]?.split("/").pop();
5935
+ return s.subflowId === subflowId || s.subflowId === localId || s.stageName === subflowId || s.stageLabel === subflowId || sfStageId === subflowId || sfStageId === localId;
5936
+ });
5936
5937
  if (!parentSnap?.subflowResult) return null;
5937
- const sfId = specNode.subflowId ?? subflowNodeName;
5938
- const sfDisplayName = specNode.subflowName ?? specNode.name;
5939
- const sfNarrative = narrativeEntries ? extractSubflowNarrative(narrativeEntries, sfId, sfDisplayName) : void 0;
5938
+ const label = parentSnap.stageLabel ?? parentSnap.stageName ?? localId;
5939
+ const sfNarrative = narrativeEntries ? extractSubflowNarrative(narrativeEntries, subflowId, label) : void 0;
5940
5940
  const sfSnapshots = subflowResultToSnapshots(parentSnap.subflowResult, sfNarrative);
5941
5941
  if (sfSnapshots.length === 0) return null;
5942
- return {
5943
- subflowId: specNode.subflowId ?? subflowNodeName,
5944
- label: specNode.subflowName ?? specNode.name,
5945
- spec: specNode.subflowStructure,
5946
- snapshots: sfSnapshots
5947
- };
5948
- }
5949
- function findSubflowSpecNode(node, name) {
5950
- if ((node.name === name || node.id === name) && node.isSubflowRoot) return node;
5951
- if (node.children) {
5952
- for (const child of node.children) {
5953
- const f = findSubflowSpecNode(child, name);
5954
- if (f) return f;
5955
- }
5956
- }
5957
- if (node.next) return findSubflowSpecNode(node.next, name);
5958
- return null;
5959
- }
5960
- function hasSubflowNodes(node) {
5961
- if (!node) return false;
5962
- if (node.isSubflowRoot) return true;
5963
- if (node.children?.some((c) => c && hasSubflowNodes(c))) return true;
5964
- if (node.next && hasSubflowNodes(node.next)) return true;
5965
- return false;
5942
+ return { subflowId, label, spec: null, snapshots: sfSnapshots, narrative: sfNarrative };
5966
5943
  }
5967
5944
  function buildDataTrace(commitLog, targetRuntimeStageId, maxDepth = 10) {
5968
5945
  const log = commitLog;
@@ -6004,7 +5981,6 @@ var RightPanel = memo8(function RightPanel2({
6004
5981
  snapshots,
6005
5982
  selectedIndex,
6006
5983
  runtimeSnapshot,
6007
- spec,
6008
5984
  activeTab,
6009
5985
  allTabs,
6010
5986
  activeNarrativeEntries,
@@ -6050,7 +6026,7 @@ var RightPanel = memo8(function RightPanel2({
6050
6026
  id: tab.id,
6051
6027
  name: insightName(tab.name),
6052
6028
  render: () => {
6053
- if (tab.id === "narrative") return /* @__PURE__ */ jsx26(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, runtimeSnapshot, spec, size, style: { height: "100%" } });
6029
+ if (tab.id === "narrative") return /* @__PURE__ */ jsx26(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, runtimeSnapshot, size, style: { height: "100%" } });
6054
6030
  const customView = recorderViews?.find((v2) => v2.id === tab.id);
6055
6031
  if (customView?.render) return customView.render({ snapshots, selectedIndex });
6056
6032
  const autoView = autoRecorderViews.find((v2) => v2.id === tab.id);
@@ -6084,7 +6060,6 @@ function insightName(name) {
6084
6060
  function ExplainableShell({
6085
6061
  snapshots: snapshotsProp,
6086
6062
  runtimeSnapshot,
6087
- spec,
6088
6063
  title,
6089
6064
  resultData: resultDataProp,
6090
6065
  logs = [],
@@ -6100,6 +6075,7 @@ function ExplainableShell({
6100
6075
  showStageId = false,
6101
6076
  traceGraph,
6102
6077
  runtimeOverlay,
6078
+ traceTheme,
6103
6079
  size = "default",
6104
6080
  unstyled = false,
6105
6081
  className,
@@ -6122,16 +6098,27 @@ function ExplainableShell({
6122
6098
  const activeRsid = snapshots2[selectedIndex]?.runtimeStageId;
6123
6099
  let overlayIdx = selectedIndex;
6124
6100
  if (activeRsid && runtimeOverlay) {
6125
- const i = runtimeOverlay.executionOrder.findIndex(
6101
+ let i = runtimeOverlay.executionOrder.findIndex(
6126
6102
  (s) => s.runtimeStageId === activeRsid
6127
6103
  );
6104
+ if (i < 0) {
6105
+ i = runtimeOverlay.executionOrder.findIndex(
6106
+ (s) => s.runtimeStageId?.endsWith("/" + activeRsid)
6107
+ );
6108
+ }
6128
6109
  if (i >= 0) overlayIdx = i;
6129
6110
  }
6111
+ const traceColors = traceTheme && {
6112
+ ...traceTheme.visited !== void 0 && { done: traceTheme.visited },
6113
+ ...traceTheme.current !== void 0 && { active: traceTheme.current },
6114
+ ...traceTheme.mode !== void 0 && { default: traceTheme.mode === "dark" ? "#94a3b8" : "#64748b" }
6115
+ };
6130
6116
  return /* @__PURE__ */ jsx26(
6131
6117
  TracedFlow,
6132
6118
  {
6133
6119
  graph: traceGraph,
6134
6120
  overlay: runtimeOverlay ?? void 0,
6121
+ colors: traceColors || void 0,
6135
6122
  scrubIndex: overlayIdx,
6136
6123
  onNodeClick: (stageId) => onNodeClick?.(stageId),
6137
6124
  onSubflowChange: (mountId) => {
@@ -6140,7 +6127,7 @@ function ExplainableShell({
6140
6127
  }
6141
6128
  );
6142
6129
  };
6143
- }, [traceGraph, runtimeOverlay]);
6130
+ }, [traceGraph, runtimeOverlay, traceTheme]);
6144
6131
  const effectiveRenderFlowchart = renderFlowchart ?? tracedFlowRenderer;
6145
6132
  const leftLabel = panelLabels?.topology ?? "Topology";
6146
6133
  const rightLabel = panelLabels?.details ?? "Details";
@@ -6220,24 +6207,23 @@ function ExplainableShell({
6220
6207
  const currentLevel = useMemo12(() => {
6221
6208
  if (drillDownStack.length > 0) {
6222
6209
  const top = drillDownStack[drillDownStack.length - 1];
6223
- return { spec: top.spec, snapshots: top.snapshots };
6210
+ return { spec: top.spec, snapshots: top.snapshots, narrative: top.narrative };
6224
6211
  }
6225
- return { spec: spec ?? null, snapshots };
6226
- }, [drillDownStack, spec, snapshots]);
6212
+ return { spec: null, snapshots, narrative: void 0 };
6213
+ }, [drillDownStack, snapshots]);
6227
6214
  const activeSnapshots = currentLevel.snapshots;
6228
- const activeSpec = currentLevel.spec;
6229
6215
  const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
6230
- const activeNarrativeEntries = isInSubflow ? void 0 : narrativeEntries;
6216
+ const activeNarrativeEntries = isInSubflow ? currentLevel.narrative : narrativeEntries;
6231
6217
  const breadcrumbs = useMemo12(() => {
6232
- const root = { label: title || "Flowchart", spec, description: spec?.description };
6218
+ const root = { label: title || "Flowchart", spec: null, description: void 0 };
6233
6219
  return [root, ...drillDownStack.map((e) => ({ label: e.label, spec: e.spec, description: void 0 }))];
6234
- }, [spec, title, drillDownStack]);
6220
+ }, [title, drillDownStack]);
6235
6221
  const showTreeSidebar = useMemo12(() => {
6236
6222
  if (traceGraph?.nodes?.length) {
6237
6223
  return traceGraph.nodes.some((n) => n.data?.isSubflow === true);
6238
6224
  }
6239
- return !!spec && hasSubflowNodes(spec);
6240
- }, [traceGraph, spec]);
6225
+ return false;
6226
+ }, [traceGraph]);
6241
6227
  const rootOverlay = useMemo12(() => {
6242
6228
  if (isInSubflow || !snapshots.length) return { activeStage: void 0, doneStages: void 0 };
6243
6229
  const doneStages = new Set(snapshots.slice(0, safeIdx).map((s) => s.stageLabel));
@@ -6253,14 +6239,13 @@ function ExplainableShell({
6253
6239
  }, []);
6254
6240
  const handleDrillDown = useCallback8(
6255
6241
  (nodeName) => {
6256
- if (!activeSpec) return;
6257
- const entry = resolveSubflowLevel(activeSpec, activeSnapshots, nodeName, narrativeEntries);
6242
+ const entry = resolveSubflowFromRuntime(activeSnapshots, nodeName, narrativeEntries);
6258
6243
  if (entry) {
6259
6244
  setDrillDownStack((prev) => [...prev, { ...entry, parentSnapshotIdx: snapshotIdx }]);
6260
6245
  setSnapshotIdx(0);
6261
6246
  }
6262
6247
  },
6263
- [activeSpec, activeSnapshots, narrativeEntries, snapshotIdx]
6248
+ [activeSnapshots, narrativeEntries, snapshotIdx]
6264
6249
  );
6265
6250
  const handleBreadcrumbNavigate = useCallback8((level) => {
6266
6251
  setDrillDownStack((prev) => {
@@ -6275,23 +6260,21 @@ function ExplainableShell({
6275
6260
  setSnapshotIdx(indexOrId);
6276
6261
  return;
6277
6262
  }
6278
- if (activeSpec) {
6279
- const sfNode = findSubflowSpecNode(activeSpec, indexOrId);
6280
- if (sfNode?.subflowStructure) {
6281
- handleDrillDown(indexOrId);
6282
- return;
6283
- }
6263
+ const drillable = resolveSubflowFromRuntime(activeSnapshots, indexOrId, narrativeEntries);
6264
+ if (drillable) {
6265
+ handleDrillDown(indexOrId);
6266
+ return;
6284
6267
  }
6285
6268
  const idx = activeSnapshots.findIndex((s) => s.stageLabel === indexOrId);
6286
6269
  if (idx >= 0) setSnapshotIdx(idx);
6287
6270
  },
6288
- [activeSpec, activeSnapshots, handleDrillDown]
6271
+ [activeSnapshots, narrativeEntries, handleDrillDown]
6289
6272
  );
6290
6273
  const handleTreeNodeSelect = useCallback8(
6291
6274
  (name, isSubflow) => {
6292
- if (isSubflow && spec) {
6275
+ if (isSubflow) {
6293
6276
  setDrillDownStack([]);
6294
- const entry = resolveSubflowLevel(spec, snapshots, name, narrativeEntries);
6277
+ const entry = resolveSubflowFromRuntime(snapshots, name, narrativeEntries);
6295
6278
  if (entry) {
6296
6279
  setDrillDownStack([{ ...entry, parentSnapshotIdx: snapshotIdx }]);
6297
6280
  setSnapshotIdx(0);
@@ -6302,7 +6285,7 @@ function ExplainableShell({
6302
6285
  if (idx >= 0) setSnapshotIdx(idx);
6303
6286
  }
6304
6287
  },
6305
- [spec, snapshots, narrativeEntries, snapshotIdx]
6288
+ [snapshots, narrativeEntries, snapshotIdx]
6306
6289
  );
6307
6290
  const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
6308
6291
  if (unstyled) {
@@ -6313,7 +6296,7 @@ function ExplainableShell({
6313
6296
  (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ jsxs23(Fragment6, { children: [
6314
6297
  /* @__PURE__ */ jsx26(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
6315
6298
  isInSubflow && /* @__PURE__ */ jsx26(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6316
- activeSpec && effectiveRenderFlowchart?.({ spec: activeSpec, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId }),
6299
+ traceGraph && effectiveRenderFlowchart?.({ spec: null, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId }),
6317
6300
  /* @__PURE__ */ jsx26(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
6318
6301
  /* @__PURE__ */ jsx26(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
6319
6302
  /* @__PURE__ */ jsx26(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
@@ -6321,7 +6304,7 @@ function ExplainableShell({
6321
6304
  ] })
6322
6305
  ] });
6323
6306
  }
6324
- const showTopology = !!effectiveRenderFlowchart && !!activeSpec;
6307
+ const showTopology = !!effectiveRenderFlowchart && !!traceGraph;
6325
6308
  const detailsContent = useMemo12(() => {
6326
6309
  if (activeTab === "result") {
6327
6310
  return /* @__PURE__ */ jsx26(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
@@ -6418,7 +6401,7 @@ function ExplainableShell({
6418
6401
  /* ── Mobile: stacked vertical ── */
6419
6402
  /* @__PURE__ */ jsxs23(Fragment6, { children: [
6420
6403
  showTopology && /* @__PURE__ */ jsx26("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
6421
- spec: activeSpec,
6404
+ spec: null,
6422
6405
  snapshots: activeSnapshots,
6423
6406
  selectedIndex: safeIdx,
6424
6407
  onNodeClick: handleNodeClick,
@@ -6458,7 +6441,7 @@ function ExplainableShell({
6458
6441
  /* @__PURE__ */ jsx26(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
6459
6442
  ] }) : /* @__PURE__ */ jsx26(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
6460
6443
  showTopology ? /* @__PURE__ */ jsx26("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
6461
- spec: activeSpec,
6444
+ spec: null,
6462
6445
  snapshots: activeSnapshots,
6463
6446
  selectedIndex: safeIdx,
6464
6447
  onNodeClick: handleNodeClick,
@@ -6473,7 +6456,6 @@ function ExplainableShell({
6473
6456
  snapshots: activeSnapshots,
6474
6457
  selectedIndex: safeIdx,
6475
6458
  runtimeSnapshot,
6476
- spec,
6477
6459
  activeTab,
6478
6460
  allTabs,
6479
6461
  activeNarrativeEntries,
@@ -6590,7 +6572,6 @@ function TraceViewer({
6590
6572
  ExplainableShell,
6591
6573
  {
6592
6574
  snapshots,
6593
- spec: parsed.trace.spec,
6594
6575
  narrativeEntries: parsed.trace.narrativeEntries,
6595
6576
  tabs,
6596
6577
  defaultTab,