executable-stories-react 0.5.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/index.js CHANGED
@@ -216,7 +216,7 @@ function DocLink({ entry }) {
216
216
  // src/components/doc/DocSection.tsx
217
217
  import { marked } from "marked";
218
218
 
219
- // src/lib/url.ts
219
+ // ../executable-stories-core/dist/utils/url.js
220
220
  function safeUrl(value) {
221
221
  if (!value) return void 0;
222
222
  const trimmed = value.trim();
@@ -511,18 +511,101 @@ function ReportStepItem({ step }) {
511
511
  );
512
512
  }
513
513
 
514
+ // ../executable-stories-core/dist/storyboard.js
515
+ function findScreenshot(entries) {
516
+ for (const entry of entries) {
517
+ if (entry.kind === "screenshot") return entry;
518
+ if (entry.children) {
519
+ const nested = findScreenshot(entry.children);
520
+ if (nested) return nested;
521
+ }
522
+ }
523
+ return void 0;
524
+ }
525
+ function extractStoryboardFrames(scenario) {
526
+ const frames = [];
527
+ for (const step of scenario.steps) {
528
+ const shot = findScreenshot(step.docEntries);
529
+ if (!shot) continue;
530
+ frames.push({
531
+ stepId: step.id,
532
+ stepIndex: step.index,
533
+ keyword: step.keyword,
534
+ text: step.text,
535
+ status: step.status,
536
+ path: shot.path,
537
+ ...shot.alt !== void 0 && { alt: shot.alt }
538
+ });
539
+ }
540
+ return frames;
541
+ }
542
+
543
+ // src/components/ReportStoryboard.tsx
544
+ import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
545
+ var FRAME_GLYPH = {
546
+ passed: "\u2713",
547
+ failed: "\u2717",
548
+ skipped: "\u25CB",
549
+ pending: "\u25CB"
550
+ };
551
+ var FRAME_GLYPH_COLOR = {
552
+ passed: "text-pass",
553
+ failed: "text-fail",
554
+ skipped: "text-skip",
555
+ pending: "text-pend"
556
+ };
557
+ function ReportStoryboard({ scenario }) {
558
+ const frames = extractStoryboardFrames(scenario);
559
+ if (frames.length < 2) return null;
560
+ return /* @__PURE__ */ jsxs11("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
561
+ /* @__PURE__ */ jsx18("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
562
+ /* @__PURE__ */ jsx18("ol", { className: "flex gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx18(StoryboardFrameItem, { frame }, frame.stepId)) })
563
+ ] });
564
+ }
565
+ function StoryboardFrameItem({ frame }) {
566
+ const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
567
+ const label = `${frame.keyword} ${frame.text}`;
568
+ return /* @__PURE__ */ jsxs11("li", { className: "w-40 shrink-0", children: [
569
+ /* @__PURE__ */ jsx18(
570
+ "a",
571
+ {
572
+ href: `#${frame.stepId}`,
573
+ "aria-label": `Jump to step: ${label}`,
574
+ className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
575
+ children: src ? /* @__PURE__ */ jsx18(
576
+ "img",
577
+ {
578
+ src,
579
+ alt: frame.alt ?? label,
580
+ loading: "lazy",
581
+ className: "h-24 w-full bg-muted object-cover object-top"
582
+ }
583
+ ) : /* @__PURE__ */ jsx18("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" })
584
+ }
585
+ ),
586
+ /* @__PURE__ */ jsxs11("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
587
+ /* @__PURE__ */ jsx18("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
588
+ /* @__PURE__ */ jsxs11("span", { className: "min-w-0", children: [
589
+ /* @__PURE__ */ jsx18("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
590
+ " ",
591
+ /* @__PURE__ */ jsx18("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
592
+ ] })
593
+ ] })
594
+ ] });
595
+ }
596
+
514
597
  // src/components/ReportAttachments.tsx
515
- import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
598
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
516
599
  function ReportAttachments({ attachments }) {
517
600
  if (attachments.length === 0) return null;
518
601
  return (
519
602
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
520
603
  // blocks don't create duplicate "Attachments" region landmarks.
521
- /* @__PURE__ */ jsx18("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
604
+ /* @__PURE__ */ jsx19("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
522
605
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
523
606
  const isImage = att.mediaType.startsWith("image/");
524
- return /* @__PURE__ */ jsx18("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
525
- /* @__PURE__ */ jsx18(
607
+ return /* @__PURE__ */ jsx19("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
608
+ /* @__PURE__ */ jsx19(
526
609
  "img",
527
610
  {
528
611
  src: dataUri,
@@ -531,8 +614,8 @@ function ReportAttachments({ attachments }) {
531
614
  className: "max-w-full rounded-md border border-border"
532
615
  }
533
616
  ),
534
- /* @__PURE__ */ jsx18("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
535
- ] }) : /* @__PURE__ */ jsxs11(
617
+ /* @__PURE__ */ jsx19("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
618
+ ] }) : /* @__PURE__ */ jsxs12(
536
619
  "a",
537
620
  {
538
621
  href: dataUri,
@@ -541,7 +624,7 @@ function ReportAttachments({ attachments }) {
541
624
  children: [
542
625
  att.name,
543
626
  " ",
544
- /* @__PURE__ */ jsxs11("span", { className: "text-muted-foreground", children: [
627
+ /* @__PURE__ */ jsxs12("span", { className: "text-muted-foreground", children: [
545
628
  "(",
546
629
  att.mediaType,
547
630
  ")"
@@ -629,7 +712,7 @@ function traceWindow(rows) {
629
712
  }
630
713
 
631
714
  // src/components/ReportTrace.tsx
632
- import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
715
+ import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
633
716
  var BAR_COLOR = {
634
717
  ok: "bg-pass",
635
718
  error: "bg-fail",
@@ -640,8 +723,8 @@ function ReportTrace({ spans }) {
640
723
  const rows = toTraceRows(spans);
641
724
  if (rows.length === 0) return null;
642
725
  const { minStartMs, totalMs } = traceWindow(rows);
643
- return /* @__PURE__ */ jsxs12("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
644
- /* @__PURE__ */ jsxs12("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
726
+ return /* @__PURE__ */ jsxs13("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
727
+ /* @__PURE__ */ jsxs13("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
645
728
  "Trace (",
646
729
  rows.length,
647
730
  " span",
@@ -650,11 +733,11 @@ function ReportTrace({ spans }) {
650
733
  formatDuration(totalMs),
651
734
  ")"
652
735
  ] }),
653
- /* @__PURE__ */ jsx19("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
736
+ /* @__PURE__ */ jsx20("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
654
737
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
655
738
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
656
- return /* @__PURE__ */ jsxs12("li", { className: "flex items-center gap-2", children: [
657
- /* @__PURE__ */ jsx19(
739
+ return /* @__PURE__ */ jsxs13("li", { className: "flex items-center gap-2", children: [
740
+ /* @__PURE__ */ jsx20(
658
741
  "span",
659
742
  {
660
743
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -663,14 +746,14 @@ function ReportTrace({ spans }) {
663
746
  children: row.name
664
747
  }
665
748
  ),
666
- /* @__PURE__ */ jsx19("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx19(
749
+ /* @__PURE__ */ jsx20("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx20(
667
750
  "span",
668
751
  {
669
752
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
670
753
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
671
754
  }
672
755
  ) }),
673
- /* @__PURE__ */ jsx19("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
756
+ /* @__PURE__ */ jsx20("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
674
757
  ] }, `${row.spanId}-${i}`);
675
758
  }) })
676
759
  ] });
@@ -721,7 +804,7 @@ function flakinessOf(entries) {
721
804
  }
722
805
 
723
806
  // src/components/ScenarioRunHistory.tsx
724
- import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
807
+ import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
725
808
  var MAX_DOTS = 10;
726
809
  var DOT_COLOR = {
727
810
  passed: "bg-pass",
@@ -741,16 +824,16 @@ function ScenarioRunHistory({ scenarioId }) {
741
824
  const recent = entries.slice(-MAX_DOTS);
742
825
  const flaky = flakinessOf(recent) === "flaky";
743
826
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
744
- return /* @__PURE__ */ jsxs13(Fragment7, { children: [
745
- flaky ? /* @__PURE__ */ jsx20(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
746
- /* @__PURE__ */ jsx20(
827
+ return /* @__PURE__ */ jsxs14(Fragment7, { children: [
828
+ flaky ? /* @__PURE__ */ jsx21(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
829
+ /* @__PURE__ */ jsx21(
747
830
  "span",
748
831
  {
749
832
  role: "img",
750
833
  "aria-label": `Run history: ${summary}`,
751
834
  title: summary,
752
835
  className: "flex shrink-0 items-center gap-[3px]",
753
- children: recent.map((e, i) => /* @__PURE__ */ jsx20(
836
+ children: recent.map((e, i) => /* @__PURE__ */ jsx21(
754
837
  "span",
755
838
  {
756
839
  "aria-hidden": true,
@@ -789,9 +872,9 @@ function useScenarioActions() {
789
872
 
790
873
  // src/components/ui/card.tsx
791
874
  import "react";
792
- import { jsx as jsx21 } from "react/jsx-runtime";
875
+ import { jsx as jsx22 } from "react/jsx-runtime";
793
876
  function Card({ className, ...props }) {
794
- return /* @__PURE__ */ jsx21(
877
+ return /* @__PURE__ */ jsx22(
795
878
  "div",
796
879
  {
797
880
  "data-slot": "card",
@@ -804,7 +887,7 @@ function Card({ className, ...props }) {
804
887
  );
805
888
  }
806
889
  function CardHeader({ className, ...props }) {
807
- return /* @__PURE__ */ jsx21(
890
+ return /* @__PURE__ */ jsx22(
808
891
  "div",
809
892
  {
810
893
  "data-slot": "card-header",
@@ -817,7 +900,7 @@ function CardHeader({ className, ...props }) {
817
900
  );
818
901
  }
819
902
  function CardContent({ className, ...props }) {
820
- return /* @__PURE__ */ jsx21(
903
+ return /* @__PURE__ */ jsx22(
821
904
  "div",
822
905
  {
823
906
  "data-slot": "card-content",
@@ -831,13 +914,13 @@ function CardContent({ className, ...props }) {
831
914
  import "react";
832
915
  import { Menu as MenuPrimitive } from "@base-ui/react/menu";
833
916
  import { CheckIcon } from "lucide-react";
834
- import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
917
+ import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
835
918
  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";
836
919
  function DropdownMenu(props) {
837
- return /* @__PURE__ */ jsx22(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
920
+ return /* @__PURE__ */ jsx23(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
838
921
  }
839
922
  function DropdownMenuTrigger(props) {
840
- return /* @__PURE__ */ jsx22(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
923
+ return /* @__PURE__ */ jsx23(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
841
924
  }
842
925
  function DropdownMenuContent({
843
926
  className,
@@ -845,14 +928,14 @@ function DropdownMenuContent({
845
928
  sideOffset = 4,
846
929
  ...props
847
930
  }) {
848
- return /* @__PURE__ */ jsx22(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx22(
931
+ return /* @__PURE__ */ jsx23(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx23(
849
932
  MenuPrimitive.Positioner,
850
933
  {
851
934
  "data-slot": "dropdown-menu-positioner",
852
935
  className: "z-50",
853
936
  align,
854
937
  sideOffset,
855
- children: /* @__PURE__ */ jsx22(
938
+ children: /* @__PURE__ */ jsx23(
856
939
  MenuPrimitive.Popup,
857
940
  {
858
941
  "data-slot": "dropdown-menu-content",
@@ -870,7 +953,7 @@ function DropdownMenuItem({
870
953
  className,
871
954
  ...props
872
955
  }) {
873
- return /* @__PURE__ */ jsx22(
956
+ return /* @__PURE__ */ jsx23(
874
957
  MenuPrimitive.Item,
875
958
  {
876
959
  "data-slot": "dropdown-menu-item",
@@ -882,7 +965,7 @@ function DropdownMenuItem({
882
965
 
883
966
  // src/components/ReportScenario.tsx
884
967
  import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
885
- import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
968
+ import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
886
969
  var STATUS_META = {
887
970
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
888
971
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -898,7 +981,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
898
981
  const collapsible = collapse !== null && !hideTitle;
899
982
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
900
983
  const actions = useScenarioActions();
901
- return /* @__PURE__ */ jsxs15(
984
+ return /* @__PURE__ */ jsxs16(
902
985
  Card,
903
986
  {
904
987
  id: scenario.id,
@@ -906,10 +989,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
906
989
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
907
990
  className: "gap-0 py-0",
908
991
  children: [
909
- /* @__PURE__ */ jsxs15(CardHeader, { className: "px-4 py-3", children: [
910
- /* @__PURE__ */ jsxs15("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
911
- hideTitle ? null : /* @__PURE__ */ jsxs15("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
912
- collapsible ? /* @__PURE__ */ jsx23(
992
+ /* @__PURE__ */ jsxs16(CardHeader, { className: "px-4 py-3", children: [
993
+ /* @__PURE__ */ jsxs16("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
994
+ hideTitle ? null : /* @__PURE__ */ jsxs16("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
995
+ collapsible ? /* @__PURE__ */ jsx24(
913
996
  "button",
914
997
  {
915
998
  type: "button",
@@ -918,49 +1001,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
918
1001
  "aria-controls": bodyId,
919
1002
  "aria-label": `Toggle ${scenario.title}`,
920
1003
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
921
- children: /* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1004
+ children: /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
922
1005
  }
923
1006
  ) : null,
924
- /* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
925
- /* @__PURE__ */ jsx23("span", { children: scenario.title })
1007
+ /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1008
+ /* @__PURE__ */ jsx24("span", { children: scenario.title })
926
1009
  ] }),
927
- /* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 items-center gap-2", children: [
928
- /* @__PURE__ */ jsx23(ScenarioRunHistory, { scenarioId: scenario.id }),
929
- scenario.durationMs > 0 ? /* @__PURE__ */ jsx23("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
930
- meta.showPill ? /* @__PURE__ */ jsx23(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx23("span", { className: "sr-only", children: `Status: ${label}` }),
931
- actions ? /* @__PURE__ */ jsxs15(DropdownMenu, { children: [
932
- /* @__PURE__ */ jsx23(
1010
+ /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2", children: [
1011
+ /* @__PURE__ */ jsx24(ScenarioRunHistory, { scenarioId: scenario.id }),
1012
+ scenario.durationMs > 0 ? /* @__PURE__ */ jsx24("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1013
+ meta.showPill ? /* @__PURE__ */ jsx24(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx24("span", { className: "sr-only", children: `Status: ${label}` }),
1014
+ actions ? /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
1015
+ /* @__PURE__ */ jsx24(
933
1016
  DropdownMenuTrigger,
934
1017
  {
935
1018
  "aria-label": `Actions for ${scenario.title}`,
936
1019
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
937
- children: /* @__PURE__ */ jsx23(MoreHorizontalIcon, { "aria-hidden": true })
1020
+ children: /* @__PURE__ */ jsx24(MoreHorizontalIcon, { "aria-hidden": true })
938
1021
  }
939
1022
  ),
940
- /* @__PURE__ */ jsxs15(DropdownMenuContent, { align: "end", children: [
941
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
942
- /* @__PURE__ */ jsx23(LinkIcon, {}),
1023
+ /* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", children: [
1024
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1025
+ /* @__PURE__ */ jsx24(LinkIcon, {}),
943
1026
  " Copy link"
944
1027
  ] }),
945
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
946
- /* @__PURE__ */ jsx23(FileTextIcon, {}),
1028
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1029
+ /* @__PURE__ */ jsx24(FileTextIcon, {}),
947
1030
  " Copy as Markdown"
948
1031
  ] }),
949
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
950
- /* @__PURE__ */ jsx23(SparklesIcon, {}),
1032
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1033
+ /* @__PURE__ */ jsx24(SparklesIcon, {}),
951
1034
  " Explain with AI"
952
1035
  ] })
953
1036
  ] })
954
1037
  ] }) : null
955
1038
  ] })
956
1039
  ] }),
957
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs15("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
958
- scenario.tags.map((t) => /* @__PURE__ */ jsx23("li", { children: /* @__PURE__ */ jsx23(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
959
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx23("li", { children: ticket.url ? /* @__PURE__ */ jsx23("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx23(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx23(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1040
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs16("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1041
+ scenario.tags.map((t) => /* @__PURE__ */ jsx24("li", { children: /* @__PURE__ */ jsx24(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1042
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx24("li", { children: ticket.url ? /* @__PURE__ */ jsx24("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx24(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx24(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
960
1043
  ] }) : null
961
1044
  ] }),
962
- /* @__PURE__ */ jsxs15(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
963
- scenario.errorMessage ? /* @__PURE__ */ jsx23(
1045
+ /* @__PURE__ */ jsxs16(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1046
+ scenario.errorMessage ? /* @__PURE__ */ jsx24(
964
1047
  "pre",
965
1048
  {
966
1049
  role: "alert",
@@ -968,10 +1051,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
968
1051
  children: scenario.errorMessage
969
1052
  }
970
1053
  ) : null,
971
- /* @__PURE__ */ jsx23(ReportSteps, { scenario }),
972
- scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx23("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx23(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
973
- /* @__PURE__ */ jsx23(ReportAttachments, { attachments: scenario.attachments }),
974
- /* @__PURE__ */ jsx23(ReportTrace, { spans: scenario.otelSpans })
1054
+ /* @__PURE__ */ jsx24(ReportStoryboard, { scenario }),
1055
+ /* @__PURE__ */ jsx24(ReportSteps, { scenario }),
1056
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx24("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx24(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1057
+ /* @__PURE__ */ jsx24(ReportAttachments, { attachments: scenario.attachments }),
1058
+ /* @__PURE__ */ jsx24(ReportTrace, { spans: scenario.otelSpans })
975
1059
  ] })
976
1060
  ]
977
1061
  }
@@ -979,13 +1063,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
979
1063
  }
980
1064
 
981
1065
  // src/components/ReportScenarioList.tsx
982
- import { Fragment as Fragment8, jsx as jsx24 } from "react/jsx-runtime";
1066
+ import { Fragment as Fragment8, jsx as jsx25 } from "react/jsx-runtime";
983
1067
  function ReportScenarioList({ feature }) {
984
- return /* @__PURE__ */ jsx24(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx24(ReportScenario, { scenario }, scenario.id)) });
1068
+ return /* @__PURE__ */ jsx25(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx25(ReportScenario, { scenario }, scenario.id)) });
985
1069
  }
986
1070
 
987
1071
  // src/components/ReportFeature.tsx
988
- import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
1072
+ import { Fragment as Fragment9, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
989
1073
  function ReportFeature({ feature }) {
990
1074
  const titleId = `${feature.id}-title`;
991
1075
  const bodyId = `${feature.id}-body`;
@@ -996,7 +1080,7 @@ function ReportFeature({ feature }) {
996
1080
  return (
997
1081
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
998
1082
  // layer of nesting so the scenario cards below read as the primary unit.
999
- /* @__PURE__ */ jsxs16(
1083
+ /* @__PURE__ */ jsxs17(
1000
1084
  "section",
1001
1085
  {
1002
1086
  id: feature.id,
@@ -1004,9 +1088,9 @@ function ReportFeature({ feature }) {
1004
1088
  "aria-labelledby": titleId,
1005
1089
  className: "flex flex-col gap-3",
1006
1090
  children: [
1007
- /* @__PURE__ */ jsxs16("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1008
- /* @__PURE__ */ jsxs16("div", { className: "min-w-0", children: [
1009
- /* @__PURE__ */ jsx25("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs16(
1091
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1092
+ /* @__PURE__ */ jsxs17("div", { className: "min-w-0", children: [
1093
+ /* @__PURE__ */ jsx26("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
1010
1094
  "button",
1011
1095
  {
1012
1096
  type: "button",
@@ -1015,31 +1099,31 @@ function ReportFeature({ feature }) {
1015
1099
  "aria-controls": bodyId,
1016
1100
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1017
1101
  children: [
1018
- /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1019
- /* @__PURE__ */ jsx25("span", { className: "truncate", children: feature.title })
1102
+ /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1103
+ /* @__PURE__ */ jsx26("span", { className: "truncate", children: feature.title })
1020
1104
  ]
1021
1105
  }
1022
1106
  ) : feature.title }),
1023
- /* @__PURE__ */ jsx25("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1107
+ /* @__PURE__ */ jsx26("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1024
1108
  ] }),
1025
- /* @__PURE__ */ jsxs16(
1109
+ /* @__PURE__ */ jsxs17(
1026
1110
  "p",
1027
1111
  {
1028
1112
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1029
1113
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1030
1114
  children: [
1031
- /* @__PURE__ */ jsxs16("span", { children: [
1115
+ /* @__PURE__ */ jsxs17("span", { children: [
1032
1116
  s.passed,
1033
1117
  " passed"
1034
1118
  ] }),
1035
- /* @__PURE__ */ jsx25("span", { "aria-hidden": true, children: "\xB7" }),
1036
- /* @__PURE__ */ jsxs16("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1119
+ /* @__PURE__ */ jsx26("span", { "aria-hidden": true, children: "\xB7" }),
1120
+ /* @__PURE__ */ jsxs17("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1037
1121
  s.failed,
1038
1122
  " failed"
1039
1123
  ] }),
1040
- skipped > 0 ? /* @__PURE__ */ jsxs16(Fragment9, { children: [
1041
- /* @__PURE__ */ jsx25("span", { "aria-hidden": true, children: "\xB7" }),
1042
- /* @__PURE__ */ jsxs16("span", { children: [
1124
+ skipped > 0 ? /* @__PURE__ */ jsxs17(Fragment9, { children: [
1125
+ /* @__PURE__ */ jsx26("span", { "aria-hidden": true, children: "\xB7" }),
1126
+ /* @__PURE__ */ jsxs17("span", { children: [
1043
1127
  skipped,
1044
1128
  " skipped"
1045
1129
  ] })
@@ -1048,7 +1132,7 @@ function ReportFeature({ feature }) {
1048
1132
  }
1049
1133
  )
1050
1134
  ] }),
1051
- /* @__PURE__ */ jsx25("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx25(ReportScenarioList, { feature }) })
1135
+ /* @__PURE__ */ jsx26("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx26(ReportScenarioList, { feature }) })
1052
1136
  ]
1053
1137
  }
1054
1138
  )
@@ -1056,17 +1140,17 @@ function ReportFeature({ feature }) {
1056
1140
  }
1057
1141
 
1058
1142
  // src/components/ReportFeatureList.tsx
1059
- import { jsx as jsx26 } from "react/jsx-runtime";
1143
+ import { jsx as jsx27 } from "react/jsx-runtime";
1060
1144
  function ReportFeatureList() {
1061
1145
  const report = useReport();
1062
- return /* @__PURE__ */ jsx26("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx26(ReportFeature, { feature }, feature.id)) });
1146
+ return /* @__PURE__ */ jsx27("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx27(ReportFeature, { feature }, feature.id)) });
1063
1147
  }
1064
1148
 
1065
1149
  // src/components/ui/empty.tsx
1066
1150
  import { cva as cva2 } from "class-variance-authority";
1067
- import { jsx as jsx27 } from "react/jsx-runtime";
1151
+ import { jsx as jsx28 } from "react/jsx-runtime";
1068
1152
  function Empty({ className, ...props }) {
1069
- return /* @__PURE__ */ jsx27(
1153
+ return /* @__PURE__ */ jsx28(
1070
1154
  "div",
1071
1155
  {
1072
1156
  "data-slot": "empty",
@@ -1079,7 +1163,7 @@ function Empty({ className, ...props }) {
1079
1163
  );
1080
1164
  }
1081
1165
  function EmptyHeader({ className, ...props }) {
1082
- return /* @__PURE__ */ jsx27(
1166
+ return /* @__PURE__ */ jsx28(
1083
1167
  "div",
1084
1168
  {
1085
1169
  "data-slot": "empty-header",
@@ -1106,7 +1190,7 @@ var emptyMediaVariants = cva2(
1106
1190
  }
1107
1191
  );
1108
1192
  function EmptyTitle({ className, ...props }) {
1109
- return /* @__PURE__ */ jsx27(
1193
+ return /* @__PURE__ */ jsx28(
1110
1194
  "div",
1111
1195
  {
1112
1196
  "data-slot": "empty-title",
@@ -1117,16 +1201,16 @@ function EmptyTitle({ className, ...props }) {
1117
1201
  }
1118
1202
 
1119
1203
  // src/components/ReportEmpty.tsx
1120
- import { jsx as jsx28 } from "react/jsx-runtime";
1204
+ import { jsx as jsx29 } from "react/jsx-runtime";
1121
1205
  function ReportEmpty({ message }) {
1122
- return /* @__PURE__ */ jsx28(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx28(EmptyHeader, { children: /* @__PURE__ */ jsx28(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1206
+ return /* @__PURE__ */ jsx29(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx29(EmptyHeader, { children: /* @__PURE__ */ jsx29(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1123
1207
  }
1124
1208
 
1125
1209
  // src/components/ReportSummary.tsx
1126
- import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
1210
+ import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
1127
1211
  function ReportSummary({ className }) {
1128
1212
  const report = useReport();
1129
- return /* @__PURE__ */ jsx29(
1213
+ return /* @__PURE__ */ jsx30(
1130
1214
  ReportSummaryView,
1131
1215
  {
1132
1216
  summary: report.summary,
@@ -1152,7 +1236,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1152
1236
  if (summary.pending > 0) {
1153
1237
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1154
1238
  }
1155
- return /* @__PURE__ */ jsx29(
1239
+ return /* @__PURE__ */ jsx30(
1156
1240
  "dl",
1157
1241
  {
1158
1242
  className: cn(
@@ -1165,17 +1249,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1165
1249
  "aria-label": ariaLabel,
1166
1250
  children: cards.map((c) => {
1167
1251
  const tone = TONE[c.status];
1168
- return /* @__PURE__ */ jsxs17(
1252
+ return /* @__PURE__ */ jsxs18(
1169
1253
  "div",
1170
1254
  {
1171
1255
  "data-status": c.status,
1172
1256
  className: "rounded-lg border bg-card px-4 py-3",
1173
1257
  children: [
1174
- /* @__PURE__ */ jsxs17("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1175
- /* @__PURE__ */ jsx29("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1258
+ /* @__PURE__ */ jsxs18("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1259
+ /* @__PURE__ */ jsx30("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1176
1260
  c.label
1177
1261
  ] }),
1178
- /* @__PURE__ */ jsx29("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1262
+ /* @__PURE__ */ jsx30("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1179
1263
  ]
1180
1264
  },
1181
1265
  c.status
@@ -1235,7 +1319,7 @@ function prUrl(ci) {
1235
1319
  }
1236
1320
 
1237
1321
  // src/components/ReportMeta.tsx
1238
- import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
1322
+ import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
1239
1323
  function ReportMeta() {
1240
1324
  const report = useReport();
1241
1325
  const items = [];
@@ -1258,13 +1342,13 @@ function ReportMeta() {
1258
1342
  const short = sha.slice(0, 8);
1259
1343
  items.push({
1260
1344
  label: "Commit",
1261
- value: url ? /* @__PURE__ */ jsx30("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1345
+ value: url ? /* @__PURE__ */ jsx31("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1262
1346
  });
1263
1347
  }
1264
1348
  if (report.ci) {
1265
1349
  items.push({
1266
1350
  label: "CI",
1267
- value: report.ci.url ? /* @__PURE__ */ jsxs18("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1351
+ value: report.ci.url ? /* @__PURE__ */ jsxs19("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1268
1352
  ciDisplayName(report.ci.name),
1269
1353
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1270
1354
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1275,7 +1359,7 @@ function ReportMeta() {
1275
1359
  const label = `#${report.ci.prNumber}`;
1276
1360
  items.push({
1277
1361
  label: "PR",
1278
- value: url ? /* @__PURE__ */ jsx30("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1362
+ value: url ? /* @__PURE__ */ jsx31("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1279
1363
  });
1280
1364
  }
1281
1365
  if (items.length === 0) return null;
@@ -1283,48 +1367,48 @@ function ReportMeta() {
1283
1367
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1284
1368
  // collapsed disclosure so it doesn't push the result down. Native <details>
1285
1369
  // so it works with no JS (the SSR/no-hydration report still toggles).
1286
- /* @__PURE__ */ jsxs18("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1287
- /* @__PURE__ */ jsxs18("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: [
1288
- /* @__PURE__ */ jsx30("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1370
+ /* @__PURE__ */ jsxs19("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1371
+ /* @__PURE__ */ jsxs19("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: [
1372
+ /* @__PURE__ */ jsx31("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1289
1373
  "Run details"
1290
1374
  ] }),
1291
- /* @__PURE__ */ jsx30("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__ */ jsxs18("div", { className: "flex items-baseline gap-1.5", children: [
1292
- /* @__PURE__ */ jsx30("dt", { className: "font-medium", children: item.label }),
1293
- /* @__PURE__ */ jsx30("dd", { className: "font-mono text-foreground", children: item.value })
1375
+ /* @__PURE__ */ jsx31("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__ */ jsxs19("div", { className: "flex items-baseline gap-1.5", children: [
1376
+ /* @__PURE__ */ jsx31("dt", { className: "font-medium", children: item.label }),
1377
+ /* @__PURE__ */ jsx31("dd", { className: "font-mono text-foreground", children: item.value })
1294
1378
  ] }, item.label)) })
1295
1379
  ] })
1296
1380
  );
1297
1381
  }
1298
1382
 
1299
1383
  // src/components/ReportSchemaError.tsx
1300
- import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
1384
+ import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
1301
1385
  function ReportSchemaError({ error }) {
1302
- return /* @__PURE__ */ jsxs19("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1303
- /* @__PURE__ */ jsx31("p", { children: /* @__PURE__ */ jsx31("strong", { children: "Report could not be displayed." }) }),
1304
- /* @__PURE__ */ jsx31("p", { children: error.message }),
1305
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs19("p", { children: [
1386
+ return /* @__PURE__ */ jsxs20("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1387
+ /* @__PURE__ */ jsx32("p", { children: /* @__PURE__ */ jsx32("strong", { children: "Report could not be displayed." }) }),
1388
+ /* @__PURE__ */ jsx32("p", { children: error.message }),
1389
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs20("p", { children: [
1306
1390
  "The report bundle is newer than this version of ",
1307
- /* @__PURE__ */ jsx31("code", { children: "executable-stories-react" }),
1391
+ /* @__PURE__ */ jsx32("code", { children: "executable-stories-react" }),
1308
1392
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1309
1393
  ] }) : null,
1310
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs19("details", { children: [
1311
- /* @__PURE__ */ jsxs19("summary", { children: [
1394
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs20("details", { children: [
1395
+ /* @__PURE__ */ jsxs20("summary", { children: [
1312
1396
  error.issues.length,
1313
1397
  " validation issue",
1314
1398
  error.issues.length === 1 ? "" : "s"
1315
1399
  ] }),
1316
- /* @__PURE__ */ jsx31("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1400
+ /* @__PURE__ */ jsx32("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1317
1401
  ] }) : null
1318
1402
  ] });
1319
1403
  }
1320
1404
 
1321
1405
  // src/components/ReportShell.tsx
1322
- import { Fragment as Fragment10, jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
1406
+ import { Fragment as Fragment10, jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1323
1407
  function ReportTitleBlock({ title }) {
1324
- return /* @__PURE__ */ jsxs20(Fragment10, { children: [
1325
- /* @__PURE__ */ jsx32("h1", { children: title ?? "Story Report" }),
1326
- /* @__PURE__ */ jsx32(ReportSummary, {}),
1327
- /* @__PURE__ */ jsx32(ReportMeta, {})
1408
+ return /* @__PURE__ */ jsxs21(Fragment10, { children: [
1409
+ /* @__PURE__ */ jsx33("h1", { children: title ?? "Story Report" }),
1410
+ /* @__PURE__ */ jsx33(ReportSummary, {}),
1411
+ /* @__PURE__ */ jsx33(ReportMeta, {})
1328
1412
  ] });
1329
1413
  }
1330
1414
  function ReportErrorShell({
@@ -1333,28 +1417,28 @@ function ReportErrorShell({
1333
1417
  title,
1334
1418
  dataTheme
1335
1419
  }) {
1336
- return /* @__PURE__ */ jsx32("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx32(ReportSchemaError, { error }) });
1420
+ return /* @__PURE__ */ jsx33("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx33(ReportSchemaError, { error }) });
1337
1421
  }
1338
1422
 
1339
1423
  // src/components/Report.tsx
1340
- import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1424
+ import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1341
1425
  function Report(props) {
1342
1426
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1343
1427
  const result = unwrapReport(report);
1344
1428
  if (!result.ok) {
1345
- return /* @__PURE__ */ jsx33(ReportErrorShell, { error: result.error, className, title, dataTheme });
1429
+ return /* @__PURE__ */ jsx34(ReportErrorShell, { error: result.error, className, title, dataTheme });
1346
1430
  }
1347
1431
  const data = result.data;
1348
1432
  const hasContent = data.features.length > 0;
1349
- return /* @__PURE__ */ jsx33(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs21("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1350
- /* @__PURE__ */ jsx33("header", { className: "es-report-header", children: /* @__PURE__ */ jsx33(ReportTitleBlock, { title }) }),
1351
- hasContent ? /* @__PURE__ */ jsx33(ReportFeatureList, {}) : /* @__PURE__ */ jsx33(ReportEmpty, {})
1433
+ return /* @__PURE__ */ jsx34(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs22("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1434
+ /* @__PURE__ */ jsx34("header", { className: "es-report-header", children: /* @__PURE__ */ jsx34(ReportTitleBlock, { title }) }),
1435
+ hasContent ? /* @__PURE__ */ jsx34(ReportFeatureList, {}) : /* @__PURE__ */ jsx34(ReportEmpty, {})
1352
1436
  ] }) });
1353
1437
  }
1354
1438
 
1355
1439
  // src/components/doc/MermaidView.tsx
1356
1440
  import { useEffect, useRef, useState as useState2 } from "react";
1357
- import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1441
+ import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
1358
1442
  function prefersDark(el) {
1359
1443
  const themed = el?.closest("[data-theme]");
1360
1444
  if (themed?.dataset.theme === "dark") return true;
@@ -1391,9 +1475,9 @@ function MermaidView({ entry, load }) {
1391
1475
  };
1392
1476
  }, [entry.code, load]);
1393
1477
  if (svg) {
1394
- return /* @__PURE__ */ jsxs22("figure", { ref, className: "my-3", children: [
1395
- entry.title ? /* @__PURE__ */ jsx34("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1396
- /* @__PURE__ */ jsx34(
1478
+ return /* @__PURE__ */ jsxs23("figure", { ref, className: "my-3", children: [
1479
+ entry.title ? /* @__PURE__ */ jsx35("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1480
+ /* @__PURE__ */ jsx35(
1397
1481
  "div",
1398
1482
  {
1399
1483
  role: "img",
@@ -1404,18 +1488,18 @@ function MermaidView({ entry, load }) {
1404
1488
  )
1405
1489
  ] });
1406
1490
  }
1407
- return /* @__PURE__ */ jsx34(MermaidSource, { entry, ref });
1491
+ return /* @__PURE__ */ jsx35(MermaidSource, { entry, ref });
1408
1492
  }
1409
1493
 
1410
1494
  // src/components/doc/MermaidDiagram.tsx
1411
- import { jsx as jsx35 } from "react/jsx-runtime";
1495
+ import { jsx as jsx36 } from "react/jsx-runtime";
1412
1496
  var mermaidLoader;
1413
1497
  function loadMermaid() {
1414
1498
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1415
1499
  return mermaidLoader;
1416
1500
  }
1417
1501
  function MermaidDiagram({ entry, load = loadMermaid }) {
1418
- return /* @__PURE__ */ jsx35(MermaidView, { entry, load });
1502
+ return /* @__PURE__ */ jsx36(MermaidView, { entry, load });
1419
1503
  }
1420
1504
 
1421
1505
  // src/components/ScenarioExplorer.tsx
@@ -1425,12 +1509,12 @@ import { useState as useState3 } from "react";
1425
1509
  import "react";
1426
1510
  import { Command as CommandPrimitive } from "cmdk";
1427
1511
  import { SearchIcon } from "lucide-react";
1428
- import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1512
+ import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1429
1513
  function Command({
1430
1514
  className,
1431
1515
  ...props
1432
1516
  }) {
1433
- return /* @__PURE__ */ jsx36(
1517
+ return /* @__PURE__ */ jsx37(
1434
1518
  CommandPrimitive,
1435
1519
  {
1436
1520
  "data-slot": "command",
@@ -1446,14 +1530,14 @@ function CommandInput({
1446
1530
  className,
1447
1531
  ...props
1448
1532
  }) {
1449
- return /* @__PURE__ */ jsxs23(
1533
+ return /* @__PURE__ */ jsxs24(
1450
1534
  "div",
1451
1535
  {
1452
1536
  "data-slot": "command-input-wrapper",
1453
1537
  className: "flex h-9 items-center gap-2 border-b px-3",
1454
1538
  children: [
1455
- /* @__PURE__ */ jsx36(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1456
- /* @__PURE__ */ jsx36(
1539
+ /* @__PURE__ */ jsx37(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1540
+ /* @__PURE__ */ jsx37(
1457
1541
  CommandPrimitive.Input,
1458
1542
  {
1459
1543
  "data-slot": "command-input",
@@ -1472,7 +1556,7 @@ function CommandList({
1472
1556
  className,
1473
1557
  ...props
1474
1558
  }) {
1475
- return /* @__PURE__ */ jsx36(
1559
+ return /* @__PURE__ */ jsx37(
1476
1560
  CommandPrimitive.List,
1477
1561
  {
1478
1562
  "data-slot": "command-list",
@@ -1487,7 +1571,7 @@ function CommandList({
1487
1571
  function CommandEmpty({
1488
1572
  ...props
1489
1573
  }) {
1490
- return /* @__PURE__ */ jsx36(
1574
+ return /* @__PURE__ */ jsx37(
1491
1575
  CommandPrimitive.Empty,
1492
1576
  {
1493
1577
  "data-slot": "command-empty",
@@ -1500,7 +1584,7 @@ function CommandGroup({
1500
1584
  className,
1501
1585
  ...props
1502
1586
  }) {
1503
- return /* @__PURE__ */ jsx36(
1587
+ return /* @__PURE__ */ jsx37(
1504
1588
  CommandPrimitive.Group,
1505
1589
  {
1506
1590
  "data-slot": "command-group",
@@ -1516,7 +1600,7 @@ function CommandItem({
1516
1600
  className,
1517
1601
  ...props
1518
1602
  }) {
1519
- return /* @__PURE__ */ jsx36(
1603
+ return /* @__PURE__ */ jsx37(
1520
1604
  CommandPrimitive.Item,
1521
1605
  {
1522
1606
  "data-slot": "command-item",
@@ -1530,7 +1614,7 @@ function CommandItem({
1530
1614
  }
1531
1615
 
1532
1616
  // src/components/ScenarioExplorer.tsx
1533
- import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1617
+ import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
1534
1618
  var STATUS_FILTERS = [
1535
1619
  { value: "all", label: "All" },
1536
1620
  { value: "passed", label: "Passed" },
@@ -1541,22 +1625,22 @@ var STATUS_FILTERS = [
1541
1625
  function ScenarioExplorer({ scenarios, summary }) {
1542
1626
  const [status, setStatus] = useState3("all");
1543
1627
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1544
- return /* @__PURE__ */ jsxs24("div", { className: "font-sans text-foreground", children: [
1545
- summary ? /* @__PURE__ */ jsxs24("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1628
+ return /* @__PURE__ */ jsxs25("div", { className: "font-sans text-foreground", children: [
1629
+ summary ? /* @__PURE__ */ jsxs25("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1546
1630
  summary.total,
1547
1631
  " scenarios \xB7 ",
1548
- /* @__PURE__ */ jsxs24("span", { className: "text-pass", children: [
1632
+ /* @__PURE__ */ jsxs25("span", { className: "text-pass", children: [
1549
1633
  summary.passed,
1550
1634
  " passed"
1551
1635
  ] }),
1552
1636
  " \xB7",
1553
1637
  " ",
1554
- /* @__PURE__ */ jsxs24("span", { className: "text-fail", children: [
1638
+ /* @__PURE__ */ jsxs25("span", { className: "text-fail", children: [
1555
1639
  summary.failed,
1556
1640
  " failed"
1557
1641
  ] })
1558
1642
  ] }) : null,
1559
- /* @__PURE__ */ jsx37("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx37(
1643
+ /* @__PURE__ */ jsx38("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx38(
1560
1644
  "button",
1561
1645
  {
1562
1646
  type: "button",
@@ -1571,26 +1655,26 @@ function ScenarioExplorer({ scenarios, summary }) {
1571
1655
  },
1572
1656
  f.value
1573
1657
  )) }),
1574
- /* @__PURE__ */ jsxs24(
1658
+ /* @__PURE__ */ jsxs25(
1575
1659
  Command,
1576
1660
  {
1577
1661
  className: "rounded-lg border border-border bg-card",
1578
1662
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1579
1663
  children: [
1580
- /* @__PURE__ */ jsx37(CommandInput, { placeholder: "Search scenarios\u2026" }),
1581
- /* @__PURE__ */ jsxs24(CommandList, { className: "max-h-none", children: [
1582
- /* @__PURE__ */ jsx37(CommandEmpty, { children: "No scenarios match your filters." }),
1583
- /* @__PURE__ */ jsx37(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx37(
1664
+ /* @__PURE__ */ jsx38(CommandInput, { placeholder: "Search scenarios\u2026" }),
1665
+ /* @__PURE__ */ jsxs25(CommandList, { className: "max-h-none", children: [
1666
+ /* @__PURE__ */ jsx38(CommandEmpty, { children: "No scenarios match your filters." }),
1667
+ /* @__PURE__ */ jsx38(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx38(
1584
1668
  CommandItem,
1585
1669
  {
1586
1670
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1587
1671
  asChild: true,
1588
1672
  className: "cursor-pointer",
1589
- children: /* @__PURE__ */ jsxs24("a", { href: s.href, className: "flex items-center gap-3", children: [
1590
- /* @__PURE__ */ jsx37(Badge, { variant: s.status, children: s.status }),
1591
- /* @__PURE__ */ jsx37("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1592
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx37(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1593
- /* @__PURE__ */ jsx37("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1673
+ children: /* @__PURE__ */ jsxs25("a", { href: s.href, className: "flex items-center gap-3", children: [
1674
+ /* @__PURE__ */ jsx38(Badge, { variant: s.status, children: s.status }),
1675
+ /* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1676
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx38(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1677
+ /* @__PURE__ */ jsx38("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1594
1678
  ] })
1595
1679
  },
1596
1680
  s.id
@@ -2610,6 +2694,7 @@ export {
2610
2694
  ReportSchemaError,
2611
2695
  ReportStepItem,
2612
2696
  ReportSteps,
2697
+ ReportStoryboard,
2613
2698
  ReportSummary,
2614
2699
  ReportSummaryView,
2615
2700
  ReportTrace,