footprint-explainable-ui 0.3.2 → 0.4.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.
@@ -24,6 +24,7 @@ __export(flowchart_exports, {
24
24
  StageNode: () => StageNode,
25
25
  SubflowBreadcrumb: () => SubflowBreadcrumb,
26
26
  TimeTravelDebugger: () => TimeTravelDebugger,
27
+ TracedFlowchartView: () => TracedFlowchartView,
27
28
  specToReactFlow: () => specToReactFlow,
28
29
  useSubflowNavigation: () => useSubflowNavigation
29
30
  });
@@ -398,75 +399,9 @@ function FlowchartView({
398
399
  );
399
400
  }
400
401
 
401
- // src/components/FlowchartView/SubflowBreadcrumb.tsx
402
- var import_react6 = require("react");
403
- var import_jsx_runtime4 = require("react/jsx-runtime");
404
- var SubflowBreadcrumb = (0, import_react6.memo)(function SubflowBreadcrumb2({
405
- breadcrumbs,
406
- onNavigate
407
- }) {
408
- if (breadcrumbs.length <= 1) return null;
409
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
410
- "div",
411
- {
412
- style: {
413
- display: "flex",
414
- alignItems: "center",
415
- gap: 4,
416
- padding: "6px 12px",
417
- background: theme.bgSecondary,
418
- borderBottom: `1px solid ${theme.border}`,
419
- fontSize: 12,
420
- fontFamily: theme.fontSans,
421
- flexShrink: 0,
422
- overflowX: "auto"
423
- },
424
- children: breadcrumbs.map((crumb, i) => {
425
- const isLast = i === breadcrumbs.length - 1;
426
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
427
- i > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
428
- isLast ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
429
- "span",
430
- {
431
- style: {
432
- color: theme.primary,
433
- fontWeight: 600
434
- },
435
- children: crumb.label
436
- }
437
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
438
- "button",
439
- {
440
- onClick: () => onNavigate(i),
441
- style: {
442
- background: "none",
443
- border: "none",
444
- color: theme.textSecondary,
445
- cursor: "pointer",
446
- padding: "2px 4px",
447
- borderRadius: 4,
448
- fontSize: 12,
449
- fontFamily: "inherit",
450
- fontWeight: 500,
451
- transition: "color 0.15s"
452
- },
453
- onMouseEnter: (e) => {
454
- e.currentTarget.style.color = `${theme.primary}`;
455
- },
456
- onMouseLeave: (e) => {
457
- e.currentTarget.style.color = `${theme.textSecondary}`;
458
- },
459
- children: crumb.label
460
- }
461
- )
462
- ] }, i);
463
- })
464
- }
465
- );
466
- });
467
-
468
- // src/components/FlowchartView/useSubflowNavigation.ts
469
- var import_react7 = require("react");
402
+ // src/components/FlowchartView/TracedFlowchartView.tsx
403
+ var import_react8 = require("react");
404
+ var import_react9 = require("@xyflow/react");
470
405
 
471
406
  // src/components/FlowchartView/specToReactFlow.ts
472
407
  var DEFAULT_COLORS = {
@@ -648,14 +583,15 @@ function specToReactFlow(spec, overlay, colors) {
648
583
  }
649
584
 
650
585
  // src/components/FlowchartView/useSubflowNavigation.ts
586
+ var import_react6 = require("react");
651
587
  function useSubflowNavigation(rootSpec, overlay, colors) {
652
- const [stack, setStack] = (0, import_react7.useState)([]);
588
+ const [stack, setStack] = (0, import_react6.useState)([]);
653
589
  const currentSpec = stack.length > 0 ? stack[stack.length - 1].spec : rootSpec;
654
- const { nodes, edges } = (0, import_react7.useMemo)(() => {
590
+ const { nodes, edges } = (0, import_react6.useMemo)(() => {
655
591
  if (!currentSpec) return { nodes: [], edges: [] };
656
592
  return specToReactFlow(currentSpec, overlay, colors);
657
593
  }, [currentSpec, overlay, colors]);
658
- const subflowMap = (0, import_react7.useMemo)(() => {
594
+ const subflowMap = (0, import_react6.useMemo)(() => {
659
595
  const map = /* @__PURE__ */ new Map();
660
596
  if (!currentSpec) return map;
661
597
  function collectSubflows(node) {
@@ -669,14 +605,14 @@ function useSubflowNavigation(rootSpec, overlay, colors) {
669
605
  collectSubflows(currentSpec);
670
606
  return map;
671
607
  }, [currentSpec]);
672
- const breadcrumbs = (0, import_react7.useMemo)(() => {
608
+ const breadcrumbs = (0, import_react6.useMemo)(() => {
673
609
  const root = {
674
610
  label: rootSpec?.name || "Pipeline",
675
611
  spec: rootSpec
676
612
  };
677
613
  return [root, ...stack];
678
614
  }, [rootSpec, stack]);
679
- const handleNodeClick = (0, import_react7.useCallback)(
615
+ const handleNodeClick = (0, import_react6.useCallback)(
680
616
  (nodeId) => {
681
617
  const subflowNode = subflowMap.get(nodeId);
682
618
  if (!subflowNode?.subflowStructure) return false;
@@ -691,7 +627,7 @@ function useSubflowNavigation(rootSpec, overlay, colors) {
691
627
  },
692
628
  [subflowMap]
693
629
  );
694
- const navigateTo = (0, import_react7.useCallback)(
630
+ const navigateTo = (0, import_react6.useCallback)(
695
631
  (level) => {
696
632
  if (level === 0) {
697
633
  setStack([]);
@@ -712,12 +648,169 @@ function useSubflowNavigation(rootSpec, overlay, colors) {
712
648
  };
713
649
  }
714
650
 
651
+ // src/components/FlowchartView/SubflowBreadcrumb.tsx
652
+ var import_react7 = require("react");
653
+ var import_jsx_runtime4 = require("react/jsx-runtime");
654
+ var SubflowBreadcrumb = (0, import_react7.memo)(function SubflowBreadcrumb2({
655
+ breadcrumbs,
656
+ onNavigate
657
+ }) {
658
+ if (breadcrumbs.length <= 1) return null;
659
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
660
+ "div",
661
+ {
662
+ style: {
663
+ display: "flex",
664
+ alignItems: "center",
665
+ gap: 4,
666
+ padding: "6px 12px",
667
+ background: theme.bgSecondary,
668
+ borderBottom: `1px solid ${theme.border}`,
669
+ fontSize: 12,
670
+ fontFamily: theme.fontSans,
671
+ flexShrink: 0,
672
+ overflowX: "auto"
673
+ },
674
+ children: breadcrumbs.map((crumb, i) => {
675
+ const isLast = i === breadcrumbs.length - 1;
676
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
677
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
678
+ isLast ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
679
+ "span",
680
+ {
681
+ style: {
682
+ color: theme.primary,
683
+ fontWeight: 600
684
+ },
685
+ children: crumb.label
686
+ }
687
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
688
+ "button",
689
+ {
690
+ onClick: () => onNavigate(i),
691
+ style: {
692
+ background: "none",
693
+ border: "none",
694
+ color: theme.textSecondary,
695
+ cursor: "pointer",
696
+ padding: "2px 4px",
697
+ borderRadius: 4,
698
+ fontSize: 12,
699
+ fontFamily: "inherit",
700
+ fontWeight: 500,
701
+ transition: "color 0.15s"
702
+ },
703
+ onMouseEnter: (e) => {
704
+ e.currentTarget.style.color = `${theme.primary}`;
705
+ },
706
+ onMouseLeave: (e) => {
707
+ e.currentTarget.style.color = `${theme.textSecondary}`;
708
+ },
709
+ children: crumb.label
710
+ }
711
+ )
712
+ ] }, i);
713
+ })
714
+ }
715
+ );
716
+ });
717
+
718
+ // src/components/FlowchartView/TracedFlowchartView.tsx
719
+ var import_jsx_runtime5 = require("react/jsx-runtime");
720
+ var nodeTypes2 = { stage: StageNode };
721
+ function TracedFlowchartView({
722
+ spec,
723
+ snapshots,
724
+ snapshotIndex = 0,
725
+ onNodeClick,
726
+ onSubflowChange,
727
+ unstyled = false,
728
+ className,
729
+ style
730
+ }) {
731
+ const subflowNav = useSubflowNavigation(spec);
732
+ const currentSpec = subflowNav.breadcrumbs.length > 0 ? subflowNav.breadcrumbs[subflowNav.breadcrumbs.length - 1].spec : null;
733
+ const overlay = (0, import_react8.useMemo)(() => {
734
+ if (!snapshots || snapshots.length === 0) return void 0;
735
+ const executionOrder = snapshots.slice(0, snapshotIndex + 1).map((s) => s.stageLabel);
736
+ const doneStages = new Set(
737
+ snapshots.slice(0, snapshotIndex).map((s) => s.stageLabel)
738
+ );
739
+ const activeStage = snapshots[snapshotIndex]?.stageLabel ?? null;
740
+ const executedStages = /* @__PURE__ */ new Set([...doneStages]);
741
+ if (activeStage) executedStages.add(activeStage);
742
+ return { doneStages, activeStage, executedStages, executionOrder };
743
+ }, [snapshots, snapshotIndex]);
744
+ const { nodes, edges } = (0, import_react8.useMemo)(() => {
745
+ if (!currentSpec) return { nodes: [], edges: [] };
746
+ return specToReactFlow(currentSpec, overlay);
747
+ }, [currentSpec, overlay]);
748
+ const handleNodeClick = (0, import_react8.useCallback)(
749
+ (_, node) => {
750
+ if (subflowNav.handleNodeClick(node.id)) {
751
+ onSubflowChange?.(true, node.id);
752
+ return;
753
+ }
754
+ if (onNodeClick && snapshots) {
755
+ const idx = snapshots.findIndex((s) => s.stageLabel === node.id);
756
+ if (idx >= 0) onNodeClick(idx);
757
+ } else if (onNodeClick) {
758
+ onNodeClick(node.id);
759
+ }
760
+ },
761
+ [subflowNav, onNodeClick, onSubflowChange, snapshots]
762
+ );
763
+ const handleBreadcrumbNavigate = (0, import_react8.useCallback)(
764
+ (level) => {
765
+ subflowNav.navigateTo(level);
766
+ onSubflowChange?.(level > 0, null);
767
+ },
768
+ [subflowNav, onSubflowChange]
769
+ );
770
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
771
+ "div",
772
+ {
773
+ className,
774
+ style: { width: "100%", height: "100%", display: "flex", flexDirection: "column", ...style },
775
+ "data-fp": "traced-flowchart",
776
+ children: [
777
+ subflowNav.isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
778
+ SubflowBreadcrumb,
779
+ {
780
+ breadcrumbs: subflowNav.breadcrumbs,
781
+ onNavigate: handleBreadcrumbNavigate
782
+ }
783
+ ),
784
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
785
+ import_react9.ReactFlow,
786
+ {
787
+ nodes,
788
+ edges,
789
+ onNodeClick: handleNodeClick,
790
+ nodeTypes: nodeTypes2,
791
+ fitView: true,
792
+ panOnDrag: false,
793
+ zoomOnScroll: false,
794
+ zoomOnPinch: false,
795
+ zoomOnDoubleClick: false,
796
+ preventScrolling: false,
797
+ nodesDraggable: false,
798
+ nodesConnectable: false,
799
+ elementsSelectable: !!onNodeClick,
800
+ children: !unstyled && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react9.Background, { variant: import_react9.BackgroundVariant.Dots, gap: 16, size: 1 })
801
+ }
802
+ ) })
803
+ ]
804
+ }
805
+ );
806
+ }
807
+
715
808
  // src/components/TimeTravelDebugger/TimeTravelDebugger.tsx
716
- var import_react11 = require("react");
809
+ var import_react13 = require("react");
717
810
 
718
811
  // src/components/MemoryInspector/MemoryInspector.tsx
719
- var import_react8 = require("react");
720
- var import_jsx_runtime5 = require("react/jsx-runtime");
812
+ var import_react10 = require("react");
813
+ var import_jsx_runtime6 = require("react/jsx-runtime");
721
814
  function MemoryInspector({
722
815
  data,
723
816
  snapshots,
@@ -729,7 +822,7 @@ function MemoryInspector({
729
822
  className,
730
823
  style
731
824
  }) {
732
- const { memory, newKeys } = (0, import_react8.useMemo)(() => {
825
+ const { memory, newKeys } = (0, import_react10.useMemo)(() => {
733
826
  if (data) {
734
827
  return { memory: data, newKeys: /* @__PURE__ */ new Set() };
735
828
  }
@@ -759,12 +852,12 @@ function MemoryInspector({
759
852
  const fs = fontSize[size];
760
853
  const pad = padding[size];
761
854
  if (unstyled) {
762
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, style, "data-fp": "memory-inspector", children: [
763
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { "data-fp": "memory-label", children: "Memory State" }),
764
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { "data-fp": "memory-json", children: JSON.stringify(memory, null, 2) })
855
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className, style, "data-fp": "memory-inspector", children: [
856
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-fp": "memory-label", children: "Memory State" }),
857
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { "data-fp": "memory-json", children: JSON.stringify(memory, null, 2) })
765
858
  ] });
766
859
  }
767
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
860
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
768
861
  "div",
769
862
  {
770
863
  className,
@@ -775,7 +868,7 @@ function MemoryInspector({
775
868
  },
776
869
  "data-fp": "memory-inspector",
777
870
  children: [
778
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
871
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
779
872
  "span",
780
873
  {
781
874
  style: {
@@ -788,7 +881,7 @@ function MemoryInspector({
788
881
  children: "Memory State"
789
882
  }
790
883
  ),
791
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
884
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
792
885
  "div",
793
886
  {
794
887
  style: {
@@ -802,8 +895,8 @@ function MemoryInspector({
802
895
  lineHeight: 1.8
803
896
  },
804
897
  children: [
805
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: "{" }),
806
- entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
898
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: theme.textMuted }, children: "{" }),
899
+ entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
807
900
  "div",
808
901
  {
809
902
  style: {
@@ -817,7 +910,7 @@ function MemoryInspector({
817
910
  entries.map(([key, value], i) => {
818
911
  const isNew = newKeys.has(key);
819
912
  const isLast = i === entries.length - 1;
820
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
913
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
821
914
  "div",
822
915
  {
823
916
  style: {
@@ -829,14 +922,14 @@ function MemoryInspector({
829
922
  paddingRight: 4
830
923
  },
831
924
  children: [
832
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: { color: theme.primary }, children: [
925
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { color: theme.primary }, children: [
833
926
  '"',
834
927
  key,
835
928
  '"'
836
929
  ] }),
837
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: ": " }),
838
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.success }, children: formatValue(value) }),
839
- showTypes && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
930
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: theme.textMuted }, children: ": " }),
931
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: theme.success }, children: formatValue(value) }),
932
+ showTypes && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
840
933
  "span",
841
934
  {
842
935
  style: {
@@ -852,13 +945,13 @@ function MemoryInspector({
852
945
  ]
853
946
  }
854
947
  ),
855
- !isLast && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: "," })
948
+ !isLast && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: theme.textMuted }, children: "," })
856
949
  ]
857
950
  },
858
951
  key
859
952
  );
860
953
  }),
861
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: "}" })
954
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: theme.textMuted }, children: "}" })
862
955
  ]
863
956
  }
864
957
  )
@@ -873,8 +966,8 @@ function formatValue(value) {
873
966
  }
874
967
 
875
968
  // src/components/NarrativeLog/NarrativeLog.tsx
876
- var import_react9 = require("react");
877
- var import_jsx_runtime6 = require("react/jsx-runtime");
969
+ var import_react11 = require("react");
970
+ var import_jsx_runtime7 = require("react/jsx-runtime");
878
971
  function NarrativeLog({
879
972
  snapshots,
880
973
  selectedIndex,
@@ -884,7 +977,7 @@ function NarrativeLog({
884
977
  className,
885
978
  style
886
979
  }) {
887
- const entries = (0, import_react9.useMemo)(() => {
980
+ const entries = (0, import_react11.useMemo)(() => {
888
981
  if (narrative) {
889
982
  return [{ label: "Output", text: narrative, isCurrent: true }];
890
983
  }
@@ -898,19 +991,19 @@ function NarrativeLog({
898
991
  const fs = fontSize[size];
899
992
  const pad = padding[size];
900
993
  if (unstyled) {
901
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style, "data-fp": "narrative-log", children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-fp": "narrative-entry", "data-current": entry.isCurrent, children: [
902
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: entry.label }),
903
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: entry.text })
994
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className, style, "data-fp": "narrative-log", children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "data-fp": "narrative-entry", "data-current": entry.isCurrent, children: [
995
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: entry.label }),
996
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: entry.text })
904
997
  ] }, i)) });
905
998
  }
906
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
999
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
907
1000
  "div",
908
1001
  {
909
1002
  className,
910
1003
  style: { padding: pad, fontFamily: theme.fontSans, ...style },
911
1004
  "data-fp": "narrative-log",
912
1005
  children: [
913
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1006
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
914
1007
  "span",
915
1008
  {
916
1009
  style: {
@@ -923,7 +1016,7 @@ function NarrativeLog({
923
1016
  children: "Execution Log"
924
1017
  }
925
1018
  ),
926
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginTop: 8, display: "flex", flexDirection: "column" }, children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1019
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 8, display: "flex", flexDirection: "column" }, children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
927
1020
  "div",
928
1021
  {
929
1022
  style: {
@@ -933,7 +1026,7 @@ function NarrativeLog({
933
1026
  borderBottom: i < entries.length - 1 ? `1px solid ${theme.border}` : "none"
934
1027
  },
935
1028
  children: [
936
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1029
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
937
1030
  "div",
938
1031
  {
939
1032
  style: {
@@ -945,7 +1038,7 @@ function NarrativeLog({
945
1038
  paddingTop: 5
946
1039
  },
947
1040
  children: [
948
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1041
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
949
1042
  "div",
950
1043
  {
951
1044
  style: {
@@ -957,7 +1050,7 @@ function NarrativeLog({
957
1050
  }
958
1051
  }
959
1052
  ),
960
- i < entries.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1053
+ i < entries.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
961
1054
  "div",
962
1055
  {
963
1056
  style: {
@@ -971,8 +1064,8 @@ function NarrativeLog({
971
1064
  ]
972
1065
  }
973
1066
  ),
974
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
975
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1067
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1068
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
976
1069
  "span",
977
1070
  {
978
1071
  style: {
@@ -983,7 +1076,7 @@ function NarrativeLog({
983
1076
  children: entry.label
984
1077
  }
985
1078
  ),
986
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1079
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
987
1080
  "div",
988
1081
  {
989
1082
  style: {
@@ -1006,8 +1099,8 @@ function NarrativeLog({
1006
1099
  }
1007
1100
 
1008
1101
  // src/components/GanttTimeline/GanttTimeline.tsx
1009
- var import_react10 = require("react");
1010
- var import_jsx_runtime7 = require("react/jsx-runtime");
1102
+ var import_react12 = require("react");
1103
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1011
1104
  function GanttTimeline({
1012
1105
  snapshots,
1013
1106
  selectedIndex = 0,
@@ -1015,9 +1108,13 @@ function GanttTimeline({
1015
1108
  size = "default",
1016
1109
  unstyled = false,
1017
1110
  className,
1018
- style
1111
+ style,
1112
+ maxVisibleRows = 5
1019
1113
  }) {
1020
- const totalWallTime = (0, import_react10.useMemo)(
1114
+ const [expanded, setExpanded] = (0, import_react12.useState)(false);
1115
+ const activeRowRef = (0, import_react12.useRef)(null);
1116
+ const scrollContainerRef = (0, import_react12.useRef)(null);
1117
+ const totalWallTime = (0, import_react12.useMemo)(
1021
1118
  () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),
1022
1119
  [snapshots]
1023
1120
  );
@@ -1025,8 +1122,19 @@ function GanttTimeline({
1025
1122
  const pad = padding[size];
1026
1123
  const labelWidth = size === "compact" ? 50 : size === "detailed" ? 100 : 80;
1027
1124
  const msWidth = size === "compact" ? 28 : 36;
1125
+ const rowHeight = size === "compact" ? 18 : 22;
1126
+ const collapsible = maxVisibleRows > 0 && snapshots.length > maxVisibleRows;
1127
+ const showAll = expanded || !collapsible;
1128
+ (0, import_react12.useEffect)(() => {
1129
+ if (!showAll && activeRowRef.current && scrollContainerRef.current) {
1130
+ activeRowRef.current.scrollIntoView({
1131
+ block: "nearest",
1132
+ behavior: "smooth"
1133
+ });
1134
+ }
1135
+ }, [selectedIndex, showAll]);
1028
1136
  if (unstyled) {
1029
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className, style, "data-fp": "gantt-timeline", children: snapshots.map((snap, idx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1137
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className, style, "data-fp": "gantt-timeline", children: snapshots.map((snap, idx) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1030
1138
  "div",
1031
1139
  {
1032
1140
  "data-fp": "gantt-bar",
@@ -1034,8 +1142,8 @@ function GanttTimeline({
1034
1142
  "data-visible": idx <= selectedIndex,
1035
1143
  onClick: () => onSelect?.(idx),
1036
1144
  children: [
1037
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "data-fp": "gantt-label", children: snap.stageLabel }),
1038
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-fp": "gantt-duration", children: [
1145
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "data-fp": "gantt-label", children: snap.stageLabel }),
1146
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { "data-fp": "gantt-duration", children: [
1039
1147
  snap.durationMs,
1040
1148
  "ms"
1041
1149
  ] })
@@ -1044,43 +1152,79 @@ function GanttTimeline({
1044
1152
  snap.stageName
1045
1153
  )) });
1046
1154
  }
1047
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1155
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1048
1156
  "div",
1049
1157
  {
1050
1158
  className,
1051
1159
  style: { padding: pad, fontFamily: theme.fontSans, ...style },
1052
1160
  "data-fp": "gantt-timeline",
1053
1161
  children: [
1054
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1055
- "span",
1162
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1163
+ "div",
1056
1164
  {
1057
1165
  style: {
1058
- fontSize: fs.label,
1059
- fontWeight: 600,
1060
- color: theme.textMuted,
1061
- textTransform: "uppercase",
1062
- letterSpacing: "0.08em"
1166
+ display: "flex",
1167
+ alignItems: "center",
1168
+ justifyContent: "space-between"
1063
1169
  },
1064
- children: size === "compact" ? "Timeline" : "Execution Timeline"
1170
+ children: [
1171
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1172
+ "span",
1173
+ {
1174
+ style: {
1175
+ fontSize: fs.label,
1176
+ fontWeight: 600,
1177
+ color: theme.textMuted,
1178
+ textTransform: "uppercase",
1179
+ letterSpacing: "0.08em"
1180
+ },
1181
+ children: size === "compact" ? "Timeline" : "Execution Timeline"
1182
+ }
1183
+ ),
1184
+ collapsible && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1185
+ "button",
1186
+ {
1187
+ onClick: () => setExpanded((e) => !e),
1188
+ style: {
1189
+ background: "none",
1190
+ border: `1px solid ${theme.border}`,
1191
+ borderRadius: 4,
1192
+ color: theme.textSecondary,
1193
+ fontSize: fs.small,
1194
+ padding: "2px 8px",
1195
+ cursor: "pointer",
1196
+ fontFamily: theme.fontSans
1197
+ },
1198
+ children: expanded ? "Collapse" : `${snapshots.length - maxVisibleRows} more...`
1199
+ }
1200
+ )
1201
+ ]
1065
1202
  }
1066
1203
  ),
1067
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1204
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1068
1205
  "div",
1069
1206
  {
1207
+ ref: scrollContainerRef,
1070
1208
  style: {
1071
1209
  marginTop: 8,
1072
1210
  display: "flex",
1073
1211
  flexDirection: "column",
1074
- gap: 4
1212
+ gap: 4,
1213
+ ...showAll ? {} : {
1214
+ maxHeight: maxVisibleRows * (rowHeight + 4),
1215
+ overflowY: "auto",
1216
+ scrollbarWidth: "thin"
1217
+ }
1075
1218
  },
1076
1219
  children: snapshots.map((snap, idx) => {
1077
1220
  const leftPct = snap.startMs / totalWallTime * 100;
1078
1221
  const widthPct = Math.max(snap.durationMs / totalWallTime * 100, 1);
1079
1222
  const isSelected = idx === selectedIndex;
1080
1223
  const isVisible = idx <= selectedIndex;
1081
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1224
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1082
1225
  "div",
1083
1226
  {
1227
+ ref: isSelected ? activeRowRef : void 0,
1084
1228
  onClick: () => onSelect?.(idx),
1085
1229
  style: {
1086
1230
  display: "flex",
@@ -1088,10 +1232,12 @@ function GanttTimeline({
1088
1232
  gap: size === "compact" ? 4 : 8,
1089
1233
  cursor: onSelect ? "pointer" : "default",
1090
1234
  opacity: isVisible ? 1 : 0.3,
1091
- transition: "opacity 0.3s ease"
1235
+ transition: "opacity 0.3s ease",
1236
+ height: rowHeight,
1237
+ flexShrink: 0
1092
1238
  },
1093
1239
  children: [
1094
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1240
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1095
1241
  "span",
1096
1242
  {
1097
1243
  style: {
@@ -1108,7 +1254,7 @@ function GanttTimeline({
1108
1254
  children: snap.stageLabel
1109
1255
  }
1110
1256
  ),
1111
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1257
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1112
1258
  "div",
1113
1259
  {
1114
1260
  style: {
@@ -1118,7 +1264,7 @@ function GanttTimeline({
1118
1264
  background: theme.bgTertiary,
1119
1265
  borderRadius: 3
1120
1266
  },
1121
- children: isVisible && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1267
+ children: isVisible && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1122
1268
  "div",
1123
1269
  {
1124
1270
  style: {
@@ -1135,7 +1281,7 @@ function GanttTimeline({
1135
1281
  )
1136
1282
  }
1137
1283
  ),
1138
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1284
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1139
1285
  "span",
1140
1286
  {
1141
1287
  style: {
@@ -1158,7 +1304,7 @@ function GanttTimeline({
1158
1304
  })
1159
1305
  }
1160
1306
  ),
1161
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1307
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1162
1308
  "div",
1163
1309
  {
1164
1310
  style: {
@@ -1172,12 +1318,12 @@ function GanttTimeline({
1172
1318
  fontFamily: theme.fontMono
1173
1319
  },
1174
1320
  children: [
1175
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "0ms" }),
1176
- size !== "compact" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1321
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "0ms" }),
1322
+ size !== "compact" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1177
1323
  (totalWallTime / 2).toFixed(1),
1178
1324
  "ms"
1179
1325
  ] }),
1180
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1326
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1181
1327
  totalWallTime.toFixed(1),
1182
1328
  "ms"
1183
1329
  ] })
@@ -1190,7 +1336,7 @@ function GanttTimeline({
1190
1336
  }
1191
1337
 
1192
1338
  // src/components/TimeTravelDebugger/TimeTravelDebugger.tsx
1193
- var import_jsx_runtime8 = require("react/jsx-runtime");
1339
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1194
1340
  function TimeTravelDebugger({
1195
1341
  snapshots,
1196
1342
  nodes,
@@ -1203,11 +1349,11 @@ function TimeTravelDebugger({
1203
1349
  className,
1204
1350
  style
1205
1351
  }) {
1206
- const [selectedIndex, setSelectedIndex] = (0, import_react11.useState)(0);
1352
+ const [selectedIndex, setSelectedIndex] = (0, import_react13.useState)(0);
1207
1353
  const fs = fontSize[size];
1208
1354
  const pad = padding[size];
1209
1355
  if (snapshots.length === 0) {
1210
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1356
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1211
1357
  "div",
1212
1358
  {
1213
1359
  className,
@@ -1223,9 +1369,9 @@ function TimeTravelDebugger({
1223
1369
  }
1224
1370
  const isHorizontal = layout === "horizontal";
1225
1371
  if (unstyled) {
1226
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className, style, "data-fp": "time-travel-debugger", children: [
1227
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: title }),
1228
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1372
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className, style, "data-fp": "time-travel-debugger", children: [
1373
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: title }),
1374
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1229
1375
  "input",
1230
1376
  {
1231
1377
  type: "range",
@@ -1235,7 +1381,7 @@ function TimeTravelDebugger({
1235
1381
  onChange: (e) => setSelectedIndex(parseInt(e.target.value))
1236
1382
  }
1237
1383
  ),
1238
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1384
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1239
1385
  FlowchartView,
1240
1386
  {
1241
1387
  nodes,
@@ -1246,7 +1392,7 @@ function TimeTravelDebugger({
1246
1392
  unstyled: true
1247
1393
  }
1248
1394
  ),
1249
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1395
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1250
1396
  MemoryInspector,
1251
1397
  {
1252
1398
  snapshots,
@@ -1254,7 +1400,7 @@ function TimeTravelDebugger({
1254
1400
  unstyled: true
1255
1401
  }
1256
1402
  ),
1257
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1403
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1258
1404
  NarrativeLog,
1259
1405
  {
1260
1406
  snapshots,
@@ -1262,7 +1408,7 @@ function TimeTravelDebugger({
1262
1408
  unstyled: true
1263
1409
  }
1264
1410
  ),
1265
- showGantt && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1411
+ showGantt && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1266
1412
  GanttTimeline,
1267
1413
  {
1268
1414
  snapshots,
@@ -1273,7 +1419,7 @@ function TimeTravelDebugger({
1273
1419
  )
1274
1420
  ] });
1275
1421
  }
1276
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1422
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1277
1423
  "div",
1278
1424
  {
1279
1425
  className,
@@ -1288,7 +1434,7 @@ function TimeTravelDebugger({
1288
1434
  },
1289
1435
  "data-fp": "time-travel-debugger",
1290
1436
  children: [
1291
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1437
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1292
1438
  "div",
1293
1439
  {
1294
1440
  style: {
@@ -1298,7 +1444,7 @@ function TimeTravelDebugger({
1298
1444
  flexShrink: 0
1299
1445
  },
1300
1446
  children: [
1301
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1447
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1302
1448
  "div",
1303
1449
  {
1304
1450
  style: {
@@ -1308,7 +1454,7 @@ function TimeTravelDebugger({
1308
1454
  marginBottom: 8
1309
1455
  },
1310
1456
  children: [
1311
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1457
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1312
1458
  "span",
1313
1459
  {
1314
1460
  style: {
@@ -1319,7 +1465,7 @@ function TimeTravelDebugger({
1319
1465
  children: title
1320
1466
  }
1321
1467
  ),
1322
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1468
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1323
1469
  "span",
1324
1470
  {
1325
1471
  style: {
@@ -1332,8 +1478,8 @@ function TimeTravelDebugger({
1332
1478
  ]
1333
1479
  }
1334
1480
  ),
1335
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1336
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1481
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1482
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1337
1483
  ScrubButton,
1338
1484
  {
1339
1485
  label: "\\u25C0",
@@ -1341,7 +1487,7 @@ function TimeTravelDebugger({
1341
1487
  onClick: () => setSelectedIndex((i) => Math.max(0, i - 1))
1342
1488
  }
1343
1489
  ),
1344
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1490
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1345
1491
  "input",
1346
1492
  {
1347
1493
  type: "range",
@@ -1357,7 +1503,7 @@ function TimeTravelDebugger({
1357
1503
  }
1358
1504
  }
1359
1505
  ),
1360
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1506
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1361
1507
  ScrubButton,
1362
1508
  {
1363
1509
  label: "\\u25B6",
@@ -1365,7 +1511,7 @@ function TimeTravelDebugger({
1365
1511
  onClick: () => setSelectedIndex((i) => Math.min(snapshots.length - 1, i + 1))
1366
1512
  }
1367
1513
  ),
1368
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1514
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1369
1515
  "span",
1370
1516
  {
1371
1517
  style: {
@@ -1385,7 +1531,7 @@ function TimeTravelDebugger({
1385
1531
  ]
1386
1532
  }
1387
1533
  ),
1388
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1534
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1389
1535
  "div",
1390
1536
  {
1391
1537
  style: {
@@ -1395,7 +1541,7 @@ function TimeTravelDebugger({
1395
1541
  overflow: "hidden"
1396
1542
  },
1397
1543
  children: [
1398
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1544
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1399
1545
  "div",
1400
1546
  {
1401
1547
  style: {
@@ -1404,7 +1550,7 @@ function TimeTravelDebugger({
1404
1550
  borderRight: isHorizontal ? `1px solid ${theme.border}` : "none",
1405
1551
  borderBottom: !isHorizontal ? `1px solid ${theme.border}` : "none"
1406
1552
  },
1407
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1553
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1408
1554
  FlowchartView,
1409
1555
  {
1410
1556
  nodes,
@@ -1417,8 +1563,8 @@ function TimeTravelDebugger({
1417
1563
  )
1418
1564
  }
1419
1565
  ),
1420
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
1421
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1566
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
1567
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1422
1568
  MemoryInspector,
1423
1569
  {
1424
1570
  snapshots,
@@ -1426,7 +1572,7 @@ function TimeTravelDebugger({
1426
1572
  size
1427
1573
  }
1428
1574
  ),
1429
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1575
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1430
1576
  "div",
1431
1577
  {
1432
1578
  style: {
@@ -1436,7 +1582,7 @@ function TimeTravelDebugger({
1436
1582
  }
1437
1583
  }
1438
1584
  ),
1439
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1585
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1440
1586
  NarrativeLog,
1441
1587
  {
1442
1588
  snapshots,
@@ -1448,7 +1594,7 @@ function TimeTravelDebugger({
1448
1594
  ]
1449
1595
  }
1450
1596
  ),
1451
- showGantt && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1597
+ showGantt && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1452
1598
  "div",
1453
1599
  {
1454
1600
  style: {
@@ -1456,7 +1602,7 @@ function TimeTravelDebugger({
1456
1602
  background: theme.bgSecondary,
1457
1603
  flexShrink: 0
1458
1604
  },
1459
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1605
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1460
1606
  GanttTimeline,
1461
1607
  {
1462
1608
  snapshots,
@@ -1476,7 +1622,7 @@ function ScrubButton({
1476
1622
  disabled,
1477
1623
  onClick
1478
1624
  }) {
1479
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1625
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1480
1626
  "button",
1481
1627
  {
1482
1628
  onClick,
@@ -1506,6 +1652,7 @@ function ScrubButton({
1506
1652
  StageNode,
1507
1653
  SubflowBreadcrumb,
1508
1654
  TimeTravelDebugger,
1655
+ TracedFlowchartView,
1509
1656
  specToReactFlow,
1510
1657
  useSubflowNavigation
1511
1658
  });