executable-stories-react 0.14.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.
@@ -47,9 +47,9 @@ __export(interactive_exports, {
47
47
  module.exports = __toCommonJS(interactive_exports);
48
48
 
49
49
  // src/interactive/ReportInteractive.tsx
50
- var import_lucide_react6 = require("lucide-react");
51
- var import_react22 = require("webmcpable/react");
52
- var import_react23 = require("react");
50
+ var import_lucide_react7 = require("lucide-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",
@@ -2526,8 +2604,138 @@ var ReportSearch = (0, import_react13.forwardRef)(
2526
2604
  }
2527
2605
  );
2528
2606
 
2607
+ // src/interactive/ReportShare.tsx
2608
+ var import_lucide_react5 = require("lucide-react");
2609
+ var import_react16 = require("react");
2610
+
2611
+ // src/components/ui/button.tsx
2612
+ var React7 = require("react");
2613
+ var import_class_variance_authority4 = require("class-variance-authority");
2614
+ var import_use_render2 = require("@base-ui/react/use-render");
2615
+ var buttonVariants = (0, import_class_variance_authority4.cva)(
2616
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
2617
+ {
2618
+ variants: {
2619
+ variant: {
2620
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
2621
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
2622
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
2623
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2624
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
2625
+ link: "text-primary underline-offset-4 hover:underline"
2626
+ },
2627
+ size: {
2628
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
2629
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
2630
+ sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
2631
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
2632
+ icon: "size-9",
2633
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
2634
+ "icon-sm": "size-8",
2635
+ "icon-lg": "size-10"
2636
+ }
2637
+ },
2638
+ defaultVariants: {
2639
+ variant: "default",
2640
+ size: "default"
2641
+ }
2642
+ }
2643
+ );
2644
+ function Button({
2645
+ className,
2646
+ variant = "default",
2647
+ size = "default",
2648
+ render,
2649
+ ...props
2650
+ }) {
2651
+ return (0, import_use_render2.useRender)({
2652
+ defaultTagName: "button",
2653
+ render,
2654
+ props: {
2655
+ "data-slot": "button",
2656
+ "data-variant": variant,
2657
+ "data-size": size,
2658
+ className: cn(buttonVariants({ variant, size, className })),
2659
+ ...props
2660
+ }
2661
+ });
2662
+ }
2663
+
2664
+ // src/interactive/ReportShare.tsx
2665
+ var import_jsx_runtime48 = require("react/jsx-runtime");
2666
+ var DEFAULT_SHARE_COMMAND = "npx executable-stories share reports/";
2667
+ function ReportShare({
2668
+ command = DEFAULT_SHARE_COMMAND,
2669
+ onCopy
2670
+ }) {
2671
+ const [open, setOpen] = (0, import_react16.useState)(false);
2672
+ const dialogRef = (0, import_react16.useRef)(null);
2673
+ (0, import_react16.useEffect)(() => {
2674
+ const dialog = dialogRef.current;
2675
+ if (!dialog) return;
2676
+ if (open && !dialog.open) dialog.showModal();
2677
+ else if (!open && dialog.open) dialog.close();
2678
+ }, [open]);
2679
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
2680
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
2681
+ Button,
2682
+ {
2683
+ type: "button",
2684
+ variant: "ghost",
2685
+ size: "sm",
2686
+ "aria-label": "Share this report",
2687
+ title: "Share this report",
2688
+ onClick: () => setOpen(true),
2689
+ children: [
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" })
2692
+ ]
2693
+ }
2694
+ ),
2695
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
2696
+ "dialog",
2697
+ {
2698
+ ref: dialogRef,
2699
+ className: "es-report-share m-auto w-[min(90vw,32rem)] rounded-lg border border-border bg-card p-6 text-card-foreground shadow-lg [overscroll-behavior:contain] backdrop:bg-black/40",
2700
+ "aria-label": "Share this report",
2701
+ onClose: () => setOpen(false),
2702
+ children: [
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)(
2708
+ Button,
2709
+ {
2710
+ type: "button",
2711
+ size: "sm",
2712
+ onClick: () => onCopy(command, "Command copied"),
2713
+ children: "Copy"
2714
+ }
2715
+ )
2716
+ ] }),
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)(
2720
+ "a",
2721
+ {
2722
+ className: "text-xs underline underline-offset-2",
2723
+ href: "https://executablestories.com/guides/sharing-reports/",
2724
+ target: "_blank",
2725
+ rel: "noreferrer",
2726
+ children: "How sharing works"
2727
+ }
2728
+ ),
2729
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), children: "Close" })
2730
+ ] })
2731
+ ]
2732
+ }
2733
+ )
2734
+ ] });
2735
+ }
2736
+
2529
2737
  // src/interactive/ReportSinceLastVisit.tsx
2530
- var import_react14 = require("react");
2738
+ var import_react17 = require("react");
2531
2739
 
2532
2740
  // src/interactive/last-visit.ts
2533
2741
  function snapshotOf(report, atMs) {
@@ -2563,7 +2771,7 @@ function diffSinceVisit(previous, report) {
2563
2771
  }
2564
2772
 
2565
2773
  // src/interactive/ReportSinceLastVisit.tsx
2566
- var import_jsx_runtime47 = require("react/jsx-runtime");
2774
+ var import_jsx_runtime49 = require("react/jsx-runtime");
2567
2775
  var KEY = "es-last-visit";
2568
2776
  var MAX_LINKS2 = 5;
2569
2777
  function readVisit() {
@@ -2588,12 +2796,12 @@ function writeVisit(snapshot) {
2588
2796
  }
2589
2797
  }
2590
2798
  function ScenarioLinks2({ scenarios, tone }) {
2591
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
2592
- scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime47.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: [
2593
2801
  i > 0 ? ", " : "",
2594
- /* @__PURE__ */ (0, import_jsx_runtime47.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 })
2595
2803
  ] }, s.id)),
2596
- scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { children: [
2804
+ scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { children: [
2597
2805
  " and ",
2598
2806
  scenarios.length - MAX_LINKS2,
2599
2807
  " more"
@@ -2601,9 +2809,9 @@ function ScenarioLinks2({ scenarios, tone }) {
2601
2809
  ] });
2602
2810
  }
2603
2811
  function ReportSinceLastVisit({ report }) {
2604
- const [delta, setDelta] = (0, import_react14.useState)(null);
2605
- const [nowMs, setNowMs] = (0, import_react14.useState)(0);
2606
- (0, import_react14.useEffect)(() => {
2812
+ const [delta, setDelta] = (0, import_react17.useState)(null);
2813
+ const [nowMs, setNowMs] = (0, import_react17.useState)(0);
2814
+ (0, import_react17.useEffect)(() => {
2607
2815
  const now = Date.now();
2608
2816
  setDelta(diffSinceVisit(readVisit(), report));
2609
2817
  setNowMs(now);
@@ -2611,25 +2819,25 @@ function ReportSinceLastVisit({ report }) {
2611
2819
  }, [report]);
2612
2820
  if (!delta) return null;
2613
2821
  const { newlyFailing, newlyPassing, added } = delta;
2614
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
2615
- /* @__PURE__ */ (0, import_jsx_runtime47.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: [
2616
2824
  "Since your last visit (",
2617
2825
  formatRelativeAge(delta.sinceMs, nowMs),
2618
2826
  "):"
2619
2827
  ] }),
2620
- newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.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: [
2621
2829
  newlyFailing.length,
2622
2830
  " started failing (",
2623
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2624
2832
  ")"
2625
2833
  ] }) : null,
2626
- newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.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: [
2627
2835
  newlyPassing.length,
2628
2836
  " fixed (",
2629
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2837
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2630
2838
  ")"
2631
2839
  ] }) : null,
2632
- added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ml-2", children: [
2840
+ added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "ml-2", children: [
2633
2841
  added.length,
2634
2842
  " new"
2635
2843
  ] }) : null
@@ -2637,63 +2845,8 @@ function ReportSinceLastVisit({ report }) {
2637
2845
  }
2638
2846
 
2639
2847
  // src/interactive/ReportShortcutsHelp.tsx
2640
- var import_react15 = require("react");
2641
-
2642
- // src/components/ui/button.tsx
2643
- var React7 = require("react");
2644
- var import_class_variance_authority4 = require("class-variance-authority");
2645
- var import_use_render2 = require("@base-ui/react/use-render");
2646
- var buttonVariants = (0, import_class_variance_authority4.cva)(
2647
- "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
2648
- {
2649
- variants: {
2650
- variant: {
2651
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
2652
- destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
2653
- outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
2654
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2655
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
2656
- link: "text-primary underline-offset-4 hover:underline"
2657
- },
2658
- size: {
2659
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
2660
- xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
2661
- sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
2662
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
2663
- icon: "size-9",
2664
- "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
2665
- "icon-sm": "size-8",
2666
- "icon-lg": "size-10"
2667
- }
2668
- },
2669
- defaultVariants: {
2670
- variant: "default",
2671
- size: "default"
2672
- }
2673
- }
2674
- );
2675
- function Button({
2676
- className,
2677
- variant = "default",
2678
- size = "default",
2679
- render,
2680
- ...props
2681
- }) {
2682
- return (0, import_use_render2.useRender)({
2683
- defaultTagName: "button",
2684
- render,
2685
- props: {
2686
- "data-slot": "button",
2687
- "data-variant": variant,
2688
- "data-size": size,
2689
- className: cn(buttonVariants({ variant, size, className })),
2690
- ...props
2691
- }
2692
- });
2693
- }
2694
-
2695
- // src/interactive/ReportShortcutsHelp.tsx
2696
- var import_jsx_runtime48 = require("react/jsx-runtime");
2848
+ var import_react18 = require("react");
2849
+ var import_jsx_runtime50 = require("react/jsx-runtime");
2697
2850
  var SHORTCUTS = [
2698
2851
  { keys: "/", description: "Focus search" },
2699
2852
  { keys: "f", description: "Jump to next failure" },
@@ -2705,20 +2858,20 @@ var SHORTCUTS = [
2705
2858
  ];
2706
2859
  function Keys({ keys }) {
2707
2860
  const parts = keys.split(" ");
2708
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
2709
- i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2710
- /* @__PURE__ */ (0, import_jsx_runtime48.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 })
2711
2864
  ] }, k)) });
2712
2865
  }
2713
2866
  function ReportShortcutsHelp({ open, onClose }) {
2714
- const dialogRef = (0, import_react15.useRef)(null);
2715
- (0, import_react15.useEffect)(() => {
2867
+ const dialogRef = (0, import_react18.useRef)(null);
2868
+ (0, import_react18.useEffect)(() => {
2716
2869
  const dialog = dialogRef.current;
2717
2870
  if (!dialog) return;
2718
2871
  if (open && !dialog.open) dialog.showModal();
2719
2872
  else if (!open && dialog.open) dialog.close();
2720
2873
  }, [open]);
2721
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
2874
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
2722
2875
  "dialog",
2723
2876
  {
2724
2877
  ref: dialogRef,
@@ -2726,20 +2879,20 @@ function ReportShortcutsHelp({ open, onClose }) {
2726
2879
  "aria-label": "Keyboard shortcuts",
2727
2880
  onClose,
2728
2881
  children: [
2729
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2730
- /* @__PURE__ */ (0, import_jsx_runtime48.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_runtime48.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2731
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Keys, { keys: s.keys }) }),
2732
- /* @__PURE__ */ (0, import_jsx_runtime48.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 })
2733
2886
  ] }, s.keys)) }),
2734
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime48.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" }) })
2735
2888
  ]
2736
2889
  }
2737
2890
  );
2738
2891
  }
2739
2892
 
2740
2893
  // src/interactive/ReportToc.tsx
2741
- var import_react16 = require("react");
2742
- var import_jsx_runtime49 = require("react/jsx-runtime");
2894
+ var import_react19 = require("react");
2895
+ var import_jsx_runtime51 = require("react/jsx-runtime");
2743
2896
  var DOT = {
2744
2897
  passed: "bg-pass",
2745
2898
  failed: "bg-fail",
@@ -2748,12 +2901,12 @@ var DOT = {
2748
2901
  };
2749
2902
  function TocContent({ onNavigate }) {
2750
2903
  const report = useReport();
2751
- const [activeId, setActiveId] = (0, import_react16.useState)(null);
2752
- const scenarioIds = (0, import_react16.useMemo)(
2904
+ const [activeId, setActiveId] = (0, import_react19.useState)(null);
2905
+ const scenarioIds = (0, import_react19.useMemo)(
2753
2906
  () => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
2754
2907
  [report]
2755
2908
  );
2756
- (0, import_react16.useEffect)(() => {
2909
+ (0, import_react19.useEffect)(() => {
2757
2910
  if (typeof IntersectionObserver === "undefined") return;
2758
2911
  const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
2759
2912
  if (els.length === 0) return;
@@ -2768,11 +2921,11 @@ function TocContent({ onNavigate }) {
2768
2921
  return () => observer.disconnect();
2769
2922
  }, [scenarioIds]);
2770
2923
  if (report.features.length === 0) return null;
2771
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { children: [
2772
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2773
- /* @__PURE__ */ (0, import_jsx_runtime49.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) => {
2774
2927
  const active = activeId === scenario.id;
2775
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
2928
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
2776
2929
  "a",
2777
2930
  {
2778
2931
  href: `#${scenario.id}`,
@@ -2787,14 +2940,14 @@ function TocContent({ onNavigate }) {
2787
2940
  active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
2788
2941
  ),
2789
2942
  children: [
2790
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2943
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
2791
2944
  "span",
2792
2945
  {
2793
2946
  "aria-hidden": true,
2794
2947
  className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
2795
2948
  }
2796
2949
  ),
2797
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "break-words", children: scenario.title })
2950
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "break-words", children: scenario.title })
2798
2951
  ]
2799
2952
  }
2800
2953
  ) }, scenario.id);
@@ -2804,48 +2957,48 @@ function TocContent({ onNavigate }) {
2804
2957
  function ReportToc() {
2805
2958
  const report = useReport();
2806
2959
  if (report.features.length === 0) return null;
2807
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
2960
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
2808
2961
  "nav",
2809
2962
  {
2810
2963
  "aria-label": "Table of contents",
2811
2964
  className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
2812
2965
  children: [
2813
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2814
- /* @__PURE__ */ (0, import_jsx_runtime49.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, {})
2815
2968
  ]
2816
2969
  }
2817
2970
  );
2818
2971
  }
2819
2972
 
2820
2973
  // src/interactive/ReportTocDrawer.tsx
2821
- var import_react17 = require("react");
2974
+ var import_react20 = require("react");
2822
2975
  var import_dialog = require("@base-ui/react/dialog");
2823
- var import_lucide_react5 = require("lucide-react");
2824
- var import_jsx_runtime50 = require("react/jsx-runtime");
2976
+ var import_lucide_react6 = require("lucide-react");
2977
+ var import_jsx_runtime52 = require("react/jsx-runtime");
2825
2978
  function ReportTocDrawer() {
2826
2979
  const report = useReport();
2827
- const [open, setOpen] = (0, import_react17.useState)(false);
2980
+ const [open, setOpen] = (0, import_react20.useState)(false);
2828
2981
  if (report.features.length === 0) return null;
2829
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
2830
- /* @__PURE__ */ (0, import_jsx_runtime50.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: [
2831
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_lucide_react5.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 }),
2832
2985
  " Contents"
2833
2986
  ] }),
2834
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_dialog.Dialog.Portal, { children: [
2835
- /* @__PURE__ */ (0, import_jsx_runtime50.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" }),
2836
- /* @__PURE__ */ (0, import_jsx_runtime50.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: [
2837
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex items-center justify-between", children: [
2838
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2839
- /* @__PURE__ */ (0, import_jsx_runtime50.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)(
2840
2993
  import_dialog.Dialog.Close,
2841
2994
  {
2842
2995
  "aria-label": "Close contents",
2843
2996
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
2844
- children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_lucide_react5.XIcon, { "aria-hidden": true })
2997
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react6.XIcon, { "aria-hidden": true })
2845
2998
  }
2846
2999
  )
2847
3000
  ] }),
2848
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(TocContent, { onNavigate: () => setOpen(false) })
3001
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(TocContent, { onNavigate: () => setOpen(false) })
2849
3002
  ] })
2850
3003
  ] })
2851
3004
  ] });
@@ -2879,10 +3032,10 @@ function failuresFirst(report) {
2879
3032
  }
2880
3033
 
2881
3034
  // src/interactive/use-deep-link-scroll.ts
2882
- var import_react18 = require("react");
3035
+ var import_react21 = require("react");
2883
3036
  function useDeepLinkScroll() {
2884
- const lastAnchor = (0, import_react18.useRef)(null);
2885
- (0, import_react18.useEffect)(() => {
3037
+ const lastAnchor = (0, import_react21.useRef)(null);
3038
+ (0, import_react21.useEffect)(() => {
2886
3039
  function scrollToHash() {
2887
3040
  const { anchor } = splitHash(window.location.hash);
2888
3041
  if (!anchor || anchor === lastAnchor.current) return;
@@ -2898,7 +3051,7 @@ function useDeepLinkScroll() {
2898
3051
  }
2899
3052
 
2900
3053
  // src/interactive/use-keyboard-shortcuts.ts
2901
- var import_react19 = require("react");
3054
+ var import_react22 = require("react");
2902
3055
  function isEditableTarget(target) {
2903
3056
  if (!(target instanceof HTMLElement)) return false;
2904
3057
  const tag = target.tagName;
@@ -2907,9 +3060,9 @@ function isEditableTarget(target) {
2907
3060
  return false;
2908
3061
  }
2909
3062
  function useKeyboardShortcuts(handlers) {
2910
- const ref = (0, import_react19.useRef)(handlers);
3063
+ const ref = (0, import_react22.useRef)(handlers);
2911
3064
  ref.current = handlers;
2912
- (0, import_react19.useEffect)(() => {
3065
+ (0, import_react22.useEffect)(() => {
2913
3066
  function onKeyDown(e) {
2914
3067
  const h = ref.current;
2915
3068
  if (e.key === "Escape") {
@@ -2953,7 +3106,7 @@ function useKeyboardShortcuts(handlers) {
2953
3106
  }
2954
3107
 
2955
3108
  // src/interactive/use-theme.ts
2956
- var import_react20 = require("react");
3109
+ var import_react23 = require("react");
2957
3110
  var KEY2 = "es-theme";
2958
3111
  function systemDark() {
2959
3112
  return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
@@ -2974,13 +3127,13 @@ function initialPref() {
2974
3127
  return "system";
2975
3128
  }
2976
3129
  function useTheme() {
2977
- const [pref, setPrefState] = (0, import_react20.useState)("system");
2978
- (0, import_react20.useEffect)(() => {
3130
+ const [pref, setPrefState] = (0, import_react23.useState)("system");
3131
+ (0, import_react23.useEffect)(() => {
2979
3132
  const p = initialPref();
2980
3133
  setPrefState(p);
2981
3134
  applyTheme(p);
2982
3135
  }, []);
2983
- (0, import_react20.useEffect)(() => {
3136
+ (0, import_react23.useEffect)(() => {
2984
3137
  if (typeof matchMedia === "undefined") return;
2985
3138
  const mq = matchMedia("(prefers-color-scheme: dark)");
2986
3139
  const onChange = () => {
@@ -2989,7 +3142,7 @@ function useTheme() {
2989
3142
  mq.addEventListener("change", onChange);
2990
3143
  return () => mq.removeEventListener("change", onChange);
2991
3144
  }, [pref]);
2992
- const setPref = (0, import_react20.useCallback)((p) => {
3145
+ const setPref = (0, import_react23.useCallback)((p) => {
2993
3146
  setPrefState(p);
2994
3147
  applyTheme(p);
2995
3148
  try {
@@ -3001,19 +3154,19 @@ function useTheme() {
3001
3154
  }
3002
3155
 
3003
3156
  // src/interactive/use-url-state.ts
3004
- var import_react21 = require("react");
3157
+ var import_react24 = require("react");
3005
3158
  var WRITE_DELAY_MS = 250;
3006
3159
  function useUrlState() {
3007
- const [state, setState] = (0, import_react21.useState)(DEFAULT_URL_STATE);
3008
- const ready = (0, import_react21.useRef)(false);
3009
- (0, import_react21.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)(() => {
3010
3163
  const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
3011
3164
  read();
3012
3165
  ready.current = true;
3013
3166
  window.addEventListener("hashchange", read);
3014
3167
  return () => window.removeEventListener("hashchange", read);
3015
3168
  }, []);
3016
- (0, import_react21.useEffect)(() => {
3169
+ (0, import_react24.useEffect)(() => {
3017
3170
  if (!ready.current) return;
3018
3171
  const timer = setTimeout(
3019
3172
  () => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
@@ -3021,7 +3174,7 @@ function useUrlState() {
3021
3174
  );
3022
3175
  return () => clearTimeout(timer);
3023
3176
  }, [state]);
3024
- const update = (0, import_react21.useCallback)(
3177
+ const update = (0, import_react24.useCallback)(
3025
3178
  (patch) => setState((prev) => ({ ...prev, ...patch })),
3026
3179
  []
3027
3180
  );
@@ -3243,12 +3396,12 @@ function reportTools(deps) {
3243
3396
  }
3244
3397
 
3245
3398
  // src/interactive/ReportInteractive.tsx
3246
- var import_jsx_runtime51 = require("react/jsx-runtime");
3399
+ var import_jsx_runtime53 = require("react/jsx-runtime");
3247
3400
  function ReportInteractive(props) {
3248
3401
  const { report, className, title, dataTheme } = props;
3249
3402
  const result = unwrapReport(report);
3250
3403
  if (!result.ok) {
3251
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3404
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3252
3405
  ReportErrorShell,
3253
3406
  {
3254
3407
  error: result.error,
@@ -3258,18 +3411,18 @@ function ReportInteractive(props) {
3258
3411
  }
3259
3412
  );
3260
3413
  }
3261
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportInteractiveView, { ...props, report: result.data });
3414
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportInteractiveView, { ...props, report: result.data });
3262
3415
  }
3263
3416
  var THEME_OPTIONS = [
3264
- { value: "light", label: "Light", Icon: import_lucide_react6.Sun },
3265
- { value: "system", label: "System", Icon: import_lucide_react6.Monitor },
3266
- { value: "dark", label: "Dark", Icon: import_lucide_react6.Moon }
3417
+ { value: "light", label: "Light", Icon: import_lucide_react7.Sun },
3418
+ { value: "system", label: "System", Icon: import_lucide_react7.Monitor },
3419
+ { value: "dark", label: "Dark", Icon: import_lucide_react7.Moon }
3267
3420
  ];
3268
3421
  function ThemeSegment({
3269
3422
  pref,
3270
3423
  onPref
3271
3424
  }) {
3272
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3425
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3273
3426
  ToggleGroup,
3274
3427
  {
3275
3428
  size: "sm",
@@ -3279,14 +3432,14 @@ function ThemeSegment({
3279
3432
  if (next) onPref(next);
3280
3433
  },
3281
3434
  "aria-label": "Color theme",
3282
- children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3435
+ children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3283
3436
  ToggleGroupItem,
3284
3437
  {
3285
3438
  value,
3286
3439
  "aria-label": label,
3287
3440
  title: label,
3288
3441
  className: "px-2",
3289
- children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Icon, {})
3442
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Icon, {})
3290
3443
  },
3291
3444
  value
3292
3445
  ))
@@ -3303,30 +3456,32 @@ function ReportInteractiveView({
3303
3456
  hideHeader = false,
3304
3457
  hideToc = false,
3305
3458
  staleAfterDays = 7,
3306
- scenarioHistory
3459
+ scenarioHistory,
3460
+ share = false,
3461
+ shareCommand
3307
3462
  }) {
3308
3463
  const [urlState, setUrlState] = useUrlState();
3309
3464
  const { query, status: statusFilter, tags: activeTags, detail } = urlState;
3310
- const setQuery = (0, import_react23.useCallback)(
3465
+ const setQuery = (0, import_react26.useCallback)(
3311
3466
  (next) => setUrlState({ query: next }),
3312
3467
  [setUrlState]
3313
3468
  );
3314
- const setStatusFilter = (0, import_react23.useCallback)(
3469
+ const setStatusFilter = (0, import_react26.useCallback)(
3315
3470
  (next) => setUrlState({ status: next }),
3316
3471
  [setUrlState]
3317
3472
  );
3318
- const setDetail = (0, import_react23.useCallback)(
3473
+ const setDetail = (0, import_react26.useCallback)(
3319
3474
  (next) => setUrlState({ detail: next }),
3320
3475
  [setUrlState]
3321
3476
  );
3322
- const [helpOpen, setHelpOpen] = (0, import_react23.useState)(false);
3477
+ const [helpOpen, setHelpOpen] = (0, import_react26.useState)(false);
3323
3478
  const { pref: themePref, setPref: setThemePref } = useTheme();
3324
- const searchRef = (0, import_react23.useRef)(null);
3325
- const expandId = (0, import_react23.useId)();
3326
- const docsId = (0, import_react23.useId)();
3327
- const deferredQuery = (0, import_react23.useDeferredValue)(query);
3328
- const failures = (0, import_react23.useMemo)(() => listFailures(report), [report]);
3329
- const filtered = (0, import_react23.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)(
3330
3485
  // Features carrying failures float to the top so the first thing on screen
3331
3486
  // is the thing that needs attention; an all-green run keeps source order.
3332
3487
  () => failuresFirst(
@@ -3339,7 +3494,7 @@ function ReportInteractiveView({
3339
3494
  [report, deferredQuery, statusFilter, activeTags]
3340
3495
  );
3341
3496
  const isFiltering = query !== deferredQuery;
3342
- const statusOptions = (0, import_react23.useMemo)(() => {
3497
+ const statusOptions = (0, import_react26.useMemo)(() => {
3343
3498
  const s = report.summary;
3344
3499
  const opts = [
3345
3500
  { key: "all", label: "All", count: s.total }
@@ -3354,21 +3509,21 @@ function ReportInteractiveView({
3354
3509
  opts.push({ key: "pending", label: "Pending", count: s.pending });
3355
3510
  return opts;
3356
3511
  }, [report]);
3357
- const tagOptions = (0, import_react23.useMemo)(() => allTags(report), [report]);
3358
- const toggleTag = (0, import_react23.useCallback)(
3512
+ const tagOptions = (0, import_react26.useMemo)(() => allTags(report), [report]);
3513
+ const toggleTag = (0, import_react26.useCallback)(
3359
3514
  (tag) => setUrlState({
3360
3515
  tags: activeTags.includes(tag) ? activeTags.filter((t) => t !== tag) : [...activeTags, tag]
3361
3516
  }),
3362
3517
  [activeTags, setUrlState]
3363
3518
  );
3364
- const [toast, setToast] = (0, import_react23.useState)(null);
3365
- const toastTimer = (0, import_react23.useRef)(null);
3366
- const showToast = (0, import_react23.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) => {
3367
3522
  setToast(msg);
3368
3523
  if (toastTimer.current) clearTimeout(toastTimer.current);
3369
3524
  toastTimer.current = setTimeout(() => setToast(null), 1800);
3370
3525
  }, []);
3371
- const copy = (0, import_react23.useCallback)(
3526
+ const copy = (0, import_react26.useCallback)(
3372
3527
  (text, msg) => {
3373
3528
  if (typeof navigator !== "undefined" && navigator.clipboard) {
3374
3529
  navigator.clipboard.writeText(text).then(
@@ -3379,7 +3534,7 @@ function ReportInteractiveView({
3379
3534
  },
3380
3535
  [showToast]
3381
3536
  );
3382
- const scenarioActions = (0, import_react23.useMemo)(
3537
+ const scenarioActions = (0, import_react26.useMemo)(
3383
3538
  () => ({
3384
3539
  copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
3385
3540
  copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
@@ -3387,31 +3542,31 @@ function ReportInteractiveView({
3387
3542
  }),
3388
3543
  [copy]
3389
3544
  );
3390
- const copyAllFailures = (0, import_react23.useCallback)(
3545
+ const copyAllFailures = (0, import_react26.useCallback)(
3391
3546
  () => copy(failuresToPrompt(failedScenarios(filtered)), "Failures copied"),
3392
3547
  [copy, filtered]
3393
3548
  );
3394
- const failureIndexRef = (0, import_react23.useRef)(0);
3395
- const allCollapsibleIds = (0, import_react23.useMemo)(
3549
+ const failureIndexRef = (0, import_react26.useRef)(0);
3550
+ const allCollapsibleIds = (0, import_react26.useMemo)(
3396
3551
  () => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
3397
3552
  [report]
3398
3553
  );
3399
3554
  const collapse = useCollapseState(
3400
- (0, import_react23.useCallback)(() => defaultCollapsedIds(report), [report])
3555
+ (0, import_react26.useCallback)(() => defaultCollapsedIds(report), [report])
3401
3556
  );
3402
3557
  const revealFilteredResults = deferredQuery.trim() !== "" || statusFilter !== "all" || activeTags.length > 0;
3403
- const visibleCollapse = (0, import_react23.useMemo)(
3558
+ const visibleCollapse = (0, import_react26.useMemo)(
3404
3559
  () => revealFilteredResults ? { ...collapse.api, isCollapsed: () => false } : collapse.api,
3405
3560
  [collapse.api, revealFilteredResults]
3406
3561
  );
3407
- const collapseAll = (0, import_react23.useCallback)(
3562
+ const collapseAll = (0, import_react26.useCallback)(
3408
3563
  () => collapse.collapseAll(allCollapsibleIds),
3409
3564
  [collapse, allCollapsibleIds]
3410
3565
  );
3411
- const [expandedAll, setExpandedAll] = (0, import_react23.useState)(
3566
+ const [expandedAll, setExpandedAll] = (0, import_react26.useState)(
3412
3567
  () => report.summary.failed === 0
3413
3568
  );
3414
- const setExpanded = (0, import_react23.useCallback)(
3569
+ const setExpanded = (0, import_react26.useCallback)(
3415
3570
  (expanded) => {
3416
3571
  if (expanded) collapse.expandAll();
3417
3572
  else collapseAll();
@@ -3419,8 +3574,8 @@ function ReportInteractiveView({
3419
3574
  },
3420
3575
  [collapse, collapseAll]
3421
3576
  );
3422
- const [agentFilter, setAgentFilter] = (0, import_react23.useState)(null);
3423
- (0, import_react22.useTools)(
3577
+ const [agentFilter, setAgentFilter] = (0, import_react26.useState)(null);
3578
+ (0, import_react25.useTools)(
3424
3579
  reportTools({
3425
3580
  report,
3426
3581
  view: urlState,
@@ -3429,14 +3584,14 @@ function ReportInteractiveView({
3429
3584
  })
3430
3585
  );
3431
3586
  const showAgentFilter = agentFilter !== null && agentFilter.search === query && agentFilter.status === statusFilter && agentFilter.tags.length === activeTags.length && agentFilter.tags.every((tag) => activeTags.includes(tag));
3432
- const clearFilters = (0, import_react23.useCallback)(
3587
+ const clearFilters = (0, import_react26.useCallback)(
3433
3588
  () => setUrlState({ query: "", status: "all", tags: [] }),
3434
3589
  [setUrlState]
3435
3590
  );
3436
- const focusSearch = (0, import_react23.useCallback)(() => {
3591
+ const focusSearch = (0, import_react26.useCallback)(() => {
3437
3592
  searchRef.current?.focus();
3438
3593
  }, []);
3439
- const stepFailure = (0, import_react23.useCallback)(
3594
+ const stepFailure = (0, import_react26.useCallback)(
3440
3595
  (direction) => {
3441
3596
  if (failures.length === 0) return;
3442
3597
  failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
@@ -3445,10 +3600,10 @@ function ReportInteractiveView({
3445
3600
  },
3446
3601
  [failures]
3447
3602
  );
3448
- const toggleHelp = (0, import_react23.useCallback)(() => {
3603
+ const toggleHelp = (0, import_react26.useCallback)(() => {
3449
3604
  setHelpOpen((v) => !v);
3450
3605
  }, []);
3451
- const escape = (0, import_react23.useCallback)(() => {
3606
+ const escape = (0, import_react26.useCallback)(() => {
3452
3607
  if (helpOpen) setHelpOpen(false);
3453
3608
  else if (query !== "") setQuery("");
3454
3609
  }, [helpOpen, query, setQuery]);
@@ -3466,13 +3621,13 @@ function ReportInteractiveView({
3466
3621
  const totalScenarios = report.summary.total;
3467
3622
  const matchedScenarios = filtered.summary.total;
3468
3623
  const showToc = !hideToc && totalScenarios > 3;
3469
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ (0, import_jsx_runtime51.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)(
3470
3625
  ReportRoot,
3471
3626
  {
3472
3627
  report: filtered,
3473
3628
  customRenderers,
3474
3629
  renderers,
3475
- children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
3630
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
3476
3631
  "main",
3477
3632
  {
3478
3633
  className: cn("es-report", "es-report-interactive", className),
@@ -3481,8 +3636,8 @@ function ReportInteractiveView({
3481
3636
  "data-theme": dataTheme,
3482
3637
  "data-detail-level": detail,
3483
3638
  children: [
3484
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("header", { className: "es-report-header", children: [
3485
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
3639
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("header", { className: "es-report-header", children: [
3640
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
3486
3641
  "div",
3487
3642
  {
3488
3643
  "data-es-navbar": true,
@@ -3491,9 +3646,9 @@ function ReportInteractiveView({
3491
3646
  hideHeader ? "justify-end" : "justify-between"
3492
3647
  ),
3493
3648
  children: [
3494
- hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3495
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
3496
- /* @__PURE__ */ (0, import_jsx_runtime51.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)(
3497
3652
  ReportSearch,
3498
3653
  {
3499
3654
  ref: searchRef,
@@ -3503,16 +3658,18 @@ function ReportInteractiveView({
3503
3658
  totalCount: totalScenarios
3504
3659
  }
3505
3660
  ),
3506
- /* @__PURE__ */ (0, import_jsx_runtime51.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 })
3507
3663
  ] })
3508
3664
  ]
3509
3665
  }
3510
3666
  ),
3511
- hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
3512
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportSummary, {}),
3513
- /* @__PURE__ */ (0, import_jsx_runtime51.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, {})
3514
3670
  ] }),
3515
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3671
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportSpanGraph, {}),
3672
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3516
3673
  ReportFreshness,
3517
3674
  {
3518
3675
  lastRunMs: reportLastRunMs(report),
@@ -3520,15 +3677,15 @@ function ReportInteractiveView({
3520
3677
  staleAfterDays
3521
3678
  }
3522
3679
  ),
3523
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3680
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3524
3681
  ReportLastRunDelta,
3525
3682
  {
3526
3683
  history: scenarioHistory,
3527
3684
  report
3528
3685
  }
3529
3686
  ),
3530
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportSinceLastVisit, { report }),
3531
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3687
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ReportSinceLastVisit, { report }),
3688
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3532
3689
  ReportFilters,
3533
3690
  {
3534
3691
  statuses: statusOptions,
@@ -3539,10 +3696,10 @@ function ReportInteractiveView({
3539
3696
  onToggleTag: toggleTag
3540
3697
  }
3541
3698
  ),
3542
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3543
- showToc ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportTocDrawer, {}) : null,
3544
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
3545
- /* @__PURE__ */ (0, import_jsx_runtime51.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)(
3546
3703
  Switch,
3547
3704
  {
3548
3705
  id: expandId,
@@ -3550,7 +3707,7 @@ function ReportInteractiveView({
3550
3707
  onCheckedChange: setExpanded
3551
3708
  }
3552
3709
  ),
3553
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3710
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3554
3711
  "label",
3555
3712
  {
3556
3713
  htmlFor: expandId,
@@ -3559,8 +3716,8 @@ function ReportInteractiveView({
3559
3716
  }
3560
3717
  )
3561
3718
  ] }),
3562
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
3563
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3719
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex items-center gap-2", children: [
3720
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3564
3721
  Switch,
3565
3722
  {
3566
3723
  id: docsId,
@@ -3568,7 +3725,7 @@ function ReportInteractiveView({
3568
3725
  onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
3569
3726
  }
3570
3727
  ),
3571
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3728
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3572
3729
  "label",
3573
3730
  {
3574
3731
  htmlFor: docsId,
@@ -3579,7 +3736,7 @@ function ReportInteractiveView({
3579
3736
  ] })
3580
3737
  ] })
3581
3738
  ] }),
3582
- showAgentFilter ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3739
+ showAgentFilter ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3583
3740
  ReportAgentFilterNotice,
3584
3741
  {
3585
3742
  applied: agentFilter,
@@ -3587,17 +3744,17 @@ function ReportInteractiveView({
3587
3744
  onDismiss: () => setAgentFilter(null)
3588
3745
  }
3589
3746
  ) : null,
3590
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
3591
- hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex gap-6", children: [
3592
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportToc, {}),
3593
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportFeatureList, {}) })
3594
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime51.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)(
3595
3752
  ReportEmpty,
3596
3753
  {
3597
3754
  message: query ? "No scenarios match the search." : void 0
3598
3755
  }
3599
3756
  ),
3600
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3757
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3601
3758
  "button",
3602
3759
  {
3603
3760
  type: "button",
@@ -3608,14 +3765,14 @@ function ReportInteractiveView({
3608
3765
  children: "?"
3609
3766
  }
3610
3767
  ),
3611
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3768
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3612
3769
  ReportShortcutsHelp,
3613
3770
  {
3614
3771
  open: helpOpen,
3615
3772
  onClose: () => setHelpOpen(false)
3616
3773
  }
3617
3774
  ),
3618
- toast ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3775
+ toast ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3619
3776
  "div",
3620
3777
  {
3621
3778
  role: "status",
@@ -3632,14 +3789,14 @@ function ReportInteractiveView({
3632
3789
  }
3633
3790
 
3634
3791
  // src/interactive/ReportInteractiveIsland.tsx
3635
- var import_react26 = require("react");
3792
+ var import_react29 = require("react");
3636
3793
 
3637
3794
  // src/interactive/island-renderers.tsx
3638
- var import_react25 = require("react");
3795
+ var import_react28 = require("react");
3639
3796
 
3640
3797
  // src/components/doc/MermaidView.tsx
3641
- var import_react24 = require("react");
3642
- var import_jsx_runtime52 = require("react/jsx-runtime");
3798
+ var import_react27 = require("react");
3799
+ var import_jsx_runtime54 = require("react/jsx-runtime");
3643
3800
  function prefersDark(el) {
3644
3801
  const themed = el?.closest("[data-theme]");
3645
3802
  if (themed?.dataset.theme === "dark") return true;
@@ -3647,10 +3804,10 @@ function prefersDark(el) {
3647
3804
  return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
3648
3805
  }
3649
3806
  function MermaidView({ entry, load }) {
3650
- const ref = (0, import_react24.useRef)(null);
3651
- const [svg, setSvg] = (0, import_react24.useState)(null);
3652
- const [error, setError] = (0, import_react24.useState)(null);
3653
- (0, import_react24.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)(() => {
3654
3811
  let cancelled = false;
3655
3812
  const draw = async () => {
3656
3813
  let mermaid;
@@ -3693,9 +3850,9 @@ function MermaidView({ entry, load }) {
3693
3850
  };
3694
3851
  }, [entry.code, load]);
3695
3852
  if (svg) {
3696
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("figure", { ref, className: "my-3", children: [
3697
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3698
- /* @__PURE__ */ (0, import_jsx_runtime52.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)(
3699
3856
  "div",
3700
3857
  {
3701
3858
  role: "img",
@@ -3706,8 +3863,8 @@ function MermaidView({ entry, load }) {
3706
3863
  )
3707
3864
  ] });
3708
3865
  }
3709
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
3710
- error ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
3866
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
3867
+ error ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
3711
3868
  "p",
3712
3869
  {
3713
3870
  role: "alert",
@@ -3719,12 +3876,12 @@ function MermaidView({ entry, load }) {
3719
3876
  ]
3720
3877
  }
3721
3878
  ) : null,
3722
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(MermaidSource, { entry, ref })
3879
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(MermaidSource, { entry, ref })
3723
3880
  ] });
3724
3881
  }
3725
3882
 
3726
3883
  // src/interactive/island-renderers.tsx
3727
- var import_jsx_runtime53 = require("react/jsx-runtime");
3884
+ var import_jsx_runtime55 = require("react/jsx-runtime");
3728
3885
  var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
3729
3886
  var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
3730
3887
  function cachedCdnModule(url) {
@@ -3741,8 +3898,8 @@ function cachedCdnModule(url) {
3741
3898
  var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
3742
3899
  var loadHljs = cachedCdnModule(HLJS_ESM);
3743
3900
  function CdnHighlightedCode({ entry }) {
3744
- const [html, setHtml] = (0, import_react25.useState)(null);
3745
- (0, import_react25.useEffect)(() => {
3901
+ const [html, setHtml] = (0, import_react28.useState)(null);
3902
+ (0, import_react28.useEffect)(() => {
3746
3903
  let cancelled = false;
3747
3904
  void (async () => {
3748
3905
  try {
@@ -3758,27 +3915,27 @@ function CdnHighlightedCode({ entry }) {
3758
3915
  cancelled = true;
3759
3916
  };
3760
3917
  }, [entry.content, entry.lang]);
3761
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3918
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3762
3919
  "code",
3763
3920
  {
3764
3921
  className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
3765
3922
  dangerouslySetInnerHTML: { __html: html }
3766
3923
  }
3767
- ) : /* @__PURE__ */ (0, import_jsx_runtime53.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 }) });
3768
3925
  }
3769
3926
  function buildIslandRenderers(opts) {
3770
3927
  const renderers = {};
3771
3928
  if (opts.mermaid) {
3772
- renderers.mermaid = (entry) => (0, import_react25.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
3929
+ renderers.mermaid = (entry) => (0, import_react28.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
3773
3930
  }
3774
3931
  if (opts.syntaxHighlighting) {
3775
- renderers.code = (entry) => (0, import_react25.createElement)(CdnHighlightedCode, { entry });
3932
+ renderers.code = (entry) => (0, import_react28.createElement)(CdnHighlightedCode, { entry });
3776
3933
  }
3777
3934
  return renderers;
3778
3935
  }
3779
3936
 
3780
3937
  // src/interactive/ReportInteractiveIsland.tsx
3781
- var import_jsx_runtime54 = require("react/jsx-runtime");
3938
+ var import_jsx_runtime56 = require("react/jsx-runtime");
3782
3939
  function ReportInteractiveIsland({
3783
3940
  report,
3784
3941
  title,
@@ -3788,11 +3945,11 @@ function ReportInteractiveIsland({
3788
3945
  syntaxHighlighting = true,
3789
3946
  mermaid = true
3790
3947
  }) {
3791
- const renderers = (0, import_react26.useMemo)(
3948
+ const renderers = (0, import_react29.useMemo)(
3792
3949
  () => buildIslandRenderers({ syntaxHighlighting, mermaid }),
3793
3950
  [syntaxHighlighting, mermaid]
3794
3951
  );
3795
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3952
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
3796
3953
  ReportInteractive,
3797
3954
  {
3798
3955
  report,