footprint-explainable-ui 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -447,8 +447,16 @@ type StageId = string & {
447
447
 
448
448
  type EdgeKind = "next" | "fork-branch" | "decision-branch";
449
449
  /**
450
- * Per-node data attached to the xyflow `Node`. Consumed by the
451
- * `StageNode` renderer (shape mirrors what the renderer expects).
450
+ * Per-node data attached to the xyflow `Node`. The built-in `StageNode`
451
+ * renderer reads the named fields below.
452
+ *
453
+ * Consumer extension: this type EXTENDS `Record<string, unknown>` so
454
+ * you can attach custom fields without TypeScript fighting you. Pair
455
+ * this with `<TraceFlow nodeTypes={{ stageNode: MyNode }} />` (or push
456
+ * nodes with `type: 'myCustomKind'`) to render those custom fields
457
+ * however you want. The built-in `StageNode` ignores fields it doesn't
458
+ * recognize, so adding consumer fields is non-breaking even if you
459
+ * keep the default renderer.
452
460
  */
453
461
  interface TraceNodeData extends Record<string, unknown> {
454
462
  label: string;
@@ -508,7 +516,14 @@ interface TraceNodeData extends Record<string, unknown> {
508
516
  prevIds: StageId[];
509
517
  nextIds: StageId[];
510
518
  }
511
- /** Per-edge data attached to the xyflow `Edge`. */
519
+ /**
520
+ * Per-edge data attached to the xyflow `Edge`. The default edge
521
+ * renderer reads `kind` (and `label`).
522
+ *
523
+ * Consumer extension: same pattern as `TraceNodeData` — extra fields
524
+ * pass through unchanged. Pair with `<TraceFlow edgeTypes={...} />`
525
+ * to render custom edges (e.g., a "retried" edge with a count badge).
526
+ */
512
527
  interface TraceEdgeData extends Record<string, unknown> {
513
528
  kind: EdgeKind | "loop";
514
529
  label?: string;
package/dist/index.d.ts CHANGED
@@ -447,8 +447,16 @@ type StageId = string & {
447
447
 
448
448
  type EdgeKind = "next" | "fork-branch" | "decision-branch";
449
449
  /**
450
- * Per-node data attached to the xyflow `Node`. Consumed by the
451
- * `StageNode` renderer (shape mirrors what the renderer expects).
450
+ * Per-node data attached to the xyflow `Node`. The built-in `StageNode`
451
+ * renderer reads the named fields below.
452
+ *
453
+ * Consumer extension: this type EXTENDS `Record<string, unknown>` so
454
+ * you can attach custom fields without TypeScript fighting you. Pair
455
+ * this with `<TraceFlow nodeTypes={{ stageNode: MyNode }} />` (or push
456
+ * nodes with `type: 'myCustomKind'`) to render those custom fields
457
+ * however you want. The built-in `StageNode` ignores fields it doesn't
458
+ * recognize, so adding consumer fields is non-breaking even if you
459
+ * keep the default renderer.
452
460
  */
453
461
  interface TraceNodeData extends Record<string, unknown> {
454
462
  label: string;
@@ -508,7 +516,14 @@ interface TraceNodeData extends Record<string, unknown> {
508
516
  prevIds: StageId[];
509
517
  nextIds: StageId[];
510
518
  }
511
- /** Per-edge data attached to the xyflow `Edge`. */
519
+ /**
520
+ * Per-edge data attached to the xyflow `Edge`. The default edge
521
+ * renderer reads `kind` (and `label`).
522
+ *
523
+ * Consumer extension: same pattern as `TraceNodeData` — extra fields
524
+ * pass through unchanged. Pair with `<TraceFlow edgeTypes={...} />`
525
+ * to render custom edges (e.g., a "retried" edge with a count badge).
526
+ */
512
527
  interface TraceEdgeData extends Record<string, unknown> {
513
528
  kind: EdgeKind | "loop";
514
529
  label?: string;
package/dist/index.js CHANGED
@@ -3742,7 +3742,7 @@ var StageNode = memo3(function StageNode2({
3742
3742
  });
3743
3743
 
3744
3744
  // src/components/FlowchartView/TraceFlow.tsx
3745
- import { jsx as jsx17 } from "react/jsx-runtime";
3745
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3746
3746
  var Y_STEP = 100;
3747
3747
  var X_SPREAD = 200;
3748
3748
  var defaultTraceFlowLayout = (graph) => {
@@ -3977,7 +3977,7 @@ function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
3977
3977
  }
3978
3978
 
3979
3979
  // src/components/FlowchartView/SubflowBreadcrumbBar.tsx
3980
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3980
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3981
3981
  function SubflowBreadcrumbBar({ entries, onNavigate }) {
3982
3982
  return /* @__PURE__ */ jsx18(
3983
3983
  "div",
@@ -3995,7 +3995,7 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
3995
3995
  "aria-label": "Subflow breadcrumb",
3996
3996
  children: entries.map((entry, i) => {
3997
3997
  const isLast = i === entries.length - 1;
3998
- return /* @__PURE__ */ jsxs16(
3998
+ return /* @__PURE__ */ jsxs17(
3999
3999
  "span",
4000
4000
  {
4001
4001
  style: { display: "inline-flex", alignItems: "center", gap: 6 },
@@ -4031,7 +4031,7 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
4031
4031
  }
4032
4032
 
4033
4033
  // src/components/FlowchartView/TracedFlow.tsx
4034
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
4034
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
4035
4035
  var DEFAULT_COLORS = {
4036
4036
  default: rawDefaults.colors.textMuted,
4037
4037
  done: rawDefaults.colors.success,
@@ -4040,6 +4040,9 @@ var DEFAULT_COLORS = {
4040
4040
  loop: rawDefaults.colors.warning
4041
4041
  };
4042
4042
  function toStageNodeWithOverlay(node, doneStageIds, activeStageId, errorMessage, executedOrderIds) {
4043
+ if (node.type !== void 0 && node.type !== "stage") {
4044
+ return node;
4045
+ }
4043
4046
  const isDone = doneStageIds.has(node.id);
4044
4047
  const isActive = activeStageId === node.id;
4045
4048
  const wasExecuted = isDone || isActive;
@@ -4104,7 +4107,7 @@ function styleEdgeWithOverlay(edge, doneStageIds, activeStageId, colors) {
4104
4107
  }
4105
4108
  return styled;
4106
4109
  }
4107
- var nodeTypes = { stageNode: StageNode };
4110
+ var DEFAULT_NODE_TYPES = { stageNode: StageNode };
4108
4111
  function TracedFlow({
4109
4112
  graph,
4110
4113
  overlay,
@@ -4113,6 +4116,9 @@ function TracedFlow({
4113
4116
  colors: colorOverrides,
4114
4117
  onNodeClick,
4115
4118
  onSubflowChange,
4119
+ nodeTypes: userNodeTypes,
4120
+ edgeTypes: userEdgeTypes,
4121
+ children,
4116
4122
  className,
4117
4123
  style
4118
4124
  }) {
@@ -4121,6 +4127,10 @@ function TracedFlow({
4121
4127
  () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
4122
4128
  [colorOverrides]
4123
4129
  );
4130
+ const mergedNodeTypes = useMemo11(
4131
+ () => userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES,
4132
+ [userNodeTypes]
4133
+ );
4124
4134
  const drill = useSubflowDrill(graph, onSubflowChange);
4125
4135
  const filteredGraph = useMemo11(
4126
4136
  () => filterGraphForDrill(graph, drill.currentSubflowId),
@@ -4178,7 +4188,7 @@ function TracedFlow({
4178
4188
  const wrapperRef = useRef8(null);
4179
4189
  const [rfInstance, setRfInstance] = useState10(null);
4180
4190
  useChartAutoRefit(wrapperRef, rfInstance);
4181
- return /* @__PURE__ */ jsxs17(
4191
+ return /* @__PURE__ */ jsxs18(
4182
4192
  "div",
4183
4193
  {
4184
4194
  ref: wrapperRef,
@@ -4199,17 +4209,21 @@ function TracedFlow({
4199
4209
  onNavigate: drill.setCurrentSubflowId
4200
4210
  }
4201
4211
  ),
4202
- /* @__PURE__ */ jsx19("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsx19(
4212
+ /* @__PURE__ */ jsx19("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsxs18(
4203
4213
  ReactFlow2,
4204
4214
  {
4205
4215
  nodes: reactFlowNodes,
4206
4216
  edges: reactFlowEdges,
4207
- nodeTypes,
4217
+ nodeTypes: mergedNodeTypes,
4218
+ ...userEdgeTypes && { edgeTypes: userEdgeTypes },
4208
4219
  onNodeClick: handleNodeClick,
4209
4220
  onInit: setRfInstance,
4210
4221
  fitView: true,
4211
4222
  proOptions: { hideAttribution: true },
4212
- children: /* @__PURE__ */ jsx19(Background2, { variant: BackgroundVariant2.Dots, gap: 20, size: 1 })
4223
+ children: [
4224
+ /* @__PURE__ */ jsx19(Background2, { variant: BackgroundVariant2.Dots, gap: 20, size: 1 }),
4225
+ children
4226
+ ]
4213
4227
  }
4214
4228
  ) })
4215
4229
  ]
@@ -4222,7 +4236,7 @@ import { memo as memo5, useState as useState11 } from "react";
4222
4236
 
4223
4237
  // src/components/DataTracePanel/DataTracePanel.tsx
4224
4238
  import { memo as memo4 } from "react";
4225
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
4239
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
4226
4240
  var DataTracePanel = memo4(function DataTracePanel2({
4227
4241
  frames,
4228
4242
  selectedStageId,
@@ -4230,7 +4244,7 @@ var DataTracePanel = memo4(function DataTracePanel2({
4230
4244
  fromStageName
4231
4245
  }) {
4232
4246
  if (frames.length === 0) {
4233
- return /* @__PURE__ */ jsxs18("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
4247
+ return /* @__PURE__ */ jsxs19("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
4234
4248
  /* @__PURE__ */ jsx20(
4235
4249
  "div",
4236
4250
  {
@@ -4249,9 +4263,9 @@ var DataTracePanel = memo4(function DataTracePanel2({
4249
4263
  /* @__PURE__ */ jsx20("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
4250
4264
  ] });
4251
4265
  }
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(
4266
+ return /* @__PURE__ */ jsxs19("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
4267
+ fromStageName && /* @__PURE__ */ jsxs19("div", { style: { padding: "4px 12px 8px" }, children: [
4268
+ /* @__PURE__ */ jsxs19(
4255
4269
  "div",
4256
4270
  {
4257
4271
  style: {
@@ -4300,7 +4314,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4300
4314
  isSelected,
4301
4315
  onClick
4302
4316
  }) {
4303
- return /* @__PURE__ */ jsxs18(
4317
+ return /* @__PURE__ */ jsxs19(
4304
4318
  "button",
4305
4319
  {
4306
4320
  onClick: () => onClick?.(frame.runtimeStageId),
@@ -4317,7 +4331,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4317
4331
  fontSize: 13
4318
4332
  },
4319
4333
  children: [
4320
- /* @__PURE__ */ jsxs18("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4334
+ /* @__PURE__ */ jsxs19("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4321
4335
  !isFirst && /* @__PURE__ */ jsx20("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
4322
4336
  /* @__PURE__ */ jsx20(
4323
4337
  "span",
@@ -4341,7 +4355,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4341
4355
  }
4342
4356
  )
4343
4357
  ] }),
4344
- frame.keysWritten.length > 0 && /* @__PURE__ */ jsxs18(
4358
+ frame.keysWritten.length > 0 && /* @__PURE__ */ jsxs19(
4345
4359
  "div",
4346
4360
  {
4347
4361
  style: {
@@ -4357,7 +4371,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4357
4371
  ]
4358
4372
  }
4359
4373
  ),
4360
- frame.linkedBy && /* @__PURE__ */ jsxs18(
4374
+ frame.linkedBy && /* @__PURE__ */ jsxs19(
4361
4375
  "div",
4362
4376
  {
4363
4377
  style: {
@@ -4378,7 +4392,7 @@ var DataTraceFrame = memo4(function DataTraceFrame2({
4378
4392
  });
4379
4393
 
4380
4394
  // src/components/InspectorPanel/InspectorPanel.tsx
4381
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
4395
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
4382
4396
  var InspectorPanel = memo5(function InspectorPanel2({
4383
4397
  snapshots,
4384
4398
  selectedIndex,
@@ -4388,7 +4402,7 @@ var InspectorPanel = memo5(function InspectorPanel2({
4388
4402
  }) {
4389
4403
  const [tab, setTab] = useState11("state");
4390
4404
  const currentSnapshot = snapshots[selectedIndex];
4391
- return /* @__PURE__ */ jsxs19(
4405
+ return /* @__PURE__ */ jsxs20(
4392
4406
  "div",
4393
4407
  {
4394
4408
  style: {
@@ -4398,7 +4412,7 @@ var InspectorPanel = memo5(function InspectorPanel2({
4398
4412
  overflow: "hidden"
4399
4413
  },
4400
4414
  children: [
4401
- /* @__PURE__ */ jsxs19(
4415
+ /* @__PURE__ */ jsxs20(
4402
4416
  "div",
4403
4417
  {
4404
4418
  style: {
@@ -4427,7 +4441,7 @@ var InspectorPanel = memo5(function InspectorPanel2({
4427
4441
  ]
4428
4442
  }
4429
4443
  ),
4430
- /* @__PURE__ */ jsxs19("div", { style: { flex: 1, overflow: "auto" }, children: [
4444
+ /* @__PURE__ */ jsxs20("div", { style: { flex: 1, overflow: "auto" }, children: [
4431
4445
  tab === "state" && /* @__PURE__ */ jsx21(
4432
4446
  MemoryPanel,
4433
4447
  {
@@ -4455,7 +4469,7 @@ function TabButton({
4455
4469
  label,
4456
4470
  badge
4457
4471
  }) {
4458
- return /* @__PURE__ */ jsxs19(
4472
+ return /* @__PURE__ */ jsxs20(
4459
4473
  "button",
4460
4474
  {
4461
4475
  onClick,
@@ -4495,7 +4509,7 @@ function TabButton({
4495
4509
 
4496
4510
  // src/components/InsightPanel/InsightPanel.tsx
4497
4511
  import { memo as memo6, useState as useState12 } from "react";
4498
- import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
4512
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
4499
4513
  var InsightPanel = memo6(function InsightPanel2({
4500
4514
  insights,
4501
4515
  expandedId,
@@ -4515,7 +4529,7 @@ var InsightTabs = memo6(function InsightTabs2({
4515
4529
  }) {
4516
4530
  const [activeId, setActiveId] = useState12(defaultId ?? insights[0]?.id);
4517
4531
  const active = insights.find((i) => i.id === activeId) ?? insights[0];
4518
- return /* @__PURE__ */ jsxs20(
4532
+ return /* @__PURE__ */ jsxs21(
4519
4533
  "div",
4520
4534
  {
4521
4535
  style: {
@@ -4575,7 +4589,7 @@ var InsightGrid = memo6(function InsightGrid2({
4575
4589
  gap: 1,
4576
4590
  background: theme.border
4577
4591
  },
4578
- children: insights.map((insight) => /* @__PURE__ */ jsxs20(
4592
+ children: insights.map((insight) => /* @__PURE__ */ jsxs21(
4579
4593
  "div",
4580
4594
  {
4581
4595
  style: {
@@ -4585,7 +4599,7 @@ var InsightGrid = memo6(function InsightGrid2({
4585
4599
  overflow: "hidden"
4586
4600
  },
4587
4601
  children: [
4588
- /* @__PURE__ */ jsxs20(
4602
+ /* @__PURE__ */ jsxs21(
4589
4603
  "div",
4590
4604
  {
4591
4605
  style: {
@@ -4626,7 +4640,7 @@ var InsightGrid = memo6(function InsightGrid2({
4626
4640
 
4627
4641
  // src/components/CompactTimeline/CompactTimeline.tsx
4628
4642
  import { memo as memo7, useState as useState13 } from "react";
4629
- import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
4643
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
4630
4644
  var CompactTimeline = memo7(function CompactTimeline2({
4631
4645
  snapshots,
4632
4646
  selectedIndex,
@@ -4634,8 +4648,8 @@ var CompactTimeline = memo7(function CompactTimeline2({
4634
4648
  }) {
4635
4649
  const [expanded, setExpanded] = useState13(defaultExpanded);
4636
4650
  if (snapshots.length === 0) return null;
4637
- return /* @__PURE__ */ jsxs21("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
4638
- /* @__PURE__ */ jsxs21(
4651
+ return /* @__PURE__ */ jsxs22("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
4652
+ /* @__PURE__ */ jsxs22(
4639
4653
  "button",
4640
4654
  {
4641
4655
  onClick: () => setExpanded((e) => !e),
@@ -4657,11 +4671,11 @@ var CompactTimeline = memo7(function CompactTimeline2({
4657
4671
  children: [
4658
4672
  /* @__PURE__ */ jsx23("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
4659
4673
  "Timeline",
4660
- /* @__PURE__ */ jsxs21("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
4674
+ /* @__PURE__ */ jsxs22("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
4661
4675
  snapshots.length,
4662
4676
  " stages"
4663
4677
  ] }),
4664
- !expanded && /* @__PURE__ */ jsxs21(
4678
+ !expanded && /* @__PURE__ */ jsxs22(
4665
4679
  "div",
4666
4680
  {
4667
4681
  style: {
@@ -4716,21 +4730,21 @@ var CompactTimeline = memo7(function CompactTimeline2({
4716
4730
  });
4717
4731
 
4718
4732
  // src/components/ExplainableShell/ExplainableShell.tsx
4719
- import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
4733
+ import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
4720
4734
  var HLinePill = memo8(function HLinePill2({
4721
4735
  label,
4722
4736
  detail,
4723
4737
  expanded,
4724
4738
  onClick
4725
4739
  }) {
4726
- return /* @__PURE__ */ jsxs22("div", { style: {
4740
+ return /* @__PURE__ */ jsxs23("div", { style: {
4727
4741
  display: "flex",
4728
4742
  alignItems: "center",
4729
4743
  gap: 0,
4730
4744
  padding: "0"
4731
4745
  }, children: [
4732
4746
  /* @__PURE__ */ jsx24("div", { style: { flex: 1, height: 1, background: theme.border } }),
4733
- /* @__PURE__ */ jsxs22(
4747
+ /* @__PURE__ */ jsxs23(
4734
4748
  "button",
4735
4749
  {
4736
4750
  onClick,
@@ -4770,7 +4784,7 @@ var VLinePill = memo8(function VLinePill2({
4770
4784
  onClick
4771
4785
  }) {
4772
4786
  const arrow = side === "right" ? expanded ? "\u25B6" : "\u25C0" : expanded ? "\u25C0" : "\u25B6";
4773
- return /* @__PURE__ */ jsxs22("div", { style: {
4787
+ return /* @__PURE__ */ jsxs23("div", { style: {
4774
4788
  display: "flex",
4775
4789
  flexDirection: "column",
4776
4790
  alignItems: "center",
@@ -4778,7 +4792,7 @@ var VLinePill = memo8(function VLinePill2({
4778
4792
  padding: "0"
4779
4793
  }, children: [
4780
4794
  /* @__PURE__ */ jsx24("div", { style: { flex: 1, width: 1, background: theme.border } }),
4781
- /* @__PURE__ */ jsxs22(
4795
+ /* @__PURE__ */ jsxs23(
4782
4796
  "button",
4783
4797
  {
4784
4798
  onClick,
@@ -4876,12 +4890,12 @@ function KeyedRecorderView({
4876
4890
  }
4877
4891
  }
4878
4892
  const grandTotal = hints?.grandTotal ?? 0;
4879
- return /* @__PURE__ */ jsxs22("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
4893
+ return /* @__PURE__ */ jsxs23("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
4880
4894
  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: [
4895
+ /* @__PURE__ */ jsxs23("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
4882
4896
  preferredOperation === "aggregate" ? (
4883
4897
  /* AGGREGATE: collect silently during scrub, button at end to reveal total */
4884
- /* @__PURE__ */ jsxs22(Fragment6, { children: [
4898
+ /* @__PURE__ */ jsxs23(Fragment6, { children: [
4885
4899
  isAtEnd ? /* @__PURE__ */ jsx24("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ jsx24(
4886
4900
  "button",
4887
4901
  {
@@ -4900,20 +4914,20 @@ function KeyedRecorderView({
4900
4914
  },
4901
4915
  children: "Aggregate \u2014 Show Grand Total"
4902
4916
  }
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: [
4917
+ ) : /* @__PURE__ */ jsxs23("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
4904
4918
  /* @__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: [
4919
+ numFieldKey && /* @__PURE__ */ jsxs23("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
4906
4920
  grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1),
4907
- /* @__PURE__ */ jsxs22("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
4921
+ /* @__PURE__ */ jsxs23("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
4908
4922
  numFieldKey,
4909
4923
  " \xB7 ",
4910
4924
  allKeys.length,
4911
4925
  " steps"
4912
4926
  ] })
4913
4927
  ] })
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: [
4928
+ ] }) }) : /* @__PURE__ */ jsxs23("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
4929
  /* @__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: [
4930
+ /* @__PURE__ */ jsxs23("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
4917
4931
  visibleEntries.length,
4918
4932
  " of ",
4919
4933
  allKeys.length,
@@ -4924,11 +4938,11 @@ function KeyedRecorderView({
4924
4938
  ] })
4925
4939
  ) : preferredOperation === "accumulate" ? (
4926
4940
  /* ACCUMULATE: running total grows with slider — IS the total at end, no button */
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: [
4941
+ /* @__PURE__ */ jsxs23(Fragment6, { children: [
4942
+ numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ jsxs23("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
4929
4943
  /* @__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
4944
  /* @__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: [
4945
+ /* @__PURE__ */ jsxs23("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
4932
4946
  numFieldKey,
4933
4947
  " \xB7 ",
4934
4948
  visibleEntries.length,
@@ -4947,7 +4961,7 @@ function KeyedRecorderView({
4947
4961
  const entry = steps[key];
4948
4962
  const label = entry.stageName ?? key;
4949
4963
  const numVal = numFieldKey ? entry[numFieldKey] : void 0;
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: [
4964
+ return /* @__PURE__ */ jsxs23("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
4951
4965
  /* @__PURE__ */ jsx24("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
4952
4966
  /* @__PURE__ */ jsx24("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
4953
4967
  numVal !== void 0 && /* @__PURE__ */ jsx24("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
@@ -4986,7 +5000,7 @@ var DetailsContent = memo8(function DetailsContent2({
4986
5000
  }
4987
5001
  }, [viewIds]);
4988
5002
  const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
4989
- return /* @__PURE__ */ jsxs22("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
5003
+ return /* @__PURE__ */ jsxs23("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
4990
5004
  /* @__PURE__ */ jsx24("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
4991
5005
  const active = view.id === activeViewId;
4992
5006
  return /* @__PURE__ */ jsx24(
@@ -5102,7 +5116,7 @@ var RightPanel = memo8(function RightPanel2({
5102
5116
  size,
5103
5117
  onNavigateToStage
5104
5118
  }) {
5105
- return /* @__PURE__ */ jsxs22(Fragment6, { children: [
5119
+ return /* @__PURE__ */ jsxs23(Fragment6, { children: [
5106
5120
  /* @__PURE__ */ jsx24("div", { style: {
5107
5121
  display: "flex",
5108
5122
  borderBottom: `1px solid ${theme.border}`,
@@ -5395,11 +5409,11 @@ function ExplainableShell({
5395
5409
  );
5396
5410
  const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
5397
5411
  if (unstyled) {
5398
- return /* @__PURE__ */ jsxs22("div", { className, style, "data-fp": "explainable-shell", children: [
5412
+ return /* @__PURE__ */ jsxs23("div", { className, style, "data-fp": "explainable-shell", children: [
5399
5413
  /* @__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: [
5414
+ /* @__PURE__ */ jsxs23("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
5401
5415
  activeTab === "result" && /* @__PURE__ */ jsx24(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
5402
- (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ jsxs22(Fragment6, { children: [
5416
+ (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ jsxs23(Fragment6, { children: [
5403
5417
  /* @__PURE__ */ jsx24(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
5404
5418
  isInSubflow && /* @__PURE__ */ jsx24(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5405
5419
  activeSpec && effectiveRenderFlowchart?.({ spec: activeSpec, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId }),
@@ -5440,7 +5454,7 @@ function ExplainableShell({
5440
5454
  }
5441
5455
  return null;
5442
5456
  }, [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: [
5457
+ const detailsPanel = /* @__PURE__ */ jsxs23("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
5444
5458
  /* @__PURE__ */ jsx24("div", { style: {
5445
5459
  display: "flex",
5446
5460
  borderBottom: `1px solid ${theme.border}`,
@@ -5475,7 +5489,7 @@ function ExplainableShell({
5475
5489
  }) }),
5476
5490
  /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
5477
5491
  ] });
5478
- return /* @__PURE__ */ jsxs22(
5492
+ return /* @__PURE__ */ jsxs23(
5479
5493
  "div",
5480
5494
  {
5481
5495
  ref: shellRef,
@@ -5505,7 +5519,7 @@ function ExplainableShell({
5505
5519
  isInSubflow && /* @__PURE__ */ jsx24(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5506
5520
  /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
5507
5521
  /* ── Mobile: stacked vertical ── */
5508
- /* @__PURE__ */ jsxs22(Fragment6, { children: [
5522
+ /* @__PURE__ */ jsxs23(Fragment6, { children: [
5509
5523
  showTopology && /* @__PURE__ */ jsx24("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
5510
5524
  spec: activeSpec,
5511
5525
  snapshots: activeSnapshots,
@@ -5513,7 +5527,7 @@ function ExplainableShell({
5513
5527
  onNodeClick: handleNodeClick,
5514
5528
  showStageId
5515
5529
  }) }),
5516
- showTreeSidebar && /* @__PURE__ */ jsxs22(Fragment6, { children: [
5530
+ showTreeSidebar && /* @__PURE__ */ jsxs23(Fragment6, { children: [
5517
5531
  /* @__PURE__ */ jsx24(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
5518
5532
  leftExpanded && /* @__PURE__ */ jsx24("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ jsx24(
5519
5533
  SubflowTree,
@@ -5532,9 +5546,9 @@ function ExplainableShell({
5532
5546
  ] })
5533
5547
  ) : (
5534
5548
  /* ── Desktop: two-column — Flowchart | Right Panel ── */
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: [
5549
+ /* @__PURE__ */ jsxs23(Fragment6, { children: [
5550
+ /* @__PURE__ */ jsxs23("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
5551
+ showTreeSidebar && (leftExpanded ? /* @__PURE__ */ jsxs23("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
5538
5552
  /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ jsx24(
5539
5553
  SubflowTree,
5540
5554
  {