executable-stories-react 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ssr.cjs CHANGED
@@ -241,7 +241,7 @@ function DocLink({ entry }) {
241
241
  // src/components/doc/DocSection.tsx
242
242
  var import_marked = require("marked");
243
243
 
244
- // src/lib/url.ts
244
+ // ../executable-stories-core/dist/utils/url.js
245
245
  function safeUrl(value) {
246
246
  if (!value) return void 0;
247
247
  const trimmed = value.trim();
@@ -536,18 +536,101 @@ function ReportStepItem({ step }) {
536
536
  );
537
537
  }
538
538
 
539
- // src/components/ReportAttachments.tsx
539
+ // ../executable-stories-core/dist/storyboard.js
540
+ function findScreenshot(entries) {
541
+ for (const entry of entries) {
542
+ if (entry.kind === "screenshot") return entry;
543
+ if (entry.children) {
544
+ const nested = findScreenshot(entry.children);
545
+ if (nested) return nested;
546
+ }
547
+ }
548
+ return void 0;
549
+ }
550
+ function extractStoryboardFrames(scenario) {
551
+ const frames = [];
552
+ for (const step of scenario.steps) {
553
+ const shot = findScreenshot(step.docEntries);
554
+ if (!shot) continue;
555
+ frames.push({
556
+ stepId: step.id,
557
+ stepIndex: step.index,
558
+ keyword: step.keyword,
559
+ text: step.text,
560
+ status: step.status,
561
+ path: shot.path,
562
+ ...shot.alt !== void 0 && { alt: shot.alt }
563
+ });
564
+ }
565
+ return frames;
566
+ }
567
+
568
+ // src/components/ReportStoryboard.tsx
540
569
  var import_jsx_runtime18 = require("react/jsx-runtime");
570
+ var FRAME_GLYPH = {
571
+ passed: "\u2713",
572
+ failed: "\u2717",
573
+ skipped: "\u25CB",
574
+ pending: "\u25CB"
575
+ };
576
+ var FRAME_GLYPH_COLOR = {
577
+ passed: "text-pass",
578
+ failed: "text-fail",
579
+ skipped: "text-skip",
580
+ pending: "text-pend"
581
+ };
582
+ function ReportStoryboard({ scenario }) {
583
+ const frames = extractStoryboardFrames(scenario);
584
+ if (frames.length < 2) return null;
585
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
586
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
587
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { className: "flex gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
588
+ ] });
589
+ }
590
+ function StoryboardFrameItem({ frame }) {
591
+ const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
592
+ const label = `${frame.keyword} ${frame.text}`;
593
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("li", { className: "w-40 shrink-0", children: [
594
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
595
+ "a",
596
+ {
597
+ href: `#${frame.stepId}`,
598
+ "aria-label": `Jump to step: ${label}`,
599
+ className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
600
+ children: src ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
601
+ "img",
602
+ {
603
+ src,
604
+ alt: frame.alt ?? label,
605
+ loading: "lazy",
606
+ className: "h-24 w-full bg-muted object-cover object-top"
607
+ }
608
+ ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
609
+ }
610
+ ),
611
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
612
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
613
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "min-w-0", children: [
614
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
615
+ " ",
616
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
617
+ ] })
618
+ ] })
619
+ ] });
620
+ }
621
+
622
+ // src/components/ReportAttachments.tsx
623
+ var import_jsx_runtime19 = require("react/jsx-runtime");
541
624
  function ReportAttachments({ attachments }) {
542
625
  if (attachments.length === 0) return null;
543
626
  return (
544
627
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
545
628
  // blocks don't create duplicate "Attachments" region landmarks.
546
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
629
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
547
630
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
548
631
  const isImage = att.mediaType.startsWith("image/");
549
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
550
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
632
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
633
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
551
634
  "img",
552
635
  {
553
636
  src: dataUri,
@@ -556,8 +639,8 @@ function ReportAttachments({ attachments }) {
556
639
  className: "max-w-full rounded-md border border-border"
557
640
  }
558
641
  ),
559
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
560
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
642
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
643
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
561
644
  "a",
562
645
  {
563
646
  href: dataUri,
@@ -566,7 +649,7 @@ function ReportAttachments({ attachments }) {
566
649
  children: [
567
650
  att.name,
568
651
  " ",
569
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "text-muted-foreground", children: [
652
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "text-muted-foreground", children: [
570
653
  "(",
571
654
  att.mediaType,
572
655
  ")"
@@ -654,7 +737,7 @@ function traceWindow(rows) {
654
737
  }
655
738
 
656
739
  // src/components/ReportTrace.tsx
657
- var import_jsx_runtime19 = require("react/jsx-runtime");
740
+ var import_jsx_runtime20 = require("react/jsx-runtime");
658
741
  var BAR_COLOR = {
659
742
  ok: "bg-pass",
660
743
  error: "bg-fail",
@@ -665,8 +748,8 @@ function ReportTrace({ spans }) {
665
748
  const rows = toTraceRows(spans);
666
749
  if (rows.length === 0) return null;
667
750
  const { minStartMs, totalMs } = traceWindow(rows);
668
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
669
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
751
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
752
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
670
753
  "Trace (",
671
754
  rows.length,
672
755
  " span",
@@ -675,11 +758,11 @@ function ReportTrace({ spans }) {
675
758
  formatDuration(totalMs),
676
759
  ")"
677
760
  ] }),
678
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
761
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
679
762
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
680
763
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
681
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: "flex items-center gap-2", children: [
682
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
764
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: "flex items-center gap-2", children: [
765
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
683
766
  "span",
684
767
  {
685
768
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -688,14 +771,14 @@ function ReportTrace({ spans }) {
688
771
  children: row.name
689
772
  }
690
773
  ),
691
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
774
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
692
775
  "span",
693
776
  {
694
777
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
695
778
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
696
779
  }
697
780
  ) }),
698
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
781
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
699
782
  ] }, `${row.spanId}-${i}`);
700
783
  }) })
701
784
  ] });
@@ -746,7 +829,7 @@ function flakinessOf(entries) {
746
829
  }
747
830
 
748
831
  // src/components/ScenarioRunHistory.tsx
749
- var import_jsx_runtime20 = require("react/jsx-runtime");
832
+ var import_jsx_runtime21 = require("react/jsx-runtime");
750
833
  var MAX_DOTS = 10;
751
834
  var DOT_COLOR = {
752
835
  passed: "bg-pass",
@@ -766,16 +849,16 @@ function ScenarioRunHistory({ scenarioId }) {
766
849
  const recent = entries.slice(-MAX_DOTS);
767
850
  const flaky = flakinessOf(recent) === "flaky";
768
851
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
769
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
770
- flaky ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
771
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
852
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
853
+ flaky ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
854
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
772
855
  "span",
773
856
  {
774
857
  role: "img",
775
858
  "aria-label": `Run history: ${summary}`,
776
859
  title: summary,
777
860
  className: "flex shrink-0 items-center gap-[3px]",
778
- children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
861
+ children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
779
862
  "span",
780
863
  {
781
864
  "aria-hidden": true,
@@ -814,9 +897,9 @@ function useScenarioActions() {
814
897
 
815
898
  // src/components/ui/card.tsx
816
899
  var React2 = require("react");
817
- var import_jsx_runtime21 = require("react/jsx-runtime");
900
+ var import_jsx_runtime22 = require("react/jsx-runtime");
818
901
  function Card({ className, ...props }) {
819
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
902
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
820
903
  "div",
821
904
  {
822
905
  "data-slot": "card",
@@ -829,7 +912,7 @@ function Card({ className, ...props }) {
829
912
  );
830
913
  }
831
914
  function CardHeader({ className, ...props }) {
832
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
915
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
833
916
  "div",
834
917
  {
835
918
  "data-slot": "card-header",
@@ -842,7 +925,7 @@ function CardHeader({ className, ...props }) {
842
925
  );
843
926
  }
844
927
  function CardContent({ className, ...props }) {
845
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
928
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
846
929
  "div",
847
930
  {
848
931
  "data-slot": "card-content",
@@ -856,13 +939,13 @@ function CardContent({ className, ...props }) {
856
939
  var React3 = require("react");
857
940
  var import_menu = require("@base-ui/react/menu");
858
941
  var import_lucide_react = require("lucide-react");
859
- var import_jsx_runtime22 = require("react/jsx-runtime");
942
+ var import_jsx_runtime23 = require("react/jsx-runtime");
860
943
  var itemClasses = "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground";
861
944
  function DropdownMenu(props) {
862
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
945
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
863
946
  }
864
947
  function DropdownMenuTrigger(props) {
865
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
948
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
866
949
  }
867
950
  function DropdownMenuContent({
868
951
  className,
@@ -870,14 +953,14 @@ function DropdownMenuContent({
870
953
  sideOffset = 4,
871
954
  ...props
872
955
  }) {
873
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
956
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
874
957
  import_menu.Menu.Positioner,
875
958
  {
876
959
  "data-slot": "dropdown-menu-positioner",
877
960
  className: "z-50",
878
961
  align,
879
962
  sideOffset,
880
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
963
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
881
964
  import_menu.Menu.Popup,
882
965
  {
883
966
  "data-slot": "dropdown-menu-content",
@@ -895,7 +978,7 @@ function DropdownMenuItem({
895
978
  className,
896
979
  ...props
897
980
  }) {
898
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
981
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
899
982
  import_menu.Menu.Item,
900
983
  {
901
984
  "data-slot": "dropdown-menu-item",
@@ -907,7 +990,7 @@ function DropdownMenuItem({
907
990
 
908
991
  // src/components/ReportScenario.tsx
909
992
  var import_lucide_react2 = require("lucide-react");
910
- var import_jsx_runtime23 = require("react/jsx-runtime");
993
+ var import_jsx_runtime24 = require("react/jsx-runtime");
911
994
  var STATUS_META = {
912
995
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
913
996
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -923,7 +1006,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
923
1006
  const collapsible = collapse !== null && !hideTitle;
924
1007
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
925
1008
  const actions = useScenarioActions();
926
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1009
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
927
1010
  Card,
928
1011
  {
929
1012
  id: scenario.id,
@@ -931,10 +1014,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
931
1014
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
932
1015
  className: "gap-0 py-0",
933
1016
  children: [
934
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardHeader, { className: "px-4 py-3", children: [
935
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
936
- hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
937
- collapsible ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1017
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CardHeader, { className: "px-4 py-3", children: [
1018
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1019
+ hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1020
+ collapsible ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
938
1021
  "button",
939
1022
  {
940
1023
  type: "button",
@@ -943,49 +1026,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
943
1026
  "aria-controls": bodyId,
944
1027
  "aria-label": `Toggle ${scenario.title}`,
945
1028
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
946
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1029
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
947
1030
  }
948
1031
  ) : null,
949
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
950
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: scenario.title })
1032
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1033
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: scenario.title })
951
1034
  ] }),
952
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
953
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
954
- scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
955
- meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
956
- actions ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenu, { children: [
957
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1035
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1036
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1037
+ scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1038
+ meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1039
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenu, { children: [
1040
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
958
1041
  DropdownMenuTrigger,
959
1042
  {
960
1043
  "aria-label": `Actions for ${scenario.title}`,
961
1044
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
962
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1045
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
963
1046
  }
964
1047
  ),
965
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuContent, { align: "end", children: [
966
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
967
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.LinkIcon, {}),
1048
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuContent, { align: "end", children: [
1049
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1050
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.LinkIcon, {}),
968
1051
  " Copy link"
969
1052
  ] }),
970
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
971
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.FileTextIcon, {}),
1053
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1054
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.FileTextIcon, {}),
972
1055
  " Copy as Markdown"
973
1056
  ] }),
974
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
975
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.SparklesIcon, {}),
1057
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1058
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.SparklesIcon, {}),
976
1059
  " Explain with AI"
977
1060
  ] })
978
1061
  ] })
979
1062
  ] }) : null
980
1063
  ] })
981
1064
  ] }),
982
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
983
- scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
984
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1065
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1066
+ scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1067
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
985
1068
  ] }) : null
986
1069
  ] }),
987
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
988
- scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1070
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1071
+ scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
989
1072
  "pre",
990
1073
  {
991
1074
  role: "alert",
@@ -993,10 +1076,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
993
1076
  children: scenario.errorMessage
994
1077
  }
995
1078
  ) : null,
996
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportSteps, { scenario }),
997
- scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
998
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportAttachments, { attachments: scenario.attachments }),
999
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportTrace, { spans: scenario.otelSpans })
1079
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportStoryboard, { scenario }),
1080
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportSteps, { scenario }),
1081
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1082
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1083
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportTrace, { spans: scenario.otelSpans })
1000
1084
  ] })
1001
1085
  ]
1002
1086
  }
@@ -1004,13 +1088,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1004
1088
  }
1005
1089
 
1006
1090
  // src/components/ReportScenarioList.tsx
1007
- var import_jsx_runtime24 = require("react/jsx-runtime");
1091
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1008
1092
  function ReportScenarioList({ feature }) {
1009
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenario, { scenario }, scenario.id)) });
1093
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenario, { scenario }, scenario.id)) });
1010
1094
  }
1011
1095
 
1012
1096
  // src/components/ReportFeature.tsx
1013
- var import_jsx_runtime25 = require("react/jsx-runtime");
1097
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1014
1098
  function ReportFeature({ feature }) {
1015
1099
  const titleId = `${feature.id}-title`;
1016
1100
  const bodyId = `${feature.id}-body`;
@@ -1021,7 +1105,7 @@ function ReportFeature({ feature }) {
1021
1105
  return (
1022
1106
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1023
1107
  // layer of nesting so the scenario cards below read as the primary unit.
1024
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1108
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1025
1109
  "section",
1026
1110
  {
1027
1111
  id: feature.id,
@@ -1029,9 +1113,9 @@ function ReportFeature({ feature }) {
1029
1113
  "aria-labelledby": titleId,
1030
1114
  className: "flex flex-col gap-3",
1031
1115
  children: [
1032
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1033
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "min-w-0", children: [
1034
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1116
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1117
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "min-w-0", children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1035
1119
  "button",
1036
1120
  {
1037
1121
  type: "button",
@@ -1040,31 +1124,31 @@ function ReportFeature({ feature }) {
1040
1124
  "aria-controls": bodyId,
1041
1125
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1042
1126
  children: [
1043
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1044
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate", children: feature.title })
1127
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1128
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "truncate", children: feature.title })
1045
1129
  ]
1046
1130
  }
1047
1131
  ) : feature.title }),
1048
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1132
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1049
1133
  ] }),
1050
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1134
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1051
1135
  "p",
1052
1136
  {
1053
1137
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1054
1138
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1055
1139
  children: [
1056
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1140
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { children: [
1057
1141
  s.passed,
1058
1142
  " passed"
1059
1143
  ] }),
1060
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1061
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1144
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1145
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1062
1146
  s.failed,
1063
1147
  " failed"
1064
1148
  ] }),
1065
- skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
1066
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1067
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1149
+ skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
1150
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1151
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { children: [
1068
1152
  skipped,
1069
1153
  " skipped"
1070
1154
  ] })
@@ -1073,7 +1157,7 @@ function ReportFeature({ feature }) {
1073
1157
  }
1074
1158
  )
1075
1159
  ] }),
1076
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenarioList, { feature }) })
1160
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenarioList, { feature }) })
1077
1161
  ]
1078
1162
  }
1079
1163
  )
@@ -1081,17 +1165,17 @@ function ReportFeature({ feature }) {
1081
1165
  }
1082
1166
 
1083
1167
  // src/components/ReportFeatureList.tsx
1084
- var import_jsx_runtime26 = require("react/jsx-runtime");
1168
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1085
1169
  function ReportFeatureList() {
1086
1170
  const report = useReport();
1087
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportFeature, { feature }, feature.id)) });
1171
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportFeature, { feature }, feature.id)) });
1088
1172
  }
1089
1173
 
1090
1174
  // src/components/ui/empty.tsx
1091
1175
  var import_class_variance_authority2 = require("class-variance-authority");
1092
- var import_jsx_runtime27 = require("react/jsx-runtime");
1176
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1093
1177
  function Empty({ className, ...props }) {
1094
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1178
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1095
1179
  "div",
1096
1180
  {
1097
1181
  "data-slot": "empty",
@@ -1104,7 +1188,7 @@ function Empty({ className, ...props }) {
1104
1188
  );
1105
1189
  }
1106
1190
  function EmptyHeader({ className, ...props }) {
1107
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1191
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1108
1192
  "div",
1109
1193
  {
1110
1194
  "data-slot": "empty-header",
@@ -1131,7 +1215,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
1131
1215
  }
1132
1216
  );
1133
1217
  function EmptyTitle({ className, ...props }) {
1134
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1218
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1135
1219
  "div",
1136
1220
  {
1137
1221
  "data-slot": "empty-title",
@@ -1142,16 +1226,16 @@ function EmptyTitle({ className, ...props }) {
1142
1226
  }
1143
1227
 
1144
1228
  // src/components/ReportEmpty.tsx
1145
- var import_jsx_runtime28 = require("react/jsx-runtime");
1229
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1146
1230
  function ReportEmpty({ message }) {
1147
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1231
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1148
1232
  }
1149
1233
 
1150
1234
  // src/components/ReportSummary.tsx
1151
- var import_jsx_runtime29 = require("react/jsx-runtime");
1235
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1152
1236
  function ReportSummary({ className }) {
1153
1237
  const report = useReport();
1154
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1238
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1155
1239
  ReportSummaryView,
1156
1240
  {
1157
1241
  summary: report.summary,
@@ -1177,7 +1261,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1177
1261
  if (summary.pending > 0) {
1178
1262
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1179
1263
  }
1180
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1264
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1181
1265
  "dl",
1182
1266
  {
1183
1267
  className: cn(
@@ -1190,17 +1274,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1190
1274
  "aria-label": ariaLabel,
1191
1275
  children: cards.map((c) => {
1192
1276
  const tone = TONE[c.status];
1193
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1277
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1194
1278
  "div",
1195
1279
  {
1196
1280
  "data-status": c.status,
1197
1281
  className: "rounded-lg border bg-card px-4 py-3",
1198
1282
  children: [
1199
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1200
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1283
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1284
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1201
1285
  c.label
1202
1286
  ] }),
1203
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1287
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1204
1288
  ]
1205
1289
  },
1206
1290
  c.status
@@ -1241,7 +1325,7 @@ function prUrl(ci) {
1241
1325
  }
1242
1326
 
1243
1327
  // src/components/ReportMeta.tsx
1244
- var import_jsx_runtime30 = require("react/jsx-runtime");
1328
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1245
1329
  function ReportMeta() {
1246
1330
  const report = useReport();
1247
1331
  const items = [];
@@ -1264,13 +1348,13 @@ function ReportMeta() {
1264
1348
  const short = sha.slice(0, 8);
1265
1349
  items.push({
1266
1350
  label: "Commit",
1267
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1351
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1268
1352
  });
1269
1353
  }
1270
1354
  if (report.ci) {
1271
1355
  items.push({
1272
1356
  label: "CI",
1273
- value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1357
+ value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1274
1358
  ciDisplayName(report.ci.name),
1275
1359
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1276
1360
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1281,7 +1365,7 @@ function ReportMeta() {
1281
1365
  const label = `#${report.ci.prNumber}`;
1282
1366
  items.push({
1283
1367
  label: "PR",
1284
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1368
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1285
1369
  });
1286
1370
  }
1287
1371
  if (items.length === 0) return null;
@@ -1289,48 +1373,48 @@ function ReportMeta() {
1289
1373
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1290
1374
  // collapsed disclosure so it doesn't push the result down. Native <details>
1291
1375
  // so it works with no JS (the SSR/no-hydration report still toggles).
1292
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1293
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1294
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1376
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1377
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1378
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1295
1379
  "Run details"
1296
1380
  ] }),
1297
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1298
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "font-medium", children: item.label }),
1299
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1381
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1382
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dt", { className: "font-medium", children: item.label }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1300
1384
  ] }, item.label)) })
1301
1385
  ] })
1302
1386
  );
1303
1387
  }
1304
1388
 
1305
1389
  // src/components/ReportSchemaError.tsx
1306
- var import_jsx_runtime31 = require("react/jsx-runtime");
1390
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1307
1391
  function ReportSchemaError({ error }) {
1308
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1309
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: "Report could not be displayed." }) }),
1310
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: error.message }),
1311
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
1392
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1393
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("strong", { children: "Report could not be displayed." }) }),
1394
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { children: error.message }),
1395
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("p", { children: [
1312
1396
  "The report bundle is newer than this version of ",
1313
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { children: "executable-stories-react" }),
1397
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("code", { children: "executable-stories-react" }),
1314
1398
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1315
1399
  ] }) : null,
1316
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { children: [
1317
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { children: [
1400
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { children: [
1401
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("summary", { children: [
1318
1402
  error.issues.length,
1319
1403
  " validation issue",
1320
1404
  error.issues.length === 1 ? "" : "s"
1321
1405
  ] }),
1322
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1406
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1323
1407
  ] }) : null
1324
1408
  ] });
1325
1409
  }
1326
1410
 
1327
1411
  // src/components/ReportShell.tsx
1328
- var import_jsx_runtime32 = require("react/jsx-runtime");
1412
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1329
1413
  function ReportTitleBlock({ title }) {
1330
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
1331
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h1", { children: title ?? "Story Report" }),
1332
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSummary, {}),
1333
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportMeta, {})
1414
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
1415
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h1", { children: title ?? "Story Report" }),
1416
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportSummary, {}),
1417
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportMeta, {})
1334
1418
  ] });
1335
1419
  }
1336
1420
  function ReportErrorShell({
@@ -1339,22 +1423,22 @@ function ReportErrorShell({
1339
1423
  title,
1340
1424
  dataTheme
1341
1425
  }) {
1342
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSchemaError, { error }) });
1426
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportSchemaError, { error }) });
1343
1427
  }
1344
1428
 
1345
1429
  // src/components/Report.tsx
1346
- var import_jsx_runtime33 = require("react/jsx-runtime");
1430
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1347
1431
  function Report(props) {
1348
1432
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1349
1433
  const result = unwrapReport(report);
1350
1434
  if (!result.ok) {
1351
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1435
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1352
1436
  }
1353
1437
  const data = result.data;
1354
1438
  const hasContent = data.features.length > 0;
1355
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1356
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportTitleBlock, { title }) }),
1357
- hasContent ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportEmpty, {})
1439
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1440
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportTitleBlock, { title }) }),
1441
+ hasContent ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportEmpty, {})
1358
1442
  ] }) });
1359
1443
  }
1360
1444