executable-stories-react 0.14.0 → 0.15.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.
@@ -8,8 +8,8 @@ import {
8
8
  useDeferredValue,
9
9
  useId as useId2,
10
10
  useMemo as useMemo3,
11
- useRef as useRef5,
12
- useState as useState10
11
+ useRef as useRef6,
12
+ useState as useState11
13
13
  } from "react";
14
14
 
15
15
  // src/components/ui/empty.tsx
@@ -2493,8 +2493,138 @@ var ReportSearch = forwardRef(
2493
2493
  }
2494
2494
  );
2495
2495
 
2496
+ // src/interactive/ReportShare.tsx
2497
+ import { Share2 } from "lucide-react";
2498
+ import { useEffect as useEffect3, useRef, useState as useState5 } from "react";
2499
+
2500
+ // src/components/ui/button.tsx
2501
+ import "react";
2502
+ import { cva as cva4 } from "class-variance-authority";
2503
+ import { useRender as useRender2 } from "@base-ui/react/use-render";
2504
+ var buttonVariants = cva4(
2505
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
2506
+ {
2507
+ variants: {
2508
+ variant: {
2509
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
2510
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
2511
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
2512
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2513
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
2514
+ link: "text-primary underline-offset-4 hover:underline"
2515
+ },
2516
+ size: {
2517
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
2518
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
2519
+ sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
2520
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
2521
+ icon: "size-9",
2522
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
2523
+ "icon-sm": "size-8",
2524
+ "icon-lg": "size-10"
2525
+ }
2526
+ },
2527
+ defaultVariants: {
2528
+ variant: "default",
2529
+ size: "default"
2530
+ }
2531
+ }
2532
+ );
2533
+ function Button({
2534
+ className,
2535
+ variant = "default",
2536
+ size = "default",
2537
+ render,
2538
+ ...props
2539
+ }) {
2540
+ return useRender2({
2541
+ defaultTagName: "button",
2542
+ render,
2543
+ props: {
2544
+ "data-slot": "button",
2545
+ "data-variant": variant,
2546
+ "data-size": size,
2547
+ className: cn(buttonVariants({ variant, size, className })),
2548
+ ...props
2549
+ }
2550
+ });
2551
+ }
2552
+
2553
+ // src/interactive/ReportShare.tsx
2554
+ import { Fragment as Fragment14, jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2555
+ var DEFAULT_SHARE_COMMAND = "npx executable-stories share reports/";
2556
+ function ReportShare({
2557
+ command = DEFAULT_SHARE_COMMAND,
2558
+ onCopy
2559
+ }) {
2560
+ const [open, setOpen] = useState5(false);
2561
+ const dialogRef = useRef(null);
2562
+ useEffect3(() => {
2563
+ const dialog = dialogRef.current;
2564
+ if (!dialog) return;
2565
+ if (open && !dialog.open) dialog.showModal();
2566
+ else if (!open && dialog.open) dialog.close();
2567
+ }, [open]);
2568
+ return /* @__PURE__ */ jsxs31(Fragment14, { children: [
2569
+ /* @__PURE__ */ jsxs31(
2570
+ Button,
2571
+ {
2572
+ type: "button",
2573
+ variant: "ghost",
2574
+ size: "sm",
2575
+ "aria-label": "Share this report",
2576
+ title: "Share this report",
2577
+ onClick: () => setOpen(true),
2578
+ children: [
2579
+ /* @__PURE__ */ jsx46(Share2, { "aria-hidden": "true", className: "size-4" }),
2580
+ /* @__PURE__ */ jsx46("span", { className: "sr-only sm:not-sr-only", children: "Share" })
2581
+ ]
2582
+ }
2583
+ ),
2584
+ /* @__PURE__ */ jsxs31(
2585
+ "dialog",
2586
+ {
2587
+ ref: dialogRef,
2588
+ className: "es-report-share m-auto w-[min(90vw,32rem)] rounded-lg border border-border bg-card p-6 text-card-foreground shadow-lg [overscroll-behavior:contain] backdrop:bg-black/40",
2589
+ "aria-label": "Share this report",
2590
+ onClose: () => setOpen(false),
2591
+ children: [
2592
+ /* @__PURE__ */ jsx46("h2", { className: "text-base font-semibold", children: "Share this report" }),
2593
+ /* @__PURE__ */ jsx46("p", { className: "mt-2 text-sm text-muted-foreground", children: "Publish it to Executable Stories Cloud and send a link. Screenshots and videos go with it. Run this from your project:" }),
2594
+ /* @__PURE__ */ jsxs31("div", { className: "mt-4 flex items-center gap-2", children: [
2595
+ /* @__PURE__ */ jsx46("code", { className: "min-w-0 flex-1 truncate rounded border border-border bg-muted px-3 py-2 font-mono text-xs", children: command }),
2596
+ /* @__PURE__ */ jsx46(
2597
+ Button,
2598
+ {
2599
+ type: "button",
2600
+ size: "sm",
2601
+ onClick: () => onCopy(command, "Command copied"),
2602
+ children: "Copy"
2603
+ }
2604
+ )
2605
+ ] }),
2606
+ /* @__PURE__ */ jsx46("p", { className: "mt-3 text-xs text-muted-foreground", children: "The file you are reading cannot upload itself, so the command does it: only the CLI can read the assets this report links to." }),
2607
+ /* @__PURE__ */ jsxs31("div", { className: "mt-6 flex items-center justify-between gap-4", children: [
2608
+ /* @__PURE__ */ jsx46(
2609
+ "a",
2610
+ {
2611
+ className: "text-xs underline underline-offset-2",
2612
+ href: "https://executablestories.com/guides/sharing-reports/",
2613
+ target: "_blank",
2614
+ rel: "noreferrer",
2615
+ children: "How sharing works"
2616
+ }
2617
+ ),
2618
+ /* @__PURE__ */ jsx46(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), children: "Close" })
2619
+ ] })
2620
+ ]
2621
+ }
2622
+ )
2623
+ ] });
2624
+ }
2625
+
2496
2626
  // src/interactive/ReportSinceLastVisit.tsx
2497
- import { useEffect as useEffect3, useState as useState5 } from "react";
2627
+ import { useEffect as useEffect4, useState as useState6 } from "react";
2498
2628
 
2499
2629
  // src/interactive/last-visit.ts
2500
2630
  function snapshotOf(report, atMs) {
@@ -2530,7 +2660,7 @@ function diffSinceVisit(previous, report) {
2530
2660
  }
2531
2661
 
2532
2662
  // src/interactive/ReportSinceLastVisit.tsx
2533
- import { Fragment as Fragment14, jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2663
+ import { Fragment as Fragment15, jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2534
2664
  var KEY = "es-last-visit";
2535
2665
  var MAX_LINKS2 = 5;
2536
2666
  function readVisit() {
@@ -2555,12 +2685,12 @@ function writeVisit(snapshot) {
2555
2685
  }
2556
2686
  }
2557
2687
  function ScenarioLinks2({ scenarios, tone }) {
2558
- return /* @__PURE__ */ jsxs31(Fragment14, { children: [
2559
- scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ jsxs31("span", { children: [
2688
+ return /* @__PURE__ */ jsxs32(Fragment15, { children: [
2689
+ scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ jsxs32("span", { children: [
2560
2690
  i > 0 ? ", " : "",
2561
- /* @__PURE__ */ jsx46("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2691
+ /* @__PURE__ */ jsx47("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2562
2692
  ] }, s.id)),
2563
- scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ jsxs31("span", { children: [
2693
+ scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ jsxs32("span", { children: [
2564
2694
  " and ",
2565
2695
  scenarios.length - MAX_LINKS2,
2566
2696
  " more"
@@ -2568,9 +2698,9 @@ function ScenarioLinks2({ scenarios, tone }) {
2568
2698
  ] });
2569
2699
  }
2570
2700
  function ReportSinceLastVisit({ report }) {
2571
- const [delta, setDelta] = useState5(null);
2572
- const [nowMs, setNowMs] = useState5(0);
2573
- useEffect3(() => {
2701
+ const [delta, setDelta] = useState6(null);
2702
+ const [nowMs, setNowMs] = useState6(0);
2703
+ useEffect4(() => {
2574
2704
  const now = Date.now();
2575
2705
  setDelta(diffSinceVisit(readVisit(), report));
2576
2706
  setNowMs(now);
@@ -2578,25 +2708,25 @@ function ReportSinceLastVisit({ report }) {
2578
2708
  }, [report]);
2579
2709
  if (!delta) return null;
2580
2710
  const { newlyFailing, newlyPassing, added } = delta;
2581
- return /* @__PURE__ */ jsxs31("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
2582
- /* @__PURE__ */ jsxs31("span", { className: "font-medium text-foreground", children: [
2711
+ return /* @__PURE__ */ jsxs32("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
2712
+ /* @__PURE__ */ jsxs32("span", { className: "font-medium text-foreground", children: [
2583
2713
  "Since your last visit (",
2584
2714
  formatRelativeAge(delta.sinceMs, nowMs),
2585
2715
  "):"
2586
2716
  ] }),
2587
- newlyFailing.length > 0 ? /* @__PURE__ */ jsxs31("span", { className: "ml-2 text-fail", children: [
2717
+ newlyFailing.length > 0 ? /* @__PURE__ */ jsxs32("span", { className: "ml-2 text-fail", children: [
2588
2718
  newlyFailing.length,
2589
2719
  " started failing (",
2590
- /* @__PURE__ */ jsx46(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2720
+ /* @__PURE__ */ jsx47(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2591
2721
  ")"
2592
2722
  ] }) : null,
2593
- newlyPassing.length > 0 ? /* @__PURE__ */ jsxs31("span", { className: "ml-2 text-pass", children: [
2723
+ newlyPassing.length > 0 ? /* @__PURE__ */ jsxs32("span", { className: "ml-2 text-pass", children: [
2594
2724
  newlyPassing.length,
2595
2725
  " fixed (",
2596
- /* @__PURE__ */ jsx46(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2726
+ /* @__PURE__ */ jsx47(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2597
2727
  ")"
2598
2728
  ] }) : null,
2599
- added.length > 0 ? /* @__PURE__ */ jsxs31("span", { className: "ml-2", children: [
2729
+ added.length > 0 ? /* @__PURE__ */ jsxs32("span", { className: "ml-2", children: [
2600
2730
  added.length,
2601
2731
  " new"
2602
2732
  ] }) : null
@@ -2604,63 +2734,8 @@ function ReportSinceLastVisit({ report }) {
2604
2734
  }
2605
2735
 
2606
2736
  // src/interactive/ReportShortcutsHelp.tsx
2607
- import { useEffect as useEffect4, useRef } from "react";
2608
-
2609
- // src/components/ui/button.tsx
2610
- import "react";
2611
- import { cva as cva4 } from "class-variance-authority";
2612
- import { useRender as useRender2 } from "@base-ui/react/use-render";
2613
- var buttonVariants = cva4(
2614
- "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
2615
- {
2616
- variants: {
2617
- variant: {
2618
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
2619
- destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
2620
- outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
2621
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2622
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
2623
- link: "text-primary underline-offset-4 hover:underline"
2624
- },
2625
- size: {
2626
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
2627
- xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
2628
- sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
2629
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
2630
- icon: "size-9",
2631
- "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
2632
- "icon-sm": "size-8",
2633
- "icon-lg": "size-10"
2634
- }
2635
- },
2636
- defaultVariants: {
2637
- variant: "default",
2638
- size: "default"
2639
- }
2640
- }
2641
- );
2642
- function Button({
2643
- className,
2644
- variant = "default",
2645
- size = "default",
2646
- render,
2647
- ...props
2648
- }) {
2649
- return useRender2({
2650
- defaultTagName: "button",
2651
- render,
2652
- props: {
2653
- "data-slot": "button",
2654
- "data-variant": variant,
2655
- "data-size": size,
2656
- className: cn(buttonVariants({ variant, size, className })),
2657
- ...props
2658
- }
2659
- });
2660
- }
2661
-
2662
- // src/interactive/ReportShortcutsHelp.tsx
2663
- import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2737
+ import { useEffect as useEffect5, useRef as useRef2 } from "react";
2738
+ import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2664
2739
  var SHORTCUTS = [
2665
2740
  { keys: "/", description: "Focus search" },
2666
2741
  { keys: "f", description: "Jump to next failure" },
@@ -2672,20 +2747,20 @@ var SHORTCUTS = [
2672
2747
  ];
2673
2748
  function Keys({ keys }) {
2674
2749
  const parts = keys.split(" ");
2675
- return /* @__PURE__ */ jsx47("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs32("span", { className: "inline-flex items-center gap-1", children: [
2676
- i > 0 ? /* @__PURE__ */ jsx47("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2677
- /* @__PURE__ */ jsx47("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2750
+ return /* @__PURE__ */ jsx48("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs33("span", { className: "inline-flex items-center gap-1", children: [
2751
+ i > 0 ? /* @__PURE__ */ jsx48("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2752
+ /* @__PURE__ */ jsx48("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2678
2753
  ] }, k)) });
2679
2754
  }
2680
2755
  function ReportShortcutsHelp({ open, onClose }) {
2681
- const dialogRef = useRef(null);
2682
- useEffect4(() => {
2756
+ const dialogRef = useRef2(null);
2757
+ useEffect5(() => {
2683
2758
  const dialog = dialogRef.current;
2684
2759
  if (!dialog) return;
2685
2760
  if (open && !dialog.open) dialog.showModal();
2686
2761
  else if (!open && dialog.open) dialog.close();
2687
2762
  }, [open]);
2688
- return /* @__PURE__ */ jsxs32(
2763
+ return /* @__PURE__ */ jsxs33(
2689
2764
  "dialog",
2690
2765
  {
2691
2766
  ref: dialogRef,
@@ -2693,20 +2768,20 @@ function ReportShortcutsHelp({ open, onClose }) {
2693
2768
  "aria-label": "Keyboard shortcuts",
2694
2769
  onClose,
2695
2770
  children: [
2696
- /* @__PURE__ */ jsx47("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2697
- /* @__PURE__ */ jsx47("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs32("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2698
- /* @__PURE__ */ jsx47("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx47(Keys, { keys: s.keys }) }),
2699
- /* @__PURE__ */ jsx47("dd", { className: "text-sm text-muted-foreground", children: s.description })
2771
+ /* @__PURE__ */ jsx48("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2772
+ /* @__PURE__ */ jsx48("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs33("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2773
+ /* @__PURE__ */ jsx48("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx48(Keys, { keys: s.keys }) }),
2774
+ /* @__PURE__ */ jsx48("dd", { className: "text-sm text-muted-foreground", children: s.description })
2700
2775
  ] }, s.keys)) }),
2701
- /* @__PURE__ */ jsx47("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx47(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2776
+ /* @__PURE__ */ jsx48("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx48(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2702
2777
  ]
2703
2778
  }
2704
2779
  );
2705
2780
  }
2706
2781
 
2707
2782
  // src/interactive/ReportToc.tsx
2708
- import { useEffect as useEffect5, useMemo as useMemo2, useState as useState6 } from "react";
2709
- import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2783
+ import { useEffect as useEffect6, useMemo as useMemo2, useState as useState7 } from "react";
2784
+ import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2710
2785
  var DOT = {
2711
2786
  passed: "bg-pass",
2712
2787
  failed: "bg-fail",
@@ -2715,12 +2790,12 @@ var DOT = {
2715
2790
  };
2716
2791
  function TocContent({ onNavigate }) {
2717
2792
  const report = useReport();
2718
- const [activeId, setActiveId] = useState6(null);
2793
+ const [activeId, setActiveId] = useState7(null);
2719
2794
  const scenarioIds = useMemo2(
2720
2795
  () => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
2721
2796
  [report]
2722
2797
  );
2723
- useEffect5(() => {
2798
+ useEffect6(() => {
2724
2799
  if (typeof IntersectionObserver === "undefined") return;
2725
2800
  const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
2726
2801
  if (els.length === 0) return;
@@ -2735,11 +2810,11 @@ function TocContent({ onNavigate }) {
2735
2810
  return () => observer.disconnect();
2736
2811
  }, [scenarioIds]);
2737
2812
  if (report.features.length === 0) return null;
2738
- return /* @__PURE__ */ jsx48("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs33("li", { children: [
2739
- /* @__PURE__ */ jsx48("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2740
- /* @__PURE__ */ jsx48("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2813
+ return /* @__PURE__ */ jsx49("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs34("li", { children: [
2814
+ /* @__PURE__ */ jsx49("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2815
+ /* @__PURE__ */ jsx49("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2741
2816
  const active = activeId === scenario.id;
2742
- return /* @__PURE__ */ jsx48("li", { children: /* @__PURE__ */ jsxs33(
2817
+ return /* @__PURE__ */ jsx49("li", { children: /* @__PURE__ */ jsxs34(
2743
2818
  "a",
2744
2819
  {
2745
2820
  href: `#${scenario.id}`,
@@ -2754,14 +2829,14 @@ function TocContent({ onNavigate }) {
2754
2829
  active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
2755
2830
  ),
2756
2831
  children: [
2757
- /* @__PURE__ */ jsx48(
2832
+ /* @__PURE__ */ jsx49(
2758
2833
  "span",
2759
2834
  {
2760
2835
  "aria-hidden": true,
2761
2836
  className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
2762
2837
  }
2763
2838
  ),
2764
- /* @__PURE__ */ jsx48("span", { className: "break-words", children: scenario.title })
2839
+ /* @__PURE__ */ jsx49("span", { className: "break-words", children: scenario.title })
2765
2840
  ]
2766
2841
  }
2767
2842
  ) }, scenario.id);
@@ -2771,48 +2846,48 @@ function TocContent({ onNavigate }) {
2771
2846
  function ReportToc() {
2772
2847
  const report = useReport();
2773
2848
  if (report.features.length === 0) return null;
2774
- return /* @__PURE__ */ jsxs33(
2849
+ return /* @__PURE__ */ jsxs34(
2775
2850
  "nav",
2776
2851
  {
2777
2852
  "aria-label": "Table of contents",
2778
2853
  className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
2779
2854
  children: [
2780
- /* @__PURE__ */ jsx48("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2781
- /* @__PURE__ */ jsx48(TocContent, {})
2855
+ /* @__PURE__ */ jsx49("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2856
+ /* @__PURE__ */ jsx49(TocContent, {})
2782
2857
  ]
2783
2858
  }
2784
2859
  );
2785
2860
  }
2786
2861
 
2787
2862
  // src/interactive/ReportTocDrawer.tsx
2788
- import { useState as useState7 } from "react";
2863
+ import { useState as useState8 } from "react";
2789
2864
  import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
2790
2865
  import { ListIcon, XIcon } from "lucide-react";
2791
- import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2866
+ import { jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
2792
2867
  function ReportTocDrawer() {
2793
2868
  const report = useReport();
2794
- const [open, setOpen] = useState7(false);
2869
+ const [open, setOpen] = useState8(false);
2795
2870
  if (report.features.length === 0) return null;
2796
- return /* @__PURE__ */ jsxs34(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
2797
- /* @__PURE__ */ jsxs34(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2798
- /* @__PURE__ */ jsx49(ListIcon, { "aria-hidden": true }),
2871
+ return /* @__PURE__ */ jsxs35(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
2872
+ /* @__PURE__ */ jsxs35(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2873
+ /* @__PURE__ */ jsx50(ListIcon, { "aria-hidden": true }),
2799
2874
  " Contents"
2800
2875
  ] }),
2801
- /* @__PURE__ */ jsxs34(DialogPrimitive.Portal, { children: [
2802
- /* @__PURE__ */ jsx49(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2803
- /* @__PURE__ */ jsxs34(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2804
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center justify-between", children: [
2805
- /* @__PURE__ */ jsx49(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2806
- /* @__PURE__ */ jsx49(
2876
+ /* @__PURE__ */ jsxs35(DialogPrimitive.Portal, { children: [
2877
+ /* @__PURE__ */ jsx50(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2878
+ /* @__PURE__ */ jsxs35(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2879
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center justify-between", children: [
2880
+ /* @__PURE__ */ jsx50(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2881
+ /* @__PURE__ */ jsx50(
2807
2882
  DialogPrimitive.Close,
2808
2883
  {
2809
2884
  "aria-label": "Close contents",
2810
2885
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
2811
- children: /* @__PURE__ */ jsx49(XIcon, { "aria-hidden": true })
2886
+ children: /* @__PURE__ */ jsx50(XIcon, { "aria-hidden": true })
2812
2887
  }
2813
2888
  )
2814
2889
  ] }),
2815
- /* @__PURE__ */ jsx49(TocContent, { onNavigate: () => setOpen(false) })
2890
+ /* @__PURE__ */ jsx50(TocContent, { onNavigate: () => setOpen(false) })
2816
2891
  ] })
2817
2892
  ] })
2818
2893
  ] });
@@ -2846,10 +2921,10 @@ function failuresFirst(report) {
2846
2921
  }
2847
2922
 
2848
2923
  // src/interactive/use-deep-link-scroll.ts
2849
- import { useEffect as useEffect6, useRef as useRef2 } from "react";
2924
+ import { useEffect as useEffect7, useRef as useRef3 } from "react";
2850
2925
  function useDeepLinkScroll() {
2851
- const lastAnchor = useRef2(null);
2852
- useEffect6(() => {
2926
+ const lastAnchor = useRef3(null);
2927
+ useEffect7(() => {
2853
2928
  function scrollToHash() {
2854
2929
  const { anchor } = splitHash(window.location.hash);
2855
2930
  if (!anchor || anchor === lastAnchor.current) return;
@@ -2865,7 +2940,7 @@ function useDeepLinkScroll() {
2865
2940
  }
2866
2941
 
2867
2942
  // src/interactive/use-keyboard-shortcuts.ts
2868
- import { useEffect as useEffect7, useRef as useRef3 } from "react";
2943
+ import { useEffect as useEffect8, useRef as useRef4 } from "react";
2869
2944
  function isEditableTarget(target) {
2870
2945
  if (!(target instanceof HTMLElement)) return false;
2871
2946
  const tag = target.tagName;
@@ -2874,9 +2949,9 @@ function isEditableTarget(target) {
2874
2949
  return false;
2875
2950
  }
2876
2951
  function useKeyboardShortcuts(handlers) {
2877
- const ref = useRef3(handlers);
2952
+ const ref = useRef4(handlers);
2878
2953
  ref.current = handlers;
2879
- useEffect7(() => {
2954
+ useEffect8(() => {
2880
2955
  function onKeyDown(e) {
2881
2956
  const h = ref.current;
2882
2957
  if (e.key === "Escape") {
@@ -2920,7 +2995,7 @@ function useKeyboardShortcuts(handlers) {
2920
2995
  }
2921
2996
 
2922
2997
  // src/interactive/use-theme.ts
2923
- import { useCallback as useCallback3, useEffect as useEffect8, useState as useState8 } from "react";
2998
+ import { useCallback as useCallback3, useEffect as useEffect9, useState as useState9 } from "react";
2924
2999
  var KEY2 = "es-theme";
2925
3000
  function systemDark() {
2926
3001
  return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
@@ -2941,13 +3016,13 @@ function initialPref() {
2941
3016
  return "system";
2942
3017
  }
2943
3018
  function useTheme() {
2944
- const [pref, setPrefState] = useState8("system");
2945
- useEffect8(() => {
3019
+ const [pref, setPrefState] = useState9("system");
3020
+ useEffect9(() => {
2946
3021
  const p = initialPref();
2947
3022
  setPrefState(p);
2948
3023
  applyTheme(p);
2949
3024
  }, []);
2950
- useEffect8(() => {
3025
+ useEffect9(() => {
2951
3026
  if (typeof matchMedia === "undefined") return;
2952
3027
  const mq = matchMedia("(prefers-color-scheme: dark)");
2953
3028
  const onChange = () => {
@@ -2968,19 +3043,19 @@ function useTheme() {
2968
3043
  }
2969
3044
 
2970
3045
  // src/interactive/use-url-state.ts
2971
- import { useCallback as useCallback4, useEffect as useEffect9, useRef as useRef4, useState as useState9 } from "react";
3046
+ import { useCallback as useCallback4, useEffect as useEffect10, useRef as useRef5, useState as useState10 } from "react";
2972
3047
  var WRITE_DELAY_MS = 250;
2973
3048
  function useUrlState() {
2974
- const [state, setState] = useState9(DEFAULT_URL_STATE);
2975
- const ready = useRef4(false);
2976
- useEffect9(() => {
3049
+ const [state, setState] = useState10(DEFAULT_URL_STATE);
3050
+ const ready = useRef5(false);
3051
+ useEffect10(() => {
2977
3052
  const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
2978
3053
  read();
2979
3054
  ready.current = true;
2980
3055
  window.addEventListener("hashchange", read);
2981
3056
  return () => window.removeEventListener("hashchange", read);
2982
3057
  }, []);
2983
- useEffect9(() => {
3058
+ useEffect10(() => {
2984
3059
  if (!ready.current) return;
2985
3060
  const timer = setTimeout(
2986
3061
  () => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
@@ -3216,12 +3291,12 @@ function reportTools(deps) {
3216
3291
  }
3217
3292
 
3218
3293
  // src/interactive/ReportInteractive.tsx
3219
- import { Fragment as Fragment15, jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
3294
+ import { Fragment as Fragment16, jsx as jsx51, jsxs as jsxs36 } from "react/jsx-runtime";
3220
3295
  function ReportInteractive(props) {
3221
3296
  const { report, className, title, dataTheme } = props;
3222
3297
  const result = unwrapReport(report);
3223
3298
  if (!result.ok) {
3224
- return /* @__PURE__ */ jsx50(
3299
+ return /* @__PURE__ */ jsx51(
3225
3300
  ReportErrorShell,
3226
3301
  {
3227
3302
  error: result.error,
@@ -3231,7 +3306,7 @@ function ReportInteractive(props) {
3231
3306
  }
3232
3307
  );
3233
3308
  }
3234
- return /* @__PURE__ */ jsx50(ReportInteractiveView, { ...props, report: result.data });
3309
+ return /* @__PURE__ */ jsx51(ReportInteractiveView, { ...props, report: result.data });
3235
3310
  }
3236
3311
  var THEME_OPTIONS = [
3237
3312
  { value: "light", label: "Light", Icon: Sun },
@@ -3242,7 +3317,7 @@ function ThemeSegment({
3242
3317
  pref,
3243
3318
  onPref
3244
3319
  }) {
3245
- return /* @__PURE__ */ jsx50(
3320
+ return /* @__PURE__ */ jsx51(
3246
3321
  ToggleGroup,
3247
3322
  {
3248
3323
  size: "sm",
@@ -3252,14 +3327,14 @@ function ThemeSegment({
3252
3327
  if (next) onPref(next);
3253
3328
  },
3254
3329
  "aria-label": "Color theme",
3255
- children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx50(
3330
+ children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx51(
3256
3331
  ToggleGroupItem,
3257
3332
  {
3258
3333
  value,
3259
3334
  "aria-label": label,
3260
3335
  title: label,
3261
3336
  className: "px-2",
3262
- children: /* @__PURE__ */ jsx50(Icon, {})
3337
+ children: /* @__PURE__ */ jsx51(Icon, {})
3263
3338
  },
3264
3339
  value
3265
3340
  ))
@@ -3276,7 +3351,9 @@ function ReportInteractiveView({
3276
3351
  hideHeader = false,
3277
3352
  hideToc = false,
3278
3353
  staleAfterDays = 7,
3279
- scenarioHistory
3354
+ scenarioHistory,
3355
+ share = false,
3356
+ shareCommand
3280
3357
  }) {
3281
3358
  const [urlState, setUrlState] = useUrlState();
3282
3359
  const { query, status: statusFilter, tags: activeTags, detail } = urlState;
@@ -3292,9 +3369,9 @@ function ReportInteractiveView({
3292
3369
  (next) => setUrlState({ detail: next }),
3293
3370
  [setUrlState]
3294
3371
  );
3295
- const [helpOpen, setHelpOpen] = useState10(false);
3372
+ const [helpOpen, setHelpOpen] = useState11(false);
3296
3373
  const { pref: themePref, setPref: setThemePref } = useTheme();
3297
- const searchRef = useRef5(null);
3374
+ const searchRef = useRef6(null);
3298
3375
  const expandId = useId2();
3299
3376
  const docsId = useId2();
3300
3377
  const deferredQuery = useDeferredValue(query);
@@ -3334,8 +3411,8 @@ function ReportInteractiveView({
3334
3411
  }),
3335
3412
  [activeTags, setUrlState]
3336
3413
  );
3337
- const [toast, setToast] = useState10(null);
3338
- const toastTimer = useRef5(null);
3414
+ const [toast, setToast] = useState11(null);
3415
+ const toastTimer = useRef6(null);
3339
3416
  const showToast = useCallback5((msg) => {
3340
3417
  setToast(msg);
3341
3418
  if (toastTimer.current) clearTimeout(toastTimer.current);
@@ -3364,7 +3441,7 @@ function ReportInteractiveView({
3364
3441
  () => copy(failuresToPrompt(failedScenarios(filtered)), "Failures copied"),
3365
3442
  [copy, filtered]
3366
3443
  );
3367
- const failureIndexRef = useRef5(0);
3444
+ const failureIndexRef = useRef6(0);
3368
3445
  const allCollapsibleIds = useMemo3(
3369
3446
  () => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
3370
3447
  [report]
@@ -3381,7 +3458,7 @@ function ReportInteractiveView({
3381
3458
  () => collapse.collapseAll(allCollapsibleIds),
3382
3459
  [collapse, allCollapsibleIds]
3383
3460
  );
3384
- const [expandedAll, setExpandedAll] = useState10(
3461
+ const [expandedAll, setExpandedAll] = useState11(
3385
3462
  () => report.summary.failed === 0
3386
3463
  );
3387
3464
  const setExpanded = useCallback5(
@@ -3392,7 +3469,7 @@ function ReportInteractiveView({
3392
3469
  },
3393
3470
  [collapse, collapseAll]
3394
3471
  );
3395
- const [agentFilter, setAgentFilter] = useState10(null);
3472
+ const [agentFilter, setAgentFilter] = useState11(null);
3396
3473
  useTools(
3397
3474
  reportTools({
3398
3475
  report,
@@ -3439,13 +3516,13 @@ function ReportInteractiveView({
3439
3516
  const totalScenarios = report.summary.total;
3440
3517
  const matchedScenarios = filtered.summary.total;
3441
3518
  const showToc = !hideToc && totalScenarios > 3;
3442
- return /* @__PURE__ */ jsx50(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ jsx50(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx50(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx50(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ jsx50(
3519
+ return /* @__PURE__ */ jsx51(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ jsx51(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx51(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx51(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ jsx51(
3443
3520
  ReportRoot,
3444
3521
  {
3445
3522
  report: filtered,
3446
3523
  customRenderers,
3447
3524
  renderers,
3448
- children: /* @__PURE__ */ jsxs35(
3525
+ children: /* @__PURE__ */ jsxs36(
3449
3526
  "main",
3450
3527
  {
3451
3528
  className: cn("es-report", "es-report-interactive", className),
@@ -3454,8 +3531,8 @@ function ReportInteractiveView({
3454
3531
  "data-theme": dataTheme,
3455
3532
  "data-detail-level": detail,
3456
3533
  children: [
3457
- /* @__PURE__ */ jsxs35("header", { className: "es-report-header", children: [
3458
- /* @__PURE__ */ jsxs35(
3534
+ /* @__PURE__ */ jsxs36("header", { className: "es-report-header", children: [
3535
+ /* @__PURE__ */ jsxs36(
3459
3536
  "div",
3460
3537
  {
3461
3538
  "data-es-navbar": true,
@@ -3464,9 +3541,9 @@ function ReportInteractiveView({
3464
3541
  hideHeader ? "justify-end" : "justify-between"
3465
3542
  ),
3466
3543
  children: [
3467
- hideHeader ? null : /* @__PURE__ */ jsx50("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3468
- /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3469
- /* @__PURE__ */ jsx50(
3544
+ hideHeader ? null : /* @__PURE__ */ jsx51("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3545
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
3546
+ /* @__PURE__ */ jsx51(
3470
3547
  ReportSearch,
3471
3548
  {
3472
3549
  ref: searchRef,
@@ -3476,16 +3553,17 @@ function ReportInteractiveView({
3476
3553
  totalCount: totalScenarios
3477
3554
  }
3478
3555
  ),
3479
- /* @__PURE__ */ jsx50(ThemeSegment, { pref: themePref, onPref: setThemePref })
3556
+ share ? /* @__PURE__ */ jsx51(ReportShare, { command: shareCommand, onCopy: copy }) : null,
3557
+ /* @__PURE__ */ jsx51(ThemeSegment, { pref: themePref, onPref: setThemePref })
3480
3558
  ] })
3481
3559
  ]
3482
3560
  }
3483
3561
  ),
3484
- hideHeader ? null : /* @__PURE__ */ jsxs35(Fragment15, { children: [
3485
- /* @__PURE__ */ jsx50(ReportSummary, {}),
3486
- /* @__PURE__ */ jsx50(ReportMeta, {})
3562
+ hideHeader ? null : /* @__PURE__ */ jsxs36(Fragment16, { children: [
3563
+ /* @__PURE__ */ jsx51(ReportSummary, {}),
3564
+ /* @__PURE__ */ jsx51(ReportMeta, {})
3487
3565
  ] }),
3488
- /* @__PURE__ */ jsx50(
3566
+ /* @__PURE__ */ jsx51(
3489
3567
  ReportFreshness,
3490
3568
  {
3491
3569
  lastRunMs: reportLastRunMs(report),
@@ -3493,15 +3571,15 @@ function ReportInteractiveView({
3493
3571
  staleAfterDays
3494
3572
  }
3495
3573
  ),
3496
- /* @__PURE__ */ jsx50(
3574
+ /* @__PURE__ */ jsx51(
3497
3575
  ReportLastRunDelta,
3498
3576
  {
3499
3577
  history: scenarioHistory,
3500
3578
  report
3501
3579
  }
3502
3580
  ),
3503
- /* @__PURE__ */ jsx50(ReportSinceLastVisit, { report }),
3504
- /* @__PURE__ */ jsx50(
3581
+ /* @__PURE__ */ jsx51(ReportSinceLastVisit, { report }),
3582
+ /* @__PURE__ */ jsx51(
3505
3583
  ReportFilters,
3506
3584
  {
3507
3585
  statuses: statusOptions,
@@ -3512,10 +3590,10 @@ function ReportInteractiveView({
3512
3590
  onToggleTag: toggleTag
3513
3591
  }
3514
3592
  ),
3515
- /* @__PURE__ */ jsxs35("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3516
- showToc ? /* @__PURE__ */ jsx50(ReportTocDrawer, {}) : null,
3517
- /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3518
- /* @__PURE__ */ jsx50(
3593
+ /* @__PURE__ */ jsxs36("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3594
+ showToc ? /* @__PURE__ */ jsx51(ReportTocDrawer, {}) : null,
3595
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
3596
+ /* @__PURE__ */ jsx51(
3519
3597
  Switch,
3520
3598
  {
3521
3599
  id: expandId,
@@ -3523,7 +3601,7 @@ function ReportInteractiveView({
3523
3601
  onCheckedChange: setExpanded
3524
3602
  }
3525
3603
  ),
3526
- /* @__PURE__ */ jsx50(
3604
+ /* @__PURE__ */ jsx51(
3527
3605
  "label",
3528
3606
  {
3529
3607
  htmlFor: expandId,
@@ -3532,8 +3610,8 @@ function ReportInteractiveView({
3532
3610
  }
3533
3611
  )
3534
3612
  ] }),
3535
- /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3536
- /* @__PURE__ */ jsx50(
3613
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
3614
+ /* @__PURE__ */ jsx51(
3537
3615
  Switch,
3538
3616
  {
3539
3617
  id: docsId,
@@ -3541,7 +3619,7 @@ function ReportInteractiveView({
3541
3619
  onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
3542
3620
  }
3543
3621
  ),
3544
- /* @__PURE__ */ jsx50(
3622
+ /* @__PURE__ */ jsx51(
3545
3623
  "label",
3546
3624
  {
3547
3625
  htmlFor: docsId,
@@ -3552,7 +3630,7 @@ function ReportInteractiveView({
3552
3630
  ] })
3553
3631
  ] })
3554
3632
  ] }),
3555
- showAgentFilter ? /* @__PURE__ */ jsx50(
3633
+ showAgentFilter ? /* @__PURE__ */ jsx51(
3556
3634
  ReportAgentFilterNotice,
3557
3635
  {
3558
3636
  applied: agentFilter,
@@ -3560,17 +3638,17 @@ function ReportInteractiveView({
3560
3638
  onDismiss: () => setAgentFilter(null)
3561
3639
  }
3562
3640
  ) : null,
3563
- /* @__PURE__ */ jsx50(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
3564
- hasContent ? showToc ? /* @__PURE__ */ jsxs35("div", { className: "flex gap-6", children: [
3565
- /* @__PURE__ */ jsx50(ReportToc, {}),
3566
- /* @__PURE__ */ jsx50("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx50(ReportFeatureList, {}) })
3567
- ] }) : /* @__PURE__ */ jsx50("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx50(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx50(
3641
+ /* @__PURE__ */ jsx51(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
3642
+ hasContent ? showToc ? /* @__PURE__ */ jsxs36("div", { className: "flex gap-6", children: [
3643
+ /* @__PURE__ */ jsx51(ReportToc, {}),
3644
+ /* @__PURE__ */ jsx51("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx51(ReportFeatureList, {}) })
3645
+ ] }) : /* @__PURE__ */ jsx51("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx51(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx51(
3568
3646
  ReportEmpty,
3569
3647
  {
3570
3648
  message: query ? "No scenarios match the search." : void 0
3571
3649
  }
3572
3650
  ),
3573
- /* @__PURE__ */ jsx50(
3651
+ /* @__PURE__ */ jsx51(
3574
3652
  "button",
3575
3653
  {
3576
3654
  type: "button",
@@ -3581,14 +3659,14 @@ function ReportInteractiveView({
3581
3659
  children: "?"
3582
3660
  }
3583
3661
  ),
3584
- /* @__PURE__ */ jsx50(
3662
+ /* @__PURE__ */ jsx51(
3585
3663
  ReportShortcutsHelp,
3586
3664
  {
3587
3665
  open: helpOpen,
3588
3666
  onClose: () => setHelpOpen(false)
3589
3667
  }
3590
3668
  ),
3591
- toast ? /* @__PURE__ */ jsx50(
3669
+ toast ? /* @__PURE__ */ jsx51(
3592
3670
  "div",
3593
3671
  {
3594
3672
  role: "status",
@@ -3608,11 +3686,11 @@ function ReportInteractiveView({
3608
3686
  import { useMemo as useMemo4 } from "react";
3609
3687
 
3610
3688
  // src/interactive/island-renderers.tsx
3611
- import { createElement, useEffect as useEffect11, useState as useState12 } from "react";
3689
+ import { createElement, useEffect as useEffect12, useState as useState13 } from "react";
3612
3690
 
3613
3691
  // src/components/doc/MermaidView.tsx
3614
- import { useEffect as useEffect10, useRef as useRef6, useState as useState11 } from "react";
3615
- import { Fragment as Fragment16, jsx as jsx51, jsxs as jsxs36 } from "react/jsx-runtime";
3692
+ import { useEffect as useEffect11, useRef as useRef7, useState as useState12 } from "react";
3693
+ import { Fragment as Fragment17, jsx as jsx52, jsxs as jsxs37 } from "react/jsx-runtime";
3616
3694
  function prefersDark(el) {
3617
3695
  const themed = el?.closest("[data-theme]");
3618
3696
  if (themed?.dataset.theme === "dark") return true;
@@ -3620,10 +3698,10 @@ function prefersDark(el) {
3620
3698
  return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
3621
3699
  }
3622
3700
  function MermaidView({ entry, load }) {
3623
- const ref = useRef6(null);
3624
- const [svg, setSvg] = useState11(null);
3625
- const [error, setError] = useState11(null);
3626
- useEffect10(() => {
3701
+ const ref = useRef7(null);
3702
+ const [svg, setSvg] = useState12(null);
3703
+ const [error, setError] = useState12(null);
3704
+ useEffect11(() => {
3627
3705
  let cancelled = false;
3628
3706
  const draw = async () => {
3629
3707
  let mermaid;
@@ -3666,9 +3744,9 @@ function MermaidView({ entry, load }) {
3666
3744
  };
3667
3745
  }, [entry.code, load]);
3668
3746
  if (svg) {
3669
- return /* @__PURE__ */ jsxs36("figure", { ref, className: "my-3", children: [
3670
- entry.title ? /* @__PURE__ */ jsx51("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3671
- /* @__PURE__ */ jsx51(
3747
+ return /* @__PURE__ */ jsxs37("figure", { ref, className: "my-3", children: [
3748
+ entry.title ? /* @__PURE__ */ jsx52("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3749
+ /* @__PURE__ */ jsx52(
3672
3750
  "div",
3673
3751
  {
3674
3752
  role: "img",
@@ -3679,8 +3757,8 @@ function MermaidView({ entry, load }) {
3679
3757
  )
3680
3758
  ] });
3681
3759
  }
3682
- return /* @__PURE__ */ jsxs36(Fragment16, { children: [
3683
- error ? /* @__PURE__ */ jsxs36(
3760
+ return /* @__PURE__ */ jsxs37(Fragment17, { children: [
3761
+ error ? /* @__PURE__ */ jsxs37(
3684
3762
  "p",
3685
3763
  {
3686
3764
  role: "alert",
@@ -3692,12 +3770,12 @@ function MermaidView({ entry, load }) {
3692
3770
  ]
3693
3771
  }
3694
3772
  ) : null,
3695
- /* @__PURE__ */ jsx51(MermaidSource, { entry, ref })
3773
+ /* @__PURE__ */ jsx52(MermaidSource, { entry, ref })
3696
3774
  ] });
3697
3775
  }
3698
3776
 
3699
3777
  // src/interactive/island-renderers.tsx
3700
- import { jsx as jsx52 } from "react/jsx-runtime";
3778
+ import { jsx as jsx53 } from "react/jsx-runtime";
3701
3779
  var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
3702
3780
  var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
3703
3781
  function cachedCdnModule(url) {
@@ -3714,8 +3792,8 @@ function cachedCdnModule(url) {
3714
3792
  var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
3715
3793
  var loadHljs = cachedCdnModule(HLJS_ESM);
3716
3794
  function CdnHighlightedCode({ entry }) {
3717
- const [html, setHtml] = useState12(null);
3718
- useEffect11(() => {
3795
+ const [html, setHtml] = useState13(null);
3796
+ useEffect12(() => {
3719
3797
  let cancelled = false;
3720
3798
  void (async () => {
3721
3799
  try {
@@ -3731,13 +3809,13 @@ function CdnHighlightedCode({ entry }) {
3731
3809
  cancelled = true;
3732
3810
  };
3733
3811
  }, [entry.content, entry.lang]);
3734
- return /* @__PURE__ */ jsx52(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx52(
3812
+ return /* @__PURE__ */ jsx53(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx53(
3735
3813
  "code",
3736
3814
  {
3737
3815
  className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
3738
3816
  dangerouslySetInnerHTML: { __html: html }
3739
3817
  }
3740
- ) : /* @__PURE__ */ jsx52("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3818
+ ) : /* @__PURE__ */ jsx53("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3741
3819
  }
3742
3820
  function buildIslandRenderers(opts) {
3743
3821
  const renderers = {};
@@ -3751,7 +3829,7 @@ function buildIslandRenderers(opts) {
3751
3829
  }
3752
3830
 
3753
3831
  // src/interactive/ReportInteractiveIsland.tsx
3754
- import { jsx as jsx53 } from "react/jsx-runtime";
3832
+ import { jsx as jsx54 } from "react/jsx-runtime";
3755
3833
  function ReportInteractiveIsland({
3756
3834
  report,
3757
3835
  title,
@@ -3765,7 +3843,7 @@ function ReportInteractiveIsland({
3765
3843
  () => buildIslandRenderers({ syntaxHighlighting, mermaid }),
3766
3844
  [syntaxHighlighting, mermaid]
3767
3845
  );
3768
- return /* @__PURE__ */ jsx53(
3846
+ return /* @__PURE__ */ jsx54(
3769
3847
  ReportInteractive,
3770
3848
  {
3771
3849
  report,