executable-stories-react 0.15.0 → 0.16.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.
@@ -48,8 +48,8 @@ module.exports = __toCommonJS(interactive_exports);
48
48
 
49
49
  // src/interactive/ReportInteractive.tsx
50
50
  var import_lucide_react7 = require("lucide-react");
51
- var import_react23 = require("webmcpable/react");
52
- var import_react24 = require("react");
51
+ var import_react25 = require("webmcpable/react");
52
+ var import_react26 = require("react");
53
53
 
54
54
  // src/components/ui/empty.tsx
55
55
  var import_class_variance_authority = require("class-variance-authority");
@@ -420,12 +420,29 @@ function DocVideo({ entry }) {
420
420
  }
421
421
 
422
422
  // src/components/doc/DocHtml.tsx
423
+ var import_react4 = require("react");
423
424
  var import_jsx_runtime14 = require("react/jsx-runtime");
425
+ var MEASURE_SCRIPT = "<script>(function(){if(parent===window)return;var last=0,queued=false;var measure=function(){var kids=document.body.children,h=0;for(var i=0;i<kids.length;i++)h=Math.max(h,kids[i].getBoundingClientRect().bottom);return Math.ceil(h||document.body.getBoundingClientRect().bottom)};var post=function(){queued=false;var h=measure();if(h===last)return;last=h;parent.postMessage({__esHtmlHeight:h},'*')};var schedule=function(){if(queued)return;queued=true;requestAnimationFrame(post)};var start=function(){new ResizeObserver(schedule).observe(document.body);new MutationObserver(schedule).observe(document.body,{subtree:true,childList:true,attributes:true,characterData:true});addEventListener('load',schedule);post()};if(document.body)start();else addEventListener('DOMContentLoaded',start)})();</script>";
426
+ var MAX_MEASURED_HEIGHT = 5e3;
424
427
  function DocHtml({ entry }) {
425
- const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
428
+ const declaredHeight = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
426
429
  const title = entry.title ?? "Embedded HTML";
427
430
  const safeHref = (0, import_url.safeUrl)(entry.url ?? entry.path);
428
- const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
431
+ const frameRef = (0, import_react4.useRef)(null);
432
+ const [measuredHeight, setMeasuredHeight] = (0, import_react4.useState)();
433
+ (0, import_react4.useEffect)(() => {
434
+ if (entry.content === void 0) return;
435
+ const onMessage = (event) => {
436
+ if (event.source !== frameRef.current?.contentWindow) return;
437
+ const reported = event.data?.__esHtmlHeight;
438
+ if (typeof reported !== "number" || !Number.isFinite(reported) || reported <= 0) return;
439
+ setMeasuredHeight(Math.min(reported, MAX_MEASURED_HEIGHT));
440
+ };
441
+ window.addEventListener("message", onMessage);
442
+ return () => window.removeEventListener("message", onMessage);
443
+ }, [entry.content]);
444
+ const height = measuredHeight === void 0 ? declaredHeight : `${measuredHeight}px`;
445
+ const frameProps = entry.content !== void 0 ? { srcDoc: entry.content + MEASURE_SCRIPT } : { src: safeHref ?? "" };
429
446
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
430
447
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("figcaption", { className: "flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground", children: [
431
448
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: entry.title ?? "HTML" }),
@@ -445,6 +462,7 @@ function DocHtml({ entry }) {
445
462
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
446
463
  "iframe",
447
464
  {
465
+ ref: frameRef,
448
466
  ...frameProps,
449
467
  sandbox: "allow-scripts",
450
468
  loading: "lazy",
@@ -898,11 +916,11 @@ function ReportTrace({ spans }) {
898
916
  }
899
917
 
900
918
  // src/interactive/scenario-history-context.ts
901
- var import_react4 = require("react");
902
- var ScenarioHistoryContext = (0, import_react4.createContext)(null);
919
+ var import_react5 = require("react");
920
+ var ScenarioHistoryContext = (0, import_react5.createContext)(null);
903
921
  var ScenarioHistoryProvider = ScenarioHistoryContext.Provider;
904
922
  function useScenarioHistory() {
905
- return (0, import_react4.useContext)(ScenarioHistoryContext);
923
+ return (0, import_react5.useContext)(ScenarioHistoryContext);
906
924
  }
907
925
 
908
926
  // src/lib/run-history.ts
@@ -1011,7 +1029,7 @@ function ScenarioRunHistory({ scenarioId }) {
1011
1029
  }
1012
1030
 
1013
1031
  // src/components/ScenarioStaleness.tsx
1014
- var import_react6 = require("react");
1032
+ var import_react7 = require("react");
1015
1033
 
1016
1034
  // src/lib/provenance.ts
1017
1035
  function reportLastRunMs(report) {
@@ -1063,11 +1081,11 @@ function prUrl(ci) {
1063
1081
  }
1064
1082
 
1065
1083
  // src/interactive/scenario-freshness-context.tsx
1066
- var import_react5 = require("react");
1067
- var ScenarioFreshnessContext = (0, import_react5.createContext)(null);
1084
+ var import_react6 = require("react");
1085
+ var ScenarioFreshnessContext = (0, import_react6.createContext)(null);
1068
1086
  var ScenarioFreshnessProvider = ScenarioFreshnessContext.Provider;
1069
1087
  function useScenarioFreshness() {
1070
- return (0, import_react5.useContext)(ScenarioFreshnessContext);
1088
+ return (0, import_react6.useContext)(ScenarioFreshnessContext);
1071
1089
  }
1072
1090
 
1073
1091
  // src/components/ScenarioStaleness.tsx
@@ -1075,8 +1093,8 @@ var import_jsx_runtime24 = require("react/jsx-runtime");
1075
1093
  function ScenarioStaleness({ scenario }) {
1076
1094
  const freshness = useScenarioFreshness();
1077
1095
  const fixedNow = freshness?.nowMs;
1078
- const [now, setNow] = (0, import_react6.useState)(fixedNow);
1079
- (0, import_react6.useEffect)(() => {
1096
+ const [now, setNow] = (0, import_react7.useState)(fixedNow);
1097
+ (0, import_react7.useEffect)(() => {
1080
1098
  if (fixedNow === void 0) setNow(Date.now());
1081
1099
  }, [fixedNow]);
1082
1100
  if (!freshness || now === void 0) return null;
@@ -1090,11 +1108,11 @@ function ScenarioStaleness({ scenario }) {
1090
1108
  }
1091
1109
 
1092
1110
  // src/interactive/collapse-context.ts
1093
- var import_react7 = require("react");
1094
- var CollapseContext = (0, import_react7.createContext)(null);
1111
+ var import_react8 = require("react");
1112
+ var CollapseContext = (0, import_react8.createContext)(null);
1095
1113
  var CollapseProvider = CollapseContext.Provider;
1096
1114
  function useCollapse() {
1097
- return (0, import_react7.useContext)(CollapseContext);
1115
+ return (0, import_react8.useContext)(CollapseContext);
1098
1116
  }
1099
1117
  var STORAGE_KEY = "es-collapsed-ids";
1100
1118
  function readPersisted() {
@@ -1114,11 +1132,11 @@ function persist(ids) {
1114
1132
  }
1115
1133
  }
1116
1134
  function useCollapseState(computeDefault) {
1117
- const [collapsed, setCollapsed] = (0, import_react7.useState)(
1135
+ const [collapsed, setCollapsed] = (0, import_react8.useState)(
1118
1136
  () => readPersisted() ?? computeDefault?.() ?? /* @__PURE__ */ new Set()
1119
1137
  );
1120
- const isCollapsed = (0, import_react7.useCallback)((id) => collapsed.has(id), [collapsed]);
1121
- const toggle = (0, import_react7.useCallback)((id) => {
1138
+ const isCollapsed = (0, import_react8.useCallback)((id) => collapsed.has(id), [collapsed]);
1139
+ const toggle = (0, import_react8.useCallback)((id) => {
1122
1140
  setCollapsed((prev) => {
1123
1141
  const next = new Set(prev);
1124
1142
  if (next.has(id)) next.delete(id);
@@ -1127,14 +1145,14 @@ function useCollapseState(computeDefault) {
1127
1145
  return next;
1128
1146
  });
1129
1147
  }, []);
1130
- const collapseAll = (0, import_react7.useCallback)((ids) => {
1148
+ const collapseAll = (0, import_react8.useCallback)((ids) => {
1131
1149
  setCollapsed(() => {
1132
1150
  const next = new Set(ids);
1133
1151
  persist(next);
1134
1152
  return next;
1135
1153
  });
1136
1154
  }, []);
1137
- const expandAll = (0, import_react7.useCallback)(() => {
1155
+ const expandAll = (0, import_react8.useCallback)(() => {
1138
1156
  setCollapsed(() => {
1139
1157
  const next = /* @__PURE__ */ new Set();
1140
1158
  persist(next);
@@ -1145,12 +1163,12 @@ function useCollapseState(computeDefault) {
1145
1163
  }
1146
1164
 
1147
1165
  // src/interactive/scenario-actions.tsx
1148
- var import_react8 = require("react");
1166
+ var import_react9 = require("react");
1149
1167
  var import_scenario_markdown = require("executable-stories-core/utils/scenario-markdown");
1150
- var ScenarioActionsContext = (0, import_react8.createContext)(null);
1168
+ var ScenarioActionsContext = (0, import_react9.createContext)(null);
1151
1169
  var ScenarioActionsProvider = ScenarioActionsContext.Provider;
1152
1170
  function useScenarioActions() {
1153
- return (0, import_react8.useContext)(ScenarioActionsContext);
1171
+ return (0, import_react9.useContext)(ScenarioActionsContext);
1154
1172
  }
1155
1173
  function scenarioToMarkdown(scenario) {
1156
1174
  return (0, import_scenario_markdown.scenarioToMarkdown)(scenario, { variant: "compact" });
@@ -1688,15 +1706,75 @@ function ReportErrorShell({
1688
1706
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportSchemaError, { error }) });
1689
1707
  }
1690
1708
 
1709
+ // src/components/ReportSpanGraph.tsx
1710
+ var import_span_graph = require("executable-stories-core/span-graph");
1711
+ var import_react10 = require("react");
1712
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1713
+ var LANE_LABEL = {
1714
+ edge: "Edge",
1715
+ service: "Service",
1716
+ queue: "Queue",
1717
+ datastore: "Data"
1718
+ };
1719
+ var MARK_LABEL = {
1720
+ failing: "Failing",
1721
+ added: "New",
1722
+ changed: "Changed"
1723
+ };
1724
+ var MARK_CLASS = {
1725
+ failing: "text-fail",
1726
+ added: "text-pass",
1727
+ changed: "text-pend"
1728
+ };
1729
+ function MarkBadge({ node }) {
1730
+ const mark = (0, import_span_graph.spanGraphNodeMark)(node);
1731
+ if (!mark) return null;
1732
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: cn("ml-2 text-xs font-medium", MARK_CLASS[mark]), children: MARK_LABEL[mark] });
1733
+ }
1734
+ function ReportSpanGraph() {
1735
+ const report = useReport();
1736
+ const { code, graph, titleById } = (0, import_react10.useMemo)(() => {
1737
+ const scenarios = report.features.flatMap((feature) => feature.scenarios);
1738
+ const derived = (0, import_span_graph.deriveSpanGraph)(scenarios);
1739
+ return {
1740
+ graph: derived,
1741
+ code: (0, import_span_graph.spanGraphToMermaid)(derived),
1742
+ titleById: new Map(scenarios.map((scenario) => [scenario.id, scenario.title]))
1743
+ };
1744
+ }, [report]);
1745
+ if (code === "") return null;
1746
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: "es-span-graph mt-6", "aria-labelledby": "es-span-graph-heading", children: [
1747
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h2", { id: "es-span-graph-heading", className: "text-base font-semibold text-foreground", children: "Architecture, as it ran" }),
1748
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: "Derived from this run\u2019s traces. Every component was named by a span while a scenario ran, so nothing here is inferred from the code. Instrumented, exercised paths only: a component no scenario reaches does not appear." }),
1749
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(DocMermaid, { entry: { kind: "mermaid", phase: "static", code } }),
1750
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("table", { className: "mt-2 w-full text-left text-sm", children: [
1751
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("caption", { className: "sr-only", children: "Each component and the scenarios that exercised it" }),
1752
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("tr", { className: "text-xs text-muted-foreground", children: [
1753
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Component" }),
1754
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Lane" }),
1755
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { scope: "col", className: "py-1 font-medium", children: "Covered by" })
1756
+ ] }) }),
1757
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tbody", { children: graph.nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("tr", { className: "border-t border-border align-top", children: [
1758
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("th", { scope: "row", className: "py-1.5 pr-4 font-mono text-xs font-normal", children: [
1759
+ node.id,
1760
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MarkBadge, { node })
1761
+ ] }),
1762
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "py-1.5 pr-4 text-xs text-muted-foreground", children: LANE_LABEL[node.kind] }),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "py-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { className: "flex flex-col gap-0.5", children: node.scenarioIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("a", { href: `#${id}`, className: "text-xs underline underline-offset-2", children: titleById.get(id) ?? id }) }, id)) }) })
1764
+ ] }, node.id)) })
1765
+ ] })
1766
+ ] });
1767
+ }
1768
+
1691
1769
  // src/components/ui/switch.tsx
1692
1770
  var React4 = require("react");
1693
1771
  var import_switch = require("@base-ui/react/switch");
1694
- var import_jsx_runtime36 = require("react/jsx-runtime");
1772
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1695
1773
  function Switch({
1696
1774
  className,
1697
1775
  ...props
1698
1776
  }) {
1699
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1777
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1700
1778
  import_switch.Switch.Root,
1701
1779
  {
1702
1780
  "data-slot": "switch",
@@ -1705,7 +1783,7 @@ function Switch({
1705
1783
  className
1706
1784
  ),
1707
1785
  ...props,
1708
- children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1786
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1709
1787
  import_switch.Switch.Thumb,
1710
1788
  {
1711
1789
  "data-slot": "switch-thumb",
@@ -1721,7 +1799,7 @@ var React5 = __toESM(require("react"), 1);
1721
1799
  var import_toggle_group = require("@base-ui/react/toggle-group");
1722
1800
  var import_toggle = require("@base-ui/react/toggle");
1723
1801
  var import_class_variance_authority3 = require("class-variance-authority");
1724
- var import_jsx_runtime37 = require("react/jsx-runtime");
1802
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1725
1803
  var toggleItemVariants = (0, import_class_variance_authority3.cva)(
1726
1804
  "inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-background data-[pressed]:text-foreground data-[pressed]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1727
1805
  {
@@ -1743,13 +1821,13 @@ function ToggleGroup({
1743
1821
  children,
1744
1822
  ...props
1745
1823
  }) {
1746
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1824
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1747
1825
  import_toggle_group.ToggleGroup,
1748
1826
  {
1749
1827
  "data-slot": "toggle-group",
1750
1828
  className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
1751
1829
  ...props,
1752
- children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ToggleGroupContext.Provider, { value: { size }, children })
1830
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ToggleGroupContext.Provider, { value: { size }, children })
1753
1831
  }
1754
1832
  );
1755
1833
  }
@@ -1760,7 +1838,7 @@ function ToggleGroupItem({
1760
1838
  ...props
1761
1839
  }) {
1762
1840
  const context = React5.useContext(ToggleGroupContext);
1763
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1841
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1764
1842
  import_toggle.Toggle,
1765
1843
  {
1766
1844
  "data-slot": "toggle-group-item",
@@ -1772,10 +1850,10 @@ function ToggleGroupItem({
1772
1850
  }
1773
1851
 
1774
1852
  // src/context/ReportRoot.tsx
1775
- var import_react9 = require("react");
1853
+ var import_react11 = require("react");
1776
1854
 
1777
1855
  // src/components/doc/NarrativeBlocks.tsx
1778
- var import_jsx_runtime38 = require("react/jsx-runtime");
1856
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1779
1857
  var FILE_TREE_TYPE = "file-tree";
1780
1858
  var DATA_MODEL_TYPE = "data-model";
1781
1859
  function isChangeKind(value) {
@@ -1789,23 +1867,23 @@ function str(value) {
1789
1867
  }
1790
1868
  function AuthoredMarker({ authored }) {
1791
1869
  if (authored !== "agent") return null;
1792
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
1870
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
1793
1871
  }
1794
1872
  function BlockFrame({
1795
1873
  title,
1796
1874
  authored,
1797
1875
  children
1798
1876
  }) {
1799
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("figure", { className: "my-3", children: [
1800
- title || authored === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
1801
- title ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
1802
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(AuthoredMarker, { authored })
1877
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("figure", { className: "my-3", children: [
1878
+ title || authored === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
1879
+ title ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
1880
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(AuthoredMarker, { authored })
1803
1881
  ] }) : null,
1804
1882
  children
1805
1883
  ] });
1806
1884
  }
1807
1885
  function ChangeBadge({ change }) {
1808
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Badge, { variant: "tag", className: "text-[10px]", children: change });
1886
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: "tag", className: "text-[10px]", children: change });
1809
1887
  }
1810
1888
  function parseFileTree(data) {
1811
1889
  if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
@@ -1854,11 +1932,11 @@ function sortedChildren(node) {
1854
1932
  }
1855
1933
  function TreeBranch({ node, depth }) {
1856
1934
  const children = sortedChildren(node);
1857
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
1935
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
1858
1936
  const isDir = child.children.size > 0;
1859
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("li", { children: [
1860
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-wrap items-baseline gap-2", children: [
1861
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1937
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("li", { children: [
1938
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-wrap items-baseline gap-2", children: [
1939
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1862
1940
  "span",
1863
1941
  {
1864
1942
  className: cn(
@@ -1868,17 +1946,17 @@ function TreeBranch({ node, depth }) {
1868
1946
  children: isDir ? `${child.name}/` : child.name
1869
1947
  }
1870
1948
  ),
1871
- child.file?.change ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ChangeBadge, { change: child.file.change }) : null,
1872
- child.file?.note ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
1949
+ child.file?.change ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ChangeBadge, { change: child.file.change }) : null,
1950
+ child.file?.note ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
1873
1951
  ] }),
1874
- isDir ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TreeBranch, { node: child, depth: depth + 1 }) : null
1952
+ isDir ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TreeBranch, { node: child, depth: depth + 1 }) : null
1875
1953
  ] }, child.name);
1876
1954
  }) });
1877
1955
  }
1878
1956
  function FileTreeBlock({ entry }) {
1879
1957
  const data = parseFileTree(entry.data);
1880
- if (!data) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(UnreadableBlock, { entry });
1881
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
1958
+ if (!data) return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(UnreadableBlock, { entry });
1959
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
1882
1960
  }
1883
1961
  function parseDataModel(data) {
1884
1962
  if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
@@ -1904,31 +1982,31 @@ function parseDataModel(data) {
1904
1982
  }
1905
1983
  function DataModelBlock({ entry }) {
1906
1984
  const data = parseDataModel(entry.data);
1907
- if (!data) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(UnreadableBlock, { entry });
1985
+ if (!data) return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(UnreadableBlock, { entry });
1908
1986
  const hasNotes = data.fields.some((f) => f.note);
1909
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
1910
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("tr", { className: "bg-muted/50", children: [
1911
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
1912
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
1913
- hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
1987
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
1988
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("tr", { className: "bg-muted/50", children: [
1989
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
1990
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
1991
+ hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
1914
1992
  ] }) }),
1915
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("tbody", { children: data.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("tr", { children: [
1916
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "flex flex-wrap items-center gap-2", children: [
1917
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "font-mono text-xs text-foreground", children: field.name }),
1918
- field.change ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ChangeBadge, { change: field.change }) : null
1993
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("tbody", { children: data.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("tr", { children: [
1994
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "flex flex-wrap items-center gap-2", children: [
1995
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "font-mono text-xs text-foreground", children: field.name }),
1996
+ field.change ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ChangeBadge, { change: field.change }) : null
1919
1997
  ] }) }),
1920
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
1921
- hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
1998
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
1999
+ hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
1922
2000
  ] }, field.name)) })
1923
2001
  ] }) }) });
1924
2002
  }
1925
2003
  function UnreadableBlock({ entry }) {
1926
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
1927
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
2004
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
2005
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
1928
2006
  entry.type,
1929
2007
  " (unrecognised shape)"
1930
2008
  ] }),
1931
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2009
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1932
2010
  "pre",
1933
2011
  {
1934
2012
  tabIndex: 0,
@@ -1946,12 +2024,12 @@ function safeStringify2(value) {
1946
2024
  }
1947
2025
  }
1948
2026
  var narrativeBlockRenderers = {
1949
- [FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FileTreeBlock, { entry }),
1950
- [DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(DataModelBlock, { entry })
2027
+ [FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(FileTreeBlock, { entry }),
2028
+ [DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(DataModelBlock, { entry })
1951
2029
  };
1952
2030
 
1953
2031
  // src/context/ReportRoot.tsx
1954
- var import_jsx_runtime39 = require("react/jsx-runtime");
2032
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1955
2033
  var EMPTY_RENDERERS2 = {};
1956
2034
  function ReportRoot({
1957
2035
  report,
@@ -1959,7 +2037,7 @@ function ReportRoot({
1959
2037
  renderers,
1960
2038
  children
1961
2039
  }) {
1962
- const value = (0, import_react9.useMemo)(
2040
+ const value = (0, import_react11.useMemo)(
1963
2041
  () => ({
1964
2042
  report,
1965
2043
  // Narrative blocks render everywhere the report does (static SSR, the
@@ -1970,7 +2048,7 @@ function ReportRoot({
1970
2048
  }),
1971
2049
  [report, customRenderers, renderers]
1972
2050
  );
1973
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportContext.Provider, { value, children });
2051
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ReportContext.Provider, { value, children });
1974
2052
  }
1975
2053
 
1976
2054
  // src/lib/hash-state.ts
@@ -2156,7 +2234,7 @@ function listFailures(report) {
2156
2234
 
2157
2235
  // src/interactive/ReportAgentFilterNotice.tsx
2158
2236
  var import_lucide_react3 = require("lucide-react");
2159
- var import_jsx_runtime40 = require("react/jsx-runtime");
2237
+ var import_jsx_runtime41 = require("react/jsx-runtime");
2160
2238
  function ReportAgentFilterNotice({
2161
2239
  applied,
2162
2240
  onReset,
@@ -2166,23 +2244,23 @@ function ReportAgentFilterNotice({
2166
2244
  if (applied.search) terms.push(`matching \u201C${applied.search}\u201D`);
2167
2245
  if (applied.status !== "all") terms.push(applied.status);
2168
2246
  if (applied.tags.length > 0) terms.push(applied.tags.join(", "));
2169
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2247
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
2170
2248
  "div",
2171
2249
  {
2172
2250
  role: "status",
2173
2251
  "aria-live": "polite",
2174
2252
  className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-md border border-primary/40 bg-primary/5 px-3 py-2 text-sm",
2175
2253
  children: [
2176
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react3.Bot, { "aria-hidden": true, className: "size-4 shrink-0 text-primary" }),
2177
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "min-w-0 flex-1", children: [
2254
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react3.Bot, { "aria-hidden": true, className: "size-4 shrink-0 text-primary" }),
2255
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "min-w-0 flex-1", children: [
2178
2256
  "An agent filtered this report",
2179
- terms.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
2257
+ terms.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
2180
2258
  " to ",
2181
2259
  terms.join(" \xB7 ")
2182
2260
  ] }) : null,
2183
2261
  " \u2014",
2184
2262
  " ",
2185
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "tabular-nums", children: [
2263
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "tabular-nums", children: [
2186
2264
  applied.matched,
2187
2265
  " of ",
2188
2266
  applied.total,
@@ -2190,7 +2268,7 @@ function ReportAgentFilterNotice({
2190
2268
  ] }),
2191
2269
  "."
2192
2270
  ] }),
2193
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2271
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2194
2272
  "button",
2195
2273
  {
2196
2274
  type: "button",
@@ -2199,14 +2277,14 @@ function ReportAgentFilterNotice({
2199
2277
  children: "Show all"
2200
2278
  }
2201
2279
  ),
2202
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2280
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2203
2281
  "button",
2204
2282
  {
2205
2283
  type: "button",
2206
2284
  onClick: onDismiss,
2207
2285
  "aria-label": "Dismiss",
2208
2286
  className: "cursor-pointer rounded-md p-1 text-muted-foreground hover:text-foreground",
2209
- children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react3.X, { "aria-hidden": true, className: "size-4" })
2287
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react3.X, { "aria-hidden": true, className: "size-4" })
2210
2288
  }
2211
2289
  )
2212
2290
  ]
@@ -2215,16 +2293,16 @@ function ReportAgentFilterNotice({
2215
2293
  }
2216
2294
 
2217
2295
  // src/interactive/ReportFailureBanner.tsx
2218
- var import_react10 = require("react");
2219
- var import_jsx_runtime41 = require("react/jsx-runtime");
2296
+ var import_react12 = require("react");
2297
+ var import_jsx_runtime42 = require("react/jsx-runtime");
2220
2298
  function ReportFailureBanner({ failures, onCopyAll }) {
2221
2299
  const first = failures[0];
2222
- const jumpToFirst = (0, import_react10.useCallback)(() => {
2300
+ const jumpToFirst = (0, import_react12.useCallback)(() => {
2223
2301
  if (!first) return;
2224
2302
  scrollToScenarioId(first.scenarioId);
2225
2303
  }, [first]);
2226
2304
  if (failures.length === 0) return null;
2227
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
2305
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2228
2306
  "div",
2229
2307
  {
2230
2308
  className: "es-failure-banner",
@@ -2232,13 +2310,13 @@ function ReportFailureBanner({ failures, onCopyAll }) {
2232
2310
  "aria-live": "polite",
2233
2311
  "aria-label": "Failure summary",
2234
2312
  children: [
2235
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "es-failure-banner-text", children: [
2236
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: failures.length }),
2313
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "es-failure-banner-text", children: [
2314
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: failures.length }),
2237
2315
  " ",
2238
2316
  "failure",
2239
2317
  failures.length === 1 ? "" : "s"
2240
2318
  ] }),
2241
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2319
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2242
2320
  "button",
2243
2321
  {
2244
2322
  type: "button",
@@ -2248,7 +2326,7 @@ function ReportFailureBanner({ failures, onCopyAll }) {
2248
2326
  children: "View first failure \u2193"
2249
2327
  }
2250
2328
  ),
2251
- onCopyAll ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
2329
+ onCopyAll ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2252
2330
  "button",
2253
2331
  {
2254
2332
  type: "button",
@@ -2270,8 +2348,8 @@ function ReportFailureBanner({ failures, onCopyAll }) {
2270
2348
  }
2271
2349
 
2272
2350
  // src/interactive/ReportFilters.tsx
2273
- var import_react11 = require("react");
2274
- var import_jsx_runtime42 = require("react/jsx-runtime");
2351
+ var import_react13 = require("react");
2352
+ var import_jsx_runtime43 = require("react/jsx-runtime");
2275
2353
  var TAG_LIMIT = 12;
2276
2354
  function ReportFilters({
2277
2355
  statuses,
@@ -2281,14 +2359,14 @@ function ReportFilters({
2281
2359
  activeTags,
2282
2360
  onToggleTag
2283
2361
  }) {
2284
- const [showAllTags, setShowAllTags] = (0, import_react11.useState)(false);
2362
+ const [showAllTags, setShowAllTags] = (0, import_react13.useState)(false);
2285
2363
  if (statuses.length === 0 && tags.length === 0) return null;
2286
2364
  const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
2287
2365
  const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
2288
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-col gap-2", children: [
2289
- statuses.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2366
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-col gap-2", children: [
2367
+ statuses.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2290
2368
  const active = status === opt.key;
2291
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2369
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
2292
2370
  "button",
2293
2371
  {
2294
2372
  type: "button",
@@ -2300,23 +2378,23 @@ function ReportFilters({
2300
2378
  ),
2301
2379
  children: [
2302
2380
  opt.label,
2303
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2381
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2304
2382
  ]
2305
2383
  },
2306
2384
  opt.key
2307
2385
  );
2308
2386
  }) }) : null,
2309
- tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2387
+ tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2310
2388
  visibleTags.map((tag) => {
2311
2389
  const active = activeTags.includes(tag);
2312
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2390
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2313
2391
  "button",
2314
2392
  {
2315
2393
  type: "button",
2316
2394
  "aria-pressed": active,
2317
2395
  onClick: () => onToggleTag(tag),
2318
2396
  className: "cursor-pointer",
2319
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2397
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2320
2398
  Badge,
2321
2399
  {
2322
2400
  variant: "tag",
@@ -2329,7 +2407,7 @@ function ReportFilters({
2329
2407
  }
2330
2408
  ) }, tag);
2331
2409
  }),
2332
- tags.length > TAG_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2410
+ tags.length > TAG_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2333
2411
  "button",
2334
2412
  {
2335
2413
  type: "button",
@@ -2344,16 +2422,16 @@ function ReportFilters({
2344
2422
  }
2345
2423
 
2346
2424
  // src/interactive/ReportFreshness.tsx
2347
- var import_react12 = require("react");
2348
- var import_jsx_runtime43 = require("react/jsx-runtime");
2425
+ var import_react14 = require("react");
2426
+ var import_jsx_runtime44 = require("react/jsx-runtime");
2349
2427
  function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2350
- const [now, setNow] = (0, import_react12.useState)(nowMs);
2351
- (0, import_react12.useEffect)(() => {
2428
+ const [now, setNow] = (0, import_react14.useState)(nowMs);
2429
+ (0, import_react14.useEffect)(() => {
2352
2430
  if (nowMs === void 0) setNow(Date.now());
2353
2431
  }, [nowMs]);
2354
2432
  if (lastRunMs === void 0 || now === void 0) return null;
2355
2433
  const age = formatRelativeAge(lastRunMs, now);
2356
- const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2434
+ const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2357
2435
  "a",
2358
2436
  {
2359
2437
  href: ciUrl,
@@ -2364,9 +2442,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2364
2442
  }
2365
2443
  ) : null;
2366
2444
  if (isReportStale(lastRunMs, staleAfterDays, now)) {
2367
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
2368
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { children: [
2369
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("strong", { children: [
2445
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
2446
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { children: [
2447
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("strong", { children: [
2370
2448
  "Last verified ",
2371
2449
  age,
2372
2450
  "."
@@ -2376,10 +2454,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2376
2454
  runLink
2377
2455
  ] });
2378
2456
  }
2379
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
2457
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
2380
2458
  "Verified ",
2381
2459
  age,
2382
- runLink ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
2460
+ runLink ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
2383
2461
  " \xB7 ",
2384
2462
  runLink
2385
2463
  ] }) : null
@@ -2387,15 +2465,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2387
2465
  }
2388
2466
 
2389
2467
  // src/interactive/ReportLastRunDelta.tsx
2390
- var import_jsx_runtime44 = require("react/jsx-runtime");
2468
+ var import_jsx_runtime45 = require("react/jsx-runtime");
2391
2469
  var MAX_LINKS = 5;
2392
2470
  function ScenarioLinks({ scenarios, tone }) {
2393
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
2394
- scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { children: [
2471
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
2472
+ scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
2395
2473
  i > 0 ? ", " : "",
2396
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2474
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2397
2475
  ] }, s.id)),
2398
- scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { children: [
2476
+ scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
2399
2477
  " and ",
2400
2478
  scenarios.length - MAX_LINKS,
2401
2479
  " more"
@@ -2412,23 +2490,23 @@ function ReportLastRunDelta({
2412
2490
  if (!delta) return null;
2413
2491
  const { newlyFailing, newlyPassing, added } = delta;
2414
2492
  if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
2415
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
2493
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
2416
2494
  }
2417
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
2418
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
2419
- newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "ml-2 text-fail", children: [
2495
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
2496
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
2497
+ newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "ml-2 text-fail", children: [
2420
2498
  newlyFailing.length,
2421
2499
  " newly failing (",
2422
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
2500
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
2423
2501
  ")"
2424
2502
  ] }) : null,
2425
- newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "ml-2 text-pass", children: [
2503
+ newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "ml-2 text-pass", children: [
2426
2504
  newlyPassing.length,
2427
2505
  " fixed (",
2428
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
2506
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
2429
2507
  ")"
2430
2508
  ] }) : null,
2431
- added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "ml-2", children: [
2509
+ added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "ml-2", children: [
2432
2510
  added.length,
2433
2511
  " new"
2434
2512
  ] }) : null
@@ -2436,14 +2514,14 @@ function ReportLastRunDelta({
2436
2514
  }
2437
2515
 
2438
2516
  // src/interactive/ReportSearch.tsx
2439
- var import_react13 = require("react");
2517
+ var import_react15 = require("react");
2440
2518
  var import_lucide_react4 = require("lucide-react");
2441
2519
 
2442
2520
  // src/components/ui/input.tsx
2443
2521
  var React6 = require("react");
2444
- var import_jsx_runtime45 = require("react/jsx-runtime");
2522
+ var import_jsx_runtime46 = require("react/jsx-runtime");
2445
2523
  function Input({ className, type, ...props }) {
2446
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2524
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2447
2525
  "input",
2448
2526
  {
2449
2527
  type,
@@ -2460,8 +2538,8 @@ function Input({ className, type, ...props }) {
2460
2538
  }
2461
2539
 
2462
2540
  // src/interactive/ReportSearch.tsx
2463
- var import_jsx_runtime46 = require("react/jsx-runtime");
2464
- var ReportSearch = (0, import_react13.forwardRef)(
2541
+ var import_jsx_runtime47 = require("react/jsx-runtime");
2542
+ var ReportSearch = (0, import_react15.forwardRef)(
2465
2543
  function ReportSearch2(props, ref) {
2466
2544
  const {
2467
2545
  value,
@@ -2471,7 +2549,7 @@ var ReportSearch = (0, import_react13.forwardRef)(
2471
2549
  placeholder = "Search scenarios, tags, tickets, errors\u2026",
2472
2550
  className
2473
2551
  } = props;
2474
- const inputId = (0, import_react13.useId)();
2552
+ const inputId = (0, import_react15.useId)();
2475
2553
  const showCounts = value.trim().length > 0 && typeof matchedCount === "number" && typeof totalCount === "number";
2476
2554
  function handleChange(e) {
2477
2555
  onChange(e.target.value);
@@ -2482,17 +2560,17 @@ var ReportSearch = (0, import_react13.forwardRef)(
2482
2560
  e.preventDefault();
2483
2561
  }
2484
2562
  }
2485
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: cn("es-search flex flex-col gap-1", className), children: [
2486
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
2487
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "relative w-full sm:w-72", children: [
2488
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2563
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: cn("es-search flex flex-col gap-1", className), children: [
2564
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
2565
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "relative w-full sm:w-72", children: [
2566
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2489
2567
  import_lucide_react4.Search,
2490
2568
  {
2491
2569
  "aria-hidden": true,
2492
2570
  className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
2493
2571
  }
2494
2572
  ),
2495
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2573
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2496
2574
  Input,
2497
2575
  {
2498
2576
  ref,
@@ -2509,7 +2587,7 @@ var ReportSearch = (0, import_react13.forwardRef)(
2509
2587
  }
2510
2588
  )
2511
2589
  ] }),
2512
- showCounts ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
2590
+ showCounts ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
2513
2591
  "span",
2514
2592
  {
2515
2593
  className: "text-xs tabular-nums text-muted-foreground",
@@ -2528,7 +2606,7 @@ var ReportSearch = (0, import_react13.forwardRef)(
2528
2606
 
2529
2607
  // src/interactive/ReportShare.tsx
2530
2608
  var import_lucide_react5 = require("lucide-react");
2531
- var import_react14 = require("react");
2609
+ var import_react16 = require("react");
2532
2610
 
2533
2611
  // src/components/ui/button.tsx
2534
2612
  var React7 = require("react");
@@ -2584,22 +2662,22 @@ function Button({
2584
2662
  }
2585
2663
 
2586
2664
  // src/interactive/ReportShare.tsx
2587
- var import_jsx_runtime47 = require("react/jsx-runtime");
2665
+ var import_jsx_runtime48 = require("react/jsx-runtime");
2588
2666
  var DEFAULT_SHARE_COMMAND = "npx executable-stories share reports/";
2589
2667
  function ReportShare({
2590
2668
  command = DEFAULT_SHARE_COMMAND,
2591
2669
  onCopy
2592
2670
  }) {
2593
- const [open, setOpen] = (0, import_react14.useState)(false);
2594
- const dialogRef = (0, import_react14.useRef)(null);
2595
- (0, import_react14.useEffect)(() => {
2671
+ const [open, setOpen] = (0, import_react16.useState)(false);
2672
+ const dialogRef = (0, import_react16.useRef)(null);
2673
+ (0, import_react16.useEffect)(() => {
2596
2674
  const dialog = dialogRef.current;
2597
2675
  if (!dialog) return;
2598
2676
  if (open && !dialog.open) dialog.showModal();
2599
2677
  else if (!open && dialog.open) dialog.close();
2600
2678
  }, [open]);
2601
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
2602
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
2679
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
2680
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
2603
2681
  Button,
2604
2682
  {
2605
2683
  type: "button",
@@ -2609,12 +2687,12 @@ function ReportShare({
2609
2687
  title: "Share this report",
2610
2688
  onClick: () => setOpen(true),
2611
2689
  children: [
2612
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react5.Share2, { "aria-hidden": "true", className: "size-4" }),
2613
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "sr-only sm:not-sr-only", children: "Share" })
2690
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react5.Share2, { "aria-hidden": "true", className: "size-4" }),
2691
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "sr-only sm:not-sr-only", children: "Share" })
2614
2692
  ]
2615
2693
  }
2616
2694
  ),
2617
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
2695
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
2618
2696
  "dialog",
2619
2697
  {
2620
2698
  ref: dialogRef,
@@ -2622,11 +2700,11 @@ function ReportShare({
2622
2700
  "aria-label": "Share this report",
2623
2701
  onClose: () => setOpen(false),
2624
2702
  children: [
2625
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("h2", { className: "text-base font-semibold", children: "Share this report" }),
2626
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "mt-2 text-sm text-muted-foreground", children: "Publish it to Executable Stories Cloud and send a link. Screenshots and videos go with it. Run this from your project:" }),
2627
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "mt-4 flex items-center gap-2", children: [
2628
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("code", { className: "min-w-0 flex-1 truncate rounded border border-border bg-muted px-3 py-2 font-mono text-xs", children: command }),
2629
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2703
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h2", { className: "text-base font-semibold", children: "Share this report" }),
2704
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "mt-2 text-sm text-muted-foreground", children: "Publish it to Executable Stories Cloud and send a link. Screenshots and videos go with it. Run this from your project:" }),
2705
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "mt-4 flex items-center gap-2", children: [
2706
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("code", { className: "min-w-0 flex-1 truncate rounded border border-border bg-muted px-3 py-2 font-mono text-xs", children: command }),
2707
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2630
2708
  Button,
2631
2709
  {
2632
2710
  type: "button",
@@ -2636,9 +2714,9 @@ function ReportShare({
2636
2714
  }
2637
2715
  )
2638
2716
  ] }),
2639
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "mt-3 text-xs text-muted-foreground", children: "The file you are reading cannot upload itself, so the command does it: only the CLI can read the assets this report links to." }),
2640
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "mt-6 flex items-center justify-between gap-4", children: [
2641
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2717
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "mt-3 text-xs text-muted-foreground", children: "The file you are reading cannot upload itself, so the command does it: only the CLI can read the assets this report links to." }),
2718
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "mt-6 flex items-center justify-between gap-4", children: [
2719
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2642
2720
  "a",
2643
2721
  {
2644
2722
  className: "text-xs underline underline-offset-2",
@@ -2648,7 +2726,7 @@ function ReportShare({
2648
2726
  children: "How sharing works"
2649
2727
  }
2650
2728
  ),
2651
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), children: "Close" })
2729
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), children: "Close" })
2652
2730
  ] })
2653
2731
  ]
2654
2732
  }
@@ -2657,7 +2735,7 @@ function ReportShare({
2657
2735
  }
2658
2736
 
2659
2737
  // src/interactive/ReportSinceLastVisit.tsx
2660
- var import_react15 = require("react");
2738
+ var import_react17 = require("react");
2661
2739
 
2662
2740
  // src/interactive/last-visit.ts
2663
2741
  function snapshotOf(report, atMs) {
@@ -2693,7 +2771,7 @@ function diffSinceVisit(previous, report) {
2693
2771
  }
2694
2772
 
2695
2773
  // src/interactive/ReportSinceLastVisit.tsx
2696
- var import_jsx_runtime48 = require("react/jsx-runtime");
2774
+ var import_jsx_runtime49 = require("react/jsx-runtime");
2697
2775
  var KEY = "es-last-visit";
2698
2776
  var MAX_LINKS2 = 5;
2699
2777
  function readVisit() {
@@ -2718,12 +2796,12 @@ function writeVisit(snapshot) {
2718
2796
  }
2719
2797
  }
2720
2798
  function ScenarioLinks2({ scenarios, tone }) {
2721
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
2722
- scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { children: [
2799
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
2800
+ scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { children: [
2723
2801
  i > 0 ? ", " : "",
2724
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2802
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2725
2803
  ] }, s.id)),
2726
- scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { children: [
2804
+ scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { children: [
2727
2805
  " and ",
2728
2806
  scenarios.length - MAX_LINKS2,
2729
2807
  " more"
@@ -2731,9 +2809,9 @@ function ScenarioLinks2({ scenarios, tone }) {
2731
2809
  ] });
2732
2810
  }
2733
2811
  function ReportSinceLastVisit({ report }) {
2734
- const [delta, setDelta] = (0, import_react15.useState)(null);
2735
- const [nowMs, setNowMs] = (0, import_react15.useState)(0);
2736
- (0, import_react15.useEffect)(() => {
2812
+ const [delta, setDelta] = (0, import_react17.useState)(null);
2813
+ const [nowMs, setNowMs] = (0, import_react17.useState)(0);
2814
+ (0, import_react17.useEffect)(() => {
2737
2815
  const now = Date.now();
2738
2816
  setDelta(diffSinceVisit(readVisit(), report));
2739
2817
  setNowMs(now);
@@ -2741,25 +2819,25 @@ function ReportSinceLastVisit({ report }) {
2741
2819
  }, [report]);
2742
2820
  if (!delta) return null;
2743
2821
  const { newlyFailing, newlyPassing, added } = delta;
2744
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
2745
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "font-medium text-foreground", children: [
2822
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
2823
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "font-medium text-foreground", children: [
2746
2824
  "Since your last visit (",
2747
2825
  formatRelativeAge(delta.sinceMs, nowMs),
2748
2826
  "):"
2749
2827
  ] }),
2750
- newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ml-2 text-fail", children: [
2828
+ newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "ml-2 text-fail", children: [
2751
2829
  newlyFailing.length,
2752
2830
  " started failing (",
2753
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2754
2832
  ")"
2755
2833
  ] }) : null,
2756
- newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ml-2 text-pass", children: [
2834
+ newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "ml-2 text-pass", children: [
2757
2835
  newlyPassing.length,
2758
2836
  " fixed (",
2759
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2837
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2760
2838
  ")"
2761
2839
  ] }) : null,
2762
- added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ml-2", children: [
2840
+ added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "ml-2", children: [
2763
2841
  added.length,
2764
2842
  " new"
2765
2843
  ] }) : null
@@ -2767,8 +2845,8 @@ function ReportSinceLastVisit({ report }) {
2767
2845
  }
2768
2846
 
2769
2847
  // src/interactive/ReportShortcutsHelp.tsx
2770
- var import_react16 = require("react");
2771
- var import_jsx_runtime49 = require("react/jsx-runtime");
2848
+ var import_react18 = require("react");
2849
+ var import_jsx_runtime50 = require("react/jsx-runtime");
2772
2850
  var SHORTCUTS = [
2773
2851
  { keys: "/", description: "Focus search" },
2774
2852
  { keys: "f", description: "Jump to next failure" },
@@ -2780,20 +2858,20 @@ var SHORTCUTS = [
2780
2858
  ];
2781
2859
  function Keys({ keys }) {
2782
2860
  const parts = keys.split(" ");
2783
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
2784
- i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2785
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2861
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
2862
+ i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2863
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2786
2864
  ] }, k)) });
2787
2865
  }
2788
2866
  function ReportShortcutsHelp({ open, onClose }) {
2789
- const dialogRef = (0, import_react16.useRef)(null);
2790
- (0, import_react16.useEffect)(() => {
2867
+ const dialogRef = (0, import_react18.useRef)(null);
2868
+ (0, import_react18.useEffect)(() => {
2791
2869
  const dialog = dialogRef.current;
2792
2870
  if (!dialog) return;
2793
2871
  if (open && !dialog.open) dialog.showModal();
2794
2872
  else if (!open && dialog.open) dialog.close();
2795
2873
  }, [open]);
2796
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
2874
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
2797
2875
  "dialog",
2798
2876
  {
2799
2877
  ref: dialogRef,
@@ -2801,20 +2879,20 @@ function ReportShortcutsHelp({ open, onClose }) {
2801
2879
  "aria-label": "Keyboard shortcuts",
2802
2880
  onClose,
2803
2881
  children: [
2804
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2805
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2806
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Keys, { keys: s.keys }) }),
2807
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
2882
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2883
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2884
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Keys, { keys: s.keys }) }),
2885
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
2808
2886
  ] }, s.keys)) }),
2809
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2887
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2810
2888
  ]
2811
2889
  }
2812
2890
  );
2813
2891
  }
2814
2892
 
2815
2893
  // src/interactive/ReportToc.tsx
2816
- var import_react17 = require("react");
2817
- var import_jsx_runtime50 = require("react/jsx-runtime");
2894
+ var import_react19 = require("react");
2895
+ var import_jsx_runtime51 = require("react/jsx-runtime");
2818
2896
  var DOT = {
2819
2897
  passed: "bg-pass",
2820
2898
  failed: "bg-fail",
@@ -2823,12 +2901,12 @@ var DOT = {
2823
2901
  };
2824
2902
  function TocContent({ onNavigate }) {
2825
2903
  const report = useReport();
2826
- const [activeId, setActiveId] = (0, import_react17.useState)(null);
2827
- const scenarioIds = (0, import_react17.useMemo)(
2904
+ const [activeId, setActiveId] = (0, import_react19.useState)(null);
2905
+ const scenarioIds = (0, import_react19.useMemo)(
2828
2906
  () => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
2829
2907
  [report]
2830
2908
  );
2831
- (0, import_react17.useEffect)(() => {
2909
+ (0, import_react19.useEffect)(() => {
2832
2910
  if (typeof IntersectionObserver === "undefined") return;
2833
2911
  const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
2834
2912
  if (els.length === 0) return;
@@ -2843,11 +2921,11 @@ function TocContent({ onNavigate }) {
2843
2921
  return () => observer.disconnect();
2844
2922
  }, [scenarioIds]);
2845
2923
  if (report.features.length === 0) return null;
2846
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("li", { children: [
2847
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2848
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2924
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("li", { children: [
2925
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2926
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2849
2927
  const active = activeId === scenario.id;
2850
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
2928
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
2851
2929
  "a",
2852
2930
  {
2853
2931
  href: `#${scenario.id}`,
@@ -2862,14 +2940,14 @@ function TocContent({ onNavigate }) {
2862
2940
  active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
2863
2941
  ),
2864
2942
  children: [
2865
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
2943
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
2866
2944
  "span",
2867
2945
  {
2868
2946
  "aria-hidden": true,
2869
2947
  className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
2870
2948
  }
2871
2949
  ),
2872
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "break-words", children: scenario.title })
2950
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "break-words", children: scenario.title })
2873
2951
  ]
2874
2952
  }
2875
2953
  ) }, scenario.id);
@@ -2879,48 +2957,48 @@ function TocContent({ onNavigate }) {
2879
2957
  function ReportToc() {
2880
2958
  const report = useReport();
2881
2959
  if (report.features.length === 0) return null;
2882
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
2960
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
2883
2961
  "nav",
2884
2962
  {
2885
2963
  "aria-label": "Table of contents",
2886
2964
  className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
2887
2965
  children: [
2888
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2889
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(TocContent, {})
2966
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2967
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(TocContent, {})
2890
2968
  ]
2891
2969
  }
2892
2970
  );
2893
2971
  }
2894
2972
 
2895
2973
  // src/interactive/ReportTocDrawer.tsx
2896
- var import_react18 = require("react");
2974
+ var import_react20 = require("react");
2897
2975
  var import_dialog = require("@base-ui/react/dialog");
2898
2976
  var import_lucide_react6 = require("lucide-react");
2899
- var import_jsx_runtime51 = require("react/jsx-runtime");
2977
+ var import_jsx_runtime52 = require("react/jsx-runtime");
2900
2978
  function ReportTocDrawer() {
2901
2979
  const report = useReport();
2902
- const [open, setOpen] = (0, import_react18.useState)(false);
2980
+ const [open, setOpen] = (0, import_react20.useState)(false);
2903
2981
  if (report.features.length === 0) return null;
2904
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
2905
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_dialog.Dialog.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2906
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react6.ListIcon, { "aria-hidden": true }),
2982
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
2983
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_dialog.Dialog.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2984
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react6.ListIcon, { "aria-hidden": true }),
2907
2985
  " Contents"
2908
2986
  ] }),
2909
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_dialog.Dialog.Portal, { children: [
2910
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_dialog.Dialog.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2911
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_dialog.Dialog.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2912
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center justify-between", children: [
2913
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2914
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
2987
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_dialog.Dialog.Portal, { children: [
2988
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_dialog.Dialog.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2989
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_dialog.Dialog.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2990
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center justify-between", children: [
2991
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2992
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
2915
2993
  import_dialog.Dialog.Close,
2916
2994
  {
2917
2995
  "aria-label": "Close contents",
2918
2996
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
2919
- children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react6.XIcon, { "aria-hidden": true })
2997
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react6.XIcon, { "aria-hidden": true })
2920
2998
  }
2921
2999
  )
2922
3000
  ] }),
2923
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(TocContent, { onNavigate: () => setOpen(false) })
3001
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(TocContent, { onNavigate: () => setOpen(false) })
2924
3002
  ] })
2925
3003
  ] })
2926
3004
  ] });
@@ -2954,10 +3032,10 @@ function failuresFirst(report) {
2954
3032
  }
2955
3033
 
2956
3034
  // src/interactive/use-deep-link-scroll.ts
2957
- var import_react19 = require("react");
3035
+ var import_react21 = require("react");
2958
3036
  function useDeepLinkScroll() {
2959
- const lastAnchor = (0, import_react19.useRef)(null);
2960
- (0, import_react19.useEffect)(() => {
3037
+ const lastAnchor = (0, import_react21.useRef)(null);
3038
+ (0, import_react21.useEffect)(() => {
2961
3039
  function scrollToHash() {
2962
3040
  const { anchor } = splitHash(window.location.hash);
2963
3041
  if (!anchor || anchor === lastAnchor.current) return;
@@ -2973,7 +3051,7 @@ function useDeepLinkScroll() {
2973
3051
  }
2974
3052
 
2975
3053
  // src/interactive/use-keyboard-shortcuts.ts
2976
- var import_react20 = require("react");
3054
+ var import_react22 = require("react");
2977
3055
  function isEditableTarget(target) {
2978
3056
  if (!(target instanceof HTMLElement)) return false;
2979
3057
  const tag = target.tagName;
@@ -2982,9 +3060,9 @@ function isEditableTarget(target) {
2982
3060
  return false;
2983
3061
  }
2984
3062
  function useKeyboardShortcuts(handlers) {
2985
- const ref = (0, import_react20.useRef)(handlers);
3063
+ const ref = (0, import_react22.useRef)(handlers);
2986
3064
  ref.current = handlers;
2987
- (0, import_react20.useEffect)(() => {
3065
+ (0, import_react22.useEffect)(() => {
2988
3066
  function onKeyDown(e) {
2989
3067
  const h = ref.current;
2990
3068
  if (e.key === "Escape") {
@@ -3028,7 +3106,7 @@ function useKeyboardShortcuts(handlers) {
3028
3106
  }
3029
3107
 
3030
3108
  // src/interactive/use-theme.ts
3031
- var import_react21 = require("react");
3109
+ var import_react23 = require("react");
3032
3110
  var KEY2 = "es-theme";
3033
3111
  function systemDark() {
3034
3112
  return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
@@ -3049,13 +3127,13 @@ function initialPref() {
3049
3127
  return "system";
3050
3128
  }
3051
3129
  function useTheme() {
3052
- const [pref, setPrefState] = (0, import_react21.useState)("system");
3053
- (0, import_react21.useEffect)(() => {
3130
+ const [pref, setPrefState] = (0, import_react23.useState)("system");
3131
+ (0, import_react23.useEffect)(() => {
3054
3132
  const p = initialPref();
3055
3133
  setPrefState(p);
3056
3134
  applyTheme(p);
3057
3135
  }, []);
3058
- (0, import_react21.useEffect)(() => {
3136
+ (0, import_react23.useEffect)(() => {
3059
3137
  if (typeof matchMedia === "undefined") return;
3060
3138
  const mq = matchMedia("(prefers-color-scheme: dark)");
3061
3139
  const onChange = () => {
@@ -3064,7 +3142,7 @@ function useTheme() {
3064
3142
  mq.addEventListener("change", onChange);
3065
3143
  return () => mq.removeEventListener("change", onChange);
3066
3144
  }, [pref]);
3067
- const setPref = (0, import_react21.useCallback)((p) => {
3145
+ const setPref = (0, import_react23.useCallback)((p) => {
3068
3146
  setPrefState(p);
3069
3147
  applyTheme(p);
3070
3148
  try {
@@ -3076,19 +3154,19 @@ function useTheme() {
3076
3154
  }
3077
3155
 
3078
3156
  // src/interactive/use-url-state.ts
3079
- var import_react22 = require("react");
3157
+ var import_react24 = require("react");
3080
3158
  var WRITE_DELAY_MS = 250;
3081
3159
  function useUrlState() {
3082
- const [state, setState] = (0, import_react22.useState)(DEFAULT_URL_STATE);
3083
- const ready = (0, import_react22.useRef)(false);
3084
- (0, import_react22.useEffect)(() => {
3160
+ const [state, setState] = (0, import_react24.useState)(DEFAULT_URL_STATE);
3161
+ const ready = (0, import_react24.useRef)(false);
3162
+ (0, import_react24.useEffect)(() => {
3085
3163
  const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
3086
3164
  read();
3087
3165
  ready.current = true;
3088
3166
  window.addEventListener("hashchange", read);
3089
3167
  return () => window.removeEventListener("hashchange", read);
3090
3168
  }, []);
3091
- (0, import_react22.useEffect)(() => {
3169
+ (0, import_react24.useEffect)(() => {
3092
3170
  if (!ready.current) return;
3093
3171
  const timer = setTimeout(
3094
3172
  () => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
@@ -3096,7 +3174,7 @@ function useUrlState() {
3096
3174
  );
3097
3175
  return () => clearTimeout(timer);
3098
3176
  }, [state]);
3099
- const update = (0, import_react22.useCallback)(
3177
+ const update = (0, import_react24.useCallback)(
3100
3178
  (patch) => setState((prev) => ({ ...prev, ...patch })),
3101
3179
  []
3102
3180
  );
@@ -3318,12 +3396,12 @@ function reportTools(deps) {
3318
3396
  }
3319
3397
 
3320
3398
  // src/interactive/ReportInteractive.tsx
3321
- var import_jsx_runtime52 = require("react/jsx-runtime");
3399
+ var import_jsx_runtime53 = require("react/jsx-runtime");
3322
3400
  function ReportInteractive(props) {
3323
3401
  const { report, className, title, dataTheme } = props;
3324
3402
  const result = unwrapReport(report);
3325
3403
  if (!result.ok) {
3326
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3404
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3327
3405
  ReportErrorShell,
3328
3406
  {
3329
3407
  error: result.error,
@@ -3333,7 +3411,7 @@ function ReportInteractive(props) {
3333
3411
  }
3334
3412
  );
3335
3413
  }
3336
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportInteractiveView, { ...props, report: result.data });
3414
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportInteractiveView, { ...props, report: result.data });
3337
3415
  }
3338
3416
  var THEME_OPTIONS = [
3339
3417
  { value: "light", label: "Light", Icon: import_lucide_react7.Sun },
@@ -3344,7 +3422,7 @@ function ThemeSegment({
3344
3422
  pref,
3345
3423
  onPref
3346
3424
  }) {
3347
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3425
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3348
3426
  ToggleGroup,
3349
3427
  {
3350
3428
  size: "sm",
@@ -3354,14 +3432,14 @@ function ThemeSegment({
3354
3432
  if (next) onPref(next);
3355
3433
  },
3356
3434
  "aria-label": "Color theme",
3357
- children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3435
+ children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3358
3436
  ToggleGroupItem,
3359
3437
  {
3360
3438
  value,
3361
3439
  "aria-label": label,
3362
3440
  title: label,
3363
3441
  className: "px-2",
3364
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(Icon, {})
3442
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Icon, {})
3365
3443
  },
3366
3444
  value
3367
3445
  ))
@@ -3384,26 +3462,26 @@ function ReportInteractiveView({
3384
3462
  }) {
3385
3463
  const [urlState, setUrlState] = useUrlState();
3386
3464
  const { query, status: statusFilter, tags: activeTags, detail } = urlState;
3387
- const setQuery = (0, import_react24.useCallback)(
3465
+ const setQuery = (0, import_react26.useCallback)(
3388
3466
  (next) => setUrlState({ query: next }),
3389
3467
  [setUrlState]
3390
3468
  );
3391
- const setStatusFilter = (0, import_react24.useCallback)(
3469
+ const setStatusFilter = (0, import_react26.useCallback)(
3392
3470
  (next) => setUrlState({ status: next }),
3393
3471
  [setUrlState]
3394
3472
  );
3395
- const setDetail = (0, import_react24.useCallback)(
3473
+ const setDetail = (0, import_react26.useCallback)(
3396
3474
  (next) => setUrlState({ detail: next }),
3397
3475
  [setUrlState]
3398
3476
  );
3399
- const [helpOpen, setHelpOpen] = (0, import_react24.useState)(false);
3477
+ const [helpOpen, setHelpOpen] = (0, import_react26.useState)(false);
3400
3478
  const { pref: themePref, setPref: setThemePref } = useTheme();
3401
- const searchRef = (0, import_react24.useRef)(null);
3402
- const expandId = (0, import_react24.useId)();
3403
- const docsId = (0, import_react24.useId)();
3404
- const deferredQuery = (0, import_react24.useDeferredValue)(query);
3405
- const failures = (0, import_react24.useMemo)(() => listFailures(report), [report]);
3406
- const filtered = (0, import_react24.useMemo)(
3479
+ const searchRef = (0, import_react26.useRef)(null);
3480
+ const expandId = (0, import_react26.useId)();
3481
+ const docsId = (0, import_react26.useId)();
3482
+ const deferredQuery = (0, import_react26.useDeferredValue)(query);
3483
+ const failures = (0, import_react26.useMemo)(() => listFailures(report), [report]);
3484
+ const filtered = (0, import_react26.useMemo)(
3407
3485
  // Features carrying failures float to the top so the first thing on screen
3408
3486
  // is the thing that needs attention; an all-green run keeps source order.
3409
3487
  () => failuresFirst(
@@ -3416,7 +3494,7 @@ function ReportInteractiveView({
3416
3494
  [report, deferredQuery, statusFilter, activeTags]
3417
3495
  );
3418
3496
  const isFiltering = query !== deferredQuery;
3419
- const statusOptions = (0, import_react24.useMemo)(() => {
3497
+ const statusOptions = (0, import_react26.useMemo)(() => {
3420
3498
  const s = report.summary;
3421
3499
  const opts = [
3422
3500
  { key: "all", label: "All", count: s.total }
@@ -3431,21 +3509,21 @@ function ReportInteractiveView({
3431
3509
  opts.push({ key: "pending", label: "Pending", count: s.pending });
3432
3510
  return opts;
3433
3511
  }, [report]);
3434
- const tagOptions = (0, import_react24.useMemo)(() => allTags(report), [report]);
3435
- const toggleTag = (0, import_react24.useCallback)(
3512
+ const tagOptions = (0, import_react26.useMemo)(() => allTags(report), [report]);
3513
+ const toggleTag = (0, import_react26.useCallback)(
3436
3514
  (tag) => setUrlState({
3437
3515
  tags: activeTags.includes(tag) ? activeTags.filter((t) => t !== tag) : [...activeTags, tag]
3438
3516
  }),
3439
3517
  [activeTags, setUrlState]
3440
3518
  );
3441
- const [toast, setToast] = (0, import_react24.useState)(null);
3442
- const toastTimer = (0, import_react24.useRef)(null);
3443
- const showToast = (0, import_react24.useCallback)((msg) => {
3519
+ const [toast, setToast] = (0, import_react26.useState)(null);
3520
+ const toastTimer = (0, import_react26.useRef)(null);
3521
+ const showToast = (0, import_react26.useCallback)((msg) => {
3444
3522
  setToast(msg);
3445
3523
  if (toastTimer.current) clearTimeout(toastTimer.current);
3446
3524
  toastTimer.current = setTimeout(() => setToast(null), 1800);
3447
3525
  }, []);
3448
- const copy = (0, import_react24.useCallback)(
3526
+ const copy = (0, import_react26.useCallback)(
3449
3527
  (text, msg) => {
3450
3528
  if (typeof navigator !== "undefined" && navigator.clipboard) {
3451
3529
  navigator.clipboard.writeText(text).then(
@@ -3456,7 +3534,7 @@ function ReportInteractiveView({
3456
3534
  },
3457
3535
  [showToast]
3458
3536
  );
3459
- const scenarioActions = (0, import_react24.useMemo)(
3537
+ const scenarioActions = (0, import_react26.useMemo)(
3460
3538
  () => ({
3461
3539
  copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
3462
3540
  copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
@@ -3464,31 +3542,31 @@ function ReportInteractiveView({
3464
3542
  }),
3465
3543
  [copy]
3466
3544
  );
3467
- const copyAllFailures = (0, import_react24.useCallback)(
3545
+ const copyAllFailures = (0, import_react26.useCallback)(
3468
3546
  () => copy(failuresToPrompt(failedScenarios(filtered)), "Failures copied"),
3469
3547
  [copy, filtered]
3470
3548
  );
3471
- const failureIndexRef = (0, import_react24.useRef)(0);
3472
- const allCollapsibleIds = (0, import_react24.useMemo)(
3549
+ const failureIndexRef = (0, import_react26.useRef)(0);
3550
+ const allCollapsibleIds = (0, import_react26.useMemo)(
3473
3551
  () => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
3474
3552
  [report]
3475
3553
  );
3476
3554
  const collapse = useCollapseState(
3477
- (0, import_react24.useCallback)(() => defaultCollapsedIds(report), [report])
3555
+ (0, import_react26.useCallback)(() => defaultCollapsedIds(report), [report])
3478
3556
  );
3479
3557
  const revealFilteredResults = deferredQuery.trim() !== "" || statusFilter !== "all" || activeTags.length > 0;
3480
- const visibleCollapse = (0, import_react24.useMemo)(
3558
+ const visibleCollapse = (0, import_react26.useMemo)(
3481
3559
  () => revealFilteredResults ? { ...collapse.api, isCollapsed: () => false } : collapse.api,
3482
3560
  [collapse.api, revealFilteredResults]
3483
3561
  );
3484
- const collapseAll = (0, import_react24.useCallback)(
3562
+ const collapseAll = (0, import_react26.useCallback)(
3485
3563
  () => collapse.collapseAll(allCollapsibleIds),
3486
3564
  [collapse, allCollapsibleIds]
3487
3565
  );
3488
- const [expandedAll, setExpandedAll] = (0, import_react24.useState)(
3566
+ const [expandedAll, setExpandedAll] = (0, import_react26.useState)(
3489
3567
  () => report.summary.failed === 0
3490
3568
  );
3491
- const setExpanded = (0, import_react24.useCallback)(
3569
+ const setExpanded = (0, import_react26.useCallback)(
3492
3570
  (expanded) => {
3493
3571
  if (expanded) collapse.expandAll();
3494
3572
  else collapseAll();
@@ -3496,8 +3574,8 @@ function ReportInteractiveView({
3496
3574
  },
3497
3575
  [collapse, collapseAll]
3498
3576
  );
3499
- const [agentFilter, setAgentFilter] = (0, import_react24.useState)(null);
3500
- (0, import_react23.useTools)(
3577
+ const [agentFilter, setAgentFilter] = (0, import_react26.useState)(null);
3578
+ (0, import_react25.useTools)(
3501
3579
  reportTools({
3502
3580
  report,
3503
3581
  view: urlState,
@@ -3506,14 +3584,14 @@ function ReportInteractiveView({
3506
3584
  })
3507
3585
  );
3508
3586
  const showAgentFilter = agentFilter !== null && agentFilter.search === query && agentFilter.status === statusFilter && agentFilter.tags.length === activeTags.length && agentFilter.tags.every((tag) => activeTags.includes(tag));
3509
- const clearFilters = (0, import_react24.useCallback)(
3587
+ const clearFilters = (0, import_react26.useCallback)(
3510
3588
  () => setUrlState({ query: "", status: "all", tags: [] }),
3511
3589
  [setUrlState]
3512
3590
  );
3513
- const focusSearch = (0, import_react24.useCallback)(() => {
3591
+ const focusSearch = (0, import_react26.useCallback)(() => {
3514
3592
  searchRef.current?.focus();
3515
3593
  }, []);
3516
- const stepFailure = (0, import_react24.useCallback)(
3594
+ const stepFailure = (0, import_react26.useCallback)(
3517
3595
  (direction) => {
3518
3596
  if (failures.length === 0) return;
3519
3597
  failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
@@ -3522,10 +3600,10 @@ function ReportInteractiveView({
3522
3600
  },
3523
3601
  [failures]
3524
3602
  );
3525
- const toggleHelp = (0, import_react24.useCallback)(() => {
3603
+ const toggleHelp = (0, import_react26.useCallback)(() => {
3526
3604
  setHelpOpen((v) => !v);
3527
3605
  }, []);
3528
- const escape = (0, import_react24.useCallback)(() => {
3606
+ const escape = (0, import_react26.useCallback)(() => {
3529
3607
  if (helpOpen) setHelpOpen(false);
3530
3608
  else if (query !== "") setQuery("");
3531
3609
  }, [helpOpen, query, setQuery]);
@@ -3543,13 +3621,13 @@ function ReportInteractiveView({
3543
3621
  const totalScenarios = report.summary.total;
3544
3622
  const matchedScenarios = filtered.summary.total;
3545
3623
  const showToc = !hideToc && totalScenarios > 3;
3546
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3624
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3547
3625
  ReportRoot,
3548
3626
  {
3549
3627
  report: filtered,
3550
3628
  customRenderers,
3551
3629
  renderers,
3552
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
3630
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
3553
3631
  "main",
3554
3632
  {
3555
3633
  className: cn("es-report", "es-report-interactive", className),
@@ -3558,8 +3636,8 @@ function ReportInteractiveView({
3558
3636
  "data-theme": dataTheme,
3559
3637
  "data-detail-level": detail,
3560
3638
  children: [
3561
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("header", { className: "es-report-header", children: [
3562
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
3639
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("header", { className: "es-report-header", children: [
3640
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
3563
3641
  "div",
3564
3642
  {
3565
3643
  "data-es-navbar": true,
@@ -3568,9 +3646,9 @@ function ReportInteractiveView({
3568
3646
  hideHeader ? "justify-end" : "justify-between"
3569
3647
  ),
3570
3648
  children: [
3571
- hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3572
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center gap-2", children: [
3573
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3649
+ hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3650
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center gap-2", children: [
3651
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3574
3652
  ReportSearch,
3575
3653
  {
3576
3654
  ref: searchRef,
@@ -3580,17 +3658,18 @@ function ReportInteractiveView({
3580
3658
  totalCount: totalScenarios
3581
3659
  }
3582
3660
  ),
3583
- share ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportShare, { command: shareCommand, onCopy: copy }) : null,
3584
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
3661
+ share ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportShare, { command: shareCommand, onCopy: copy }) : null,
3662
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
3585
3663
  ] })
3586
3664
  ]
3587
3665
  }
3588
3666
  ),
3589
- hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
3590
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportSummary, {}),
3591
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportMeta, {})
3667
+ hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
3668
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportSummary, {}),
3669
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportMeta, {})
3592
3670
  ] }),
3593
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3671
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportSpanGraph, {}),
3672
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3594
3673
  ReportFreshness,
3595
3674
  {
3596
3675
  lastRunMs: reportLastRunMs(report),
@@ -3598,15 +3677,15 @@ function ReportInteractiveView({
3598
3677
  staleAfterDays
3599
3678
  }
3600
3679
  ),
3601
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3680
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3602
3681
  ReportLastRunDelta,
3603
3682
  {
3604
3683
  history: scenarioHistory,
3605
3684
  report
3606
3685
  }
3607
3686
  ),
3608
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportSinceLastVisit, { report }),
3609
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3687
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportSinceLastVisit, { report }),
3688
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3610
3689
  ReportFilters,
3611
3690
  {
3612
3691
  statuses: statusOptions,
@@ -3617,10 +3696,10 @@ function ReportInteractiveView({
3617
3696
  onToggleTag: toggleTag
3618
3697
  }
3619
3698
  ),
3620
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3621
- showToc ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportTocDrawer, {}) : null,
3622
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center gap-2", children: [
3623
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3699
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3700
+ showToc ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportTocDrawer, {}) : null,
3701
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center gap-2", children: [
3702
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3624
3703
  Switch,
3625
3704
  {
3626
3705
  id: expandId,
@@ -3628,7 +3707,7 @@ function ReportInteractiveView({
3628
3707
  onCheckedChange: setExpanded
3629
3708
  }
3630
3709
  ),
3631
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3710
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3632
3711
  "label",
3633
3712
  {
3634
3713
  htmlFor: expandId,
@@ -3637,8 +3716,8 @@ function ReportInteractiveView({
3637
3716
  }
3638
3717
  )
3639
3718
  ] }),
3640
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center gap-2", children: [
3641
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3719
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center gap-2", children: [
3720
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3642
3721
  Switch,
3643
3722
  {
3644
3723
  id: docsId,
@@ -3646,7 +3725,7 @@ function ReportInteractiveView({
3646
3725
  onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
3647
3726
  }
3648
3727
  ),
3649
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3728
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3650
3729
  "label",
3651
3730
  {
3652
3731
  htmlFor: docsId,
@@ -3657,7 +3736,7 @@ function ReportInteractiveView({
3657
3736
  ] })
3658
3737
  ] })
3659
3738
  ] }),
3660
- showAgentFilter ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3739
+ showAgentFilter ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3661
3740
  ReportAgentFilterNotice,
3662
3741
  {
3663
3742
  applied: agentFilter,
@@ -3665,17 +3744,17 @@ function ReportInteractiveView({
3665
3744
  onDismiss: () => setAgentFilter(null)
3666
3745
  }
3667
3746
  ) : null,
3668
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
3669
- hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex gap-6", children: [
3670
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportToc, {}),
3671
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportFeatureList, {}) })
3672
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3747
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
3748
+ hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex gap-6", children: [
3749
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportToc, {}),
3750
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportFeatureList, {}) })
3751
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3673
3752
  ReportEmpty,
3674
3753
  {
3675
3754
  message: query ? "No scenarios match the search." : void 0
3676
3755
  }
3677
3756
  ),
3678
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3757
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3679
3758
  "button",
3680
3759
  {
3681
3760
  type: "button",
@@ -3686,14 +3765,14 @@ function ReportInteractiveView({
3686
3765
  children: "?"
3687
3766
  }
3688
3767
  ),
3689
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3768
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3690
3769
  ReportShortcutsHelp,
3691
3770
  {
3692
3771
  open: helpOpen,
3693
3772
  onClose: () => setHelpOpen(false)
3694
3773
  }
3695
3774
  ),
3696
- toast ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3775
+ toast ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3697
3776
  "div",
3698
3777
  {
3699
3778
  role: "status",
@@ -3710,14 +3789,14 @@ function ReportInteractiveView({
3710
3789
  }
3711
3790
 
3712
3791
  // src/interactive/ReportInteractiveIsland.tsx
3713
- var import_react27 = require("react");
3792
+ var import_react29 = require("react");
3714
3793
 
3715
3794
  // src/interactive/island-renderers.tsx
3716
- var import_react26 = require("react");
3795
+ var import_react28 = require("react");
3717
3796
 
3718
3797
  // src/components/doc/MermaidView.tsx
3719
- var import_react25 = require("react");
3720
- var import_jsx_runtime53 = require("react/jsx-runtime");
3798
+ var import_react27 = require("react");
3799
+ var import_jsx_runtime54 = require("react/jsx-runtime");
3721
3800
  function prefersDark(el) {
3722
3801
  const themed = el?.closest("[data-theme]");
3723
3802
  if (themed?.dataset.theme === "dark") return true;
@@ -3725,10 +3804,10 @@ function prefersDark(el) {
3725
3804
  return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
3726
3805
  }
3727
3806
  function MermaidView({ entry, load }) {
3728
- const ref = (0, import_react25.useRef)(null);
3729
- const [svg, setSvg] = (0, import_react25.useState)(null);
3730
- const [error, setError] = (0, import_react25.useState)(null);
3731
- (0, import_react25.useEffect)(() => {
3807
+ const ref = (0, import_react27.useRef)(null);
3808
+ const [svg, setSvg] = (0, import_react27.useState)(null);
3809
+ const [error, setError] = (0, import_react27.useState)(null);
3810
+ (0, import_react27.useEffect)(() => {
3732
3811
  let cancelled = false;
3733
3812
  const draw = async () => {
3734
3813
  let mermaid;
@@ -3771,9 +3850,9 @@ function MermaidView({ entry, load }) {
3771
3850
  };
3772
3851
  }, [entry.code, load]);
3773
3852
  if (svg) {
3774
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("figure", { ref, className: "my-3", children: [
3775
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3776
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3853
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("figure", { ref, className: "my-3", children: [
3854
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3855
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3777
3856
  "div",
3778
3857
  {
3779
3858
  role: "img",
@@ -3784,8 +3863,8 @@ function MermaidView({ entry, load }) {
3784
3863
  )
3785
3864
  ] });
3786
3865
  }
3787
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
3788
- error ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
3866
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
3867
+ error ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
3789
3868
  "p",
3790
3869
  {
3791
3870
  role: "alert",
@@ -3797,12 +3876,12 @@ function MermaidView({ entry, load }) {
3797
3876
  ]
3798
3877
  }
3799
3878
  ) : null,
3800
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(MermaidSource, { entry, ref })
3879
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(MermaidSource, { entry, ref })
3801
3880
  ] });
3802
3881
  }
3803
3882
 
3804
3883
  // src/interactive/island-renderers.tsx
3805
- var import_jsx_runtime54 = require("react/jsx-runtime");
3884
+ var import_jsx_runtime55 = require("react/jsx-runtime");
3806
3885
  var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
3807
3886
  var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
3808
3887
  function cachedCdnModule(url) {
@@ -3819,8 +3898,8 @@ function cachedCdnModule(url) {
3819
3898
  var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
3820
3899
  var loadHljs = cachedCdnModule(HLJS_ESM);
3821
3900
  function CdnHighlightedCode({ entry }) {
3822
- const [html, setHtml] = (0, import_react26.useState)(null);
3823
- (0, import_react26.useEffect)(() => {
3901
+ const [html, setHtml] = (0, import_react28.useState)(null);
3902
+ (0, import_react28.useEffect)(() => {
3824
3903
  let cancelled = false;
3825
3904
  void (async () => {
3826
3905
  try {
@@ -3836,27 +3915,27 @@ function CdnHighlightedCode({ entry }) {
3836
3915
  cancelled = true;
3837
3916
  };
3838
3917
  }, [entry.content, entry.lang]);
3839
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3918
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3840
3919
  "code",
3841
3920
  {
3842
3921
  className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
3843
3922
  dangerouslySetInnerHTML: { __html: html }
3844
3923
  }
3845
- ) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3924
+ ) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3846
3925
  }
3847
3926
  function buildIslandRenderers(opts) {
3848
3927
  const renderers = {};
3849
3928
  if (opts.mermaid) {
3850
- renderers.mermaid = (entry) => (0, import_react26.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
3929
+ renderers.mermaid = (entry) => (0, import_react28.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
3851
3930
  }
3852
3931
  if (opts.syntaxHighlighting) {
3853
- renderers.code = (entry) => (0, import_react26.createElement)(CdnHighlightedCode, { entry });
3932
+ renderers.code = (entry) => (0, import_react28.createElement)(CdnHighlightedCode, { entry });
3854
3933
  }
3855
3934
  return renderers;
3856
3935
  }
3857
3936
 
3858
3937
  // src/interactive/ReportInteractiveIsland.tsx
3859
- var import_jsx_runtime55 = require("react/jsx-runtime");
3938
+ var import_jsx_runtime56 = require("react/jsx-runtime");
3860
3939
  function ReportInteractiveIsland({
3861
3940
  report,
3862
3941
  title,
@@ -3866,11 +3945,11 @@ function ReportInteractiveIsland({
3866
3945
  syntaxHighlighting = true,
3867
3946
  mermaid = true
3868
3947
  }) {
3869
- const renderers = (0, import_react27.useMemo)(
3948
+ const renderers = (0, import_react29.useMemo)(
3870
3949
  () => buildIslandRenderers({ syntaxHighlighting, mermaid }),
3871
3950
  [syntaxHighlighting, mermaid]
3872
3951
  );
3873
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3952
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
3874
3953
  ReportInteractive,
3875
3954
  {
3876
3955
  report,