executable-stories-react 0.6.0 → 0.8.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.cjs CHANGED
@@ -59,6 +59,7 @@ __export(src_exports, {
59
59
  ReportSchemaError: () => ReportSchemaError,
60
60
  ReportStepItem: () => ReportStepItem,
61
61
  ReportSteps: () => ReportSteps,
62
+ ReportStoryboard: () => ReportStoryboard,
62
63
  ReportSummary: () => ReportSummary,
63
64
  ReportSummaryView: () => ReportSummaryView,
64
65
  ReportTrace: () => ReportTrace,
@@ -299,7 +300,7 @@ function DocLink({ entry }) {
299
300
  // src/components/doc/DocSection.tsx
300
301
  var import_marked = require("marked");
301
302
 
302
- // src/lib/url.ts
303
+ // ../executable-stories-core/dist/utils/url.js
303
304
  function safeUrl(value) {
304
305
  if (!value) return void 0;
305
306
  const trimmed = value.trim();
@@ -457,17 +458,29 @@ function DocHtml({ entry }) {
457
458
  ] });
458
459
  }
459
460
 
460
- // src/components/doc/DocCustom.tsx
461
+ // src/components/doc/DocState.tsx
461
462
  var import_jsx_runtime13 = require("react/jsx-runtime");
463
+ function DocState({ entry }) {
464
+ let json;
465
+ try {
466
+ json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);
467
+ } catch {
468
+ json = String(entry.value);
469
+ }
470
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
471
+ }
472
+
473
+ // src/components/doc/DocCustom.tsx
474
+ var import_jsx_runtime14 = require("react/jsx-runtime");
462
475
  function DocCustom({ entry }) {
463
476
  const renderers = useCustomRenderers();
464
477
  const renderer = renderers[entry.type];
465
478
  if (renderer) {
466
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: renderer(entry) });
479
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: renderer(entry) });
467
480
  }
468
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
469
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
470
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
481
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
482
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
483
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
471
484
  ] });
472
485
  }
473
486
  function safeStringify(value) {
@@ -479,45 +492,47 @@ function safeStringify(value) {
479
492
  }
480
493
 
481
494
  // src/components/doc/DocEntry.tsx
482
- var import_jsx_runtime14 = require("react/jsx-runtime");
495
+ var import_jsx_runtime15 = require("react/jsx-runtime");
483
496
  function DocEntry({ entry }) {
484
497
  switch (entry.kind) {
485
498
  case "note":
486
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocNote, { entry });
499
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocNote, { entry });
487
500
  case "tag":
488
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocTag, { entry });
501
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTag, { entry });
489
502
  case "kv":
490
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocKv, { entry });
503
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocKv, { entry });
491
504
  case "code":
492
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocCode, { entry });
505
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCode, { entry });
493
506
  case "table":
494
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocTable, { entry });
507
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTable, { entry });
495
508
  case "link":
496
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocLink, { entry });
509
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocLink, { entry });
497
510
  case "section":
498
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocSection, { entry });
511
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocSection, { entry });
499
512
  case "mermaid":
500
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocMermaid, { entry });
513
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocMermaid, { entry });
501
514
  case "screenshot":
502
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocScreenshot, { entry });
515
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocScreenshot, { entry });
503
516
  case "video":
504
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocVideo, { entry });
517
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocVideo, { entry });
505
518
  case "html":
506
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocHtml, { entry });
519
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocHtml, { entry });
520
+ case "state":
521
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocState, { entry });
507
522
  case "custom":
508
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocCustom, { entry });
523
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCustom, { entry });
509
524
  }
510
525
  }
511
526
 
512
527
  // src/components/ReportDocEntries.tsx
513
- var import_jsx_runtime15 = require("react/jsx-runtime");
528
+ var import_jsx_runtime16 = require("react/jsx-runtime");
514
529
  function ReportDocEntries({ entries }) {
515
530
  if (entries.length === 0) return null;
516
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocEntry, { entry }, i)) });
531
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocEntry, { entry }, i)) });
517
532
  }
518
533
 
519
534
  // src/lib/step-params.tsx
520
- var import_jsx_runtime16 = require("react/jsx-runtime");
535
+ var import_jsx_runtime17 = require("react/jsx-runtime");
521
536
  var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
522
537
  function highlightStepParams(text) {
523
538
  const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
@@ -529,7 +544,7 @@ function highlightStepParams(text) {
529
544
  const end = start + match[0].length;
530
545
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
531
546
  nodes.push(
532
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
547
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
533
548
  );
534
549
  lastIndex = end;
535
550
  });
@@ -538,7 +553,7 @@ function highlightStepParams(text) {
538
553
  }
539
554
 
540
555
  // src/components/ReportSteps.tsx
541
- var import_jsx_runtime17 = require("react/jsx-runtime");
556
+ var import_jsx_runtime18 = require("react/jsx-runtime");
542
557
  var STEP_GLYPH = {
543
558
  passed: "\u2713",
544
559
  failed: "\u2717",
@@ -553,21 +568,21 @@ var STEP_GLYPH_COLOR = {
553
568
  };
554
569
  function ReportSteps({ scenario }) {
555
570
  if (scenario.steps.length === 0) return null;
556
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReportStepItem, { step }, step.id)) });
571
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportStepItem, { step }, step.id)) });
557
572
  }
558
573
  function ReportStepItem({ step }) {
559
574
  const kw = step.keyword.toLowerCase();
560
575
  const continuation = kw === "and" || kw === "but";
561
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
576
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
562
577
  "li",
563
578
  {
564
579
  id: step.id,
565
580
  "data-status": step.status,
566
581
  className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
567
582
  children: [
568
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-baseline gap-2", children: [
569
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
570
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
583
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-baseline gap-2", children: [
584
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
585
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
571
586
  "span",
572
587
  {
573
588
  className: cn(
@@ -577,10 +592,10 @@ function ReportStepItem({ step }) {
577
592
  children: step.keyword
578
593
  }
579
594
  ),
580
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
581
- step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
595
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
596
+ step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
582
597
  ] }),
583
- step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
598
+ step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
584
599
  "pre",
585
600
  {
586
601
  role: "alert",
@@ -588,24 +603,255 @@ function ReportStepItem({ step }) {
588
603
  children: step.errorMessage
589
604
  }
590
605
  ) : null,
591
- step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
606
+ step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
592
607
  ]
593
608
  }
594
609
  );
595
610
  }
596
611
 
612
+ // ../executable-stories-core/dist/state-diff.js
613
+ var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
614
+ function deepEqual(a, b) {
615
+ if (Object.is(a, b)) return true;
616
+ if (Array.isArray(a) && Array.isArray(b)) {
617
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
618
+ }
619
+ if (isPlainObject(a) && isPlainObject(b)) {
620
+ const ak = Object.keys(a);
621
+ const bk = Object.keys(b);
622
+ return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
623
+ }
624
+ return false;
625
+ }
626
+ var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
627
+ function walk(path, before, after, out) {
628
+ if (Object.is(before, after)) return;
629
+ if (Array.isArray(before) && Array.isArray(after)) {
630
+ const shared = Math.min(before.length, after.length);
631
+ for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
632
+ for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
633
+ for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
634
+ return;
635
+ }
636
+ if (isPlainObject(before) && isPlainObject(after)) {
637
+ for (const key of Object.keys(after)) {
638
+ const p = joinKey(path, key);
639
+ if (key in before) walk(p, before[key], after[key], out);
640
+ else out.push({ path: p, kind: "added", after: after[key] });
641
+ }
642
+ for (const key of Object.keys(before)) {
643
+ if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
644
+ }
645
+ return;
646
+ }
647
+ if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
648
+ }
649
+ function diffStateValues(before, after) {
650
+ const out = [];
651
+ walk("", before, after, out);
652
+ return out;
653
+ }
654
+ function formatStateValue(value, maxLen = 60) {
655
+ const s = value === void 0 ? "undefined" : JSON.stringify(value);
656
+ return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
657
+ }
658
+ function summarizeStateChanges(changes) {
659
+ return changes.map((c) => {
660
+ const at = c.path === "" ? "(root)" : c.path;
661
+ switch (c.kind) {
662
+ case "added":
663
+ return `+ ${at}: ${formatStateValue(c.after)}`;
664
+ case "removed":
665
+ return `\u2212 ${at}`;
666
+ case "changed":
667
+ return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
668
+ }
669
+ });
670
+ }
671
+
672
+ // ../executable-stories-core/dist/storyboard.js
673
+ function findScreenshot(entries) {
674
+ for (const entry of entries) {
675
+ if (entry.kind === "screenshot") return entry;
676
+ if (entry.children) {
677
+ const nested = findScreenshot(entry.children);
678
+ if (nested) return nested;
679
+ }
680
+ }
681
+ return void 0;
682
+ }
683
+ function findStates(entries, out = []) {
684
+ for (const entry of entries) {
685
+ if (entry.kind === "state") out.push(entry);
686
+ if (entry.children) findStates(entry.children, out);
687
+ }
688
+ return out;
689
+ }
690
+ var laneOf = (label) => label ?? "";
691
+ function extractStoryboardFrames(scenario) {
692
+ const frames = [];
693
+ const laneOrder = [];
694
+ const previous = /* @__PURE__ */ new Map();
695
+ for (const step of scenario.steps) {
696
+ const shot = findScreenshot(step.docEntries);
697
+ const stateDocs = findStates(step.docEntries);
698
+ if (!shot && stateDocs.length === 0) continue;
699
+ const byLane = /* @__PURE__ */ new Map();
700
+ for (const doc of stateDocs) {
701
+ const lane = laneOf(doc.label);
702
+ if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
703
+ byLane.set(lane, doc);
704
+ }
705
+ const states = [];
706
+ for (const lane of laneOrder) {
707
+ const doc = byLane.get(lane);
708
+ if (!doc) continue;
709
+ const card = {
710
+ ...doc.label !== void 0 && { label: doc.label },
711
+ value: doc.value
712
+ };
713
+ if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
714
+ previous.set(lane, doc.value);
715
+ states.push(card);
716
+ }
717
+ frames.push({
718
+ stepId: step.id,
719
+ stepIndex: step.index,
720
+ keyword: step.keyword,
721
+ text: step.text,
722
+ status: step.status,
723
+ ...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
724
+ states
725
+ });
726
+ }
727
+ return frames;
728
+ }
729
+
730
+ // src/components/ReportStoryboard.tsx
731
+ var import_jsx_runtime19 = require("react/jsx-runtime");
732
+ var FRAME_GLYPH = {
733
+ passed: "\u2713",
734
+ failed: "\u2717",
735
+ skipped: "\u25CB",
736
+ pending: "\u25CB"
737
+ };
738
+ var FRAME_GLYPH_COLOR = {
739
+ passed: "text-pass",
740
+ failed: "text-fail",
741
+ skipped: "text-skip",
742
+ pending: "text-pend"
743
+ };
744
+ function ReportStoryboard({ scenario }) {
745
+ const frames = extractStoryboardFrames(scenario);
746
+ if (frames.length < 2) return null;
747
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
748
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
749
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
750
+ ] });
751
+ }
752
+ function StoryboardFrameItem({ frame }) {
753
+ const label = `${frame.keyword} ${frame.text}`;
754
+ const hasStates = frame.states.length > 0;
755
+ const caption = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
756
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
757
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0", children: [
758
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
759
+ " ",
760
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
761
+ ] })
762
+ ] });
763
+ return (
764
+ // State cards need room for diff rows; screenshot-only frames keep the
765
+ // original narrow film-cell width (and DOM) unchanged.
766
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
767
+ frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FrameScreenshot, { frame, label }) : null,
768
+ hasStates ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StateCardView, { card }, card.label ?? i)) }) : null,
769
+ frame.screenshot ? caption : (
770
+ // No screenshot means no image anchor, so the caption carries the
771
+ // jump-to-step link instead.
772
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
773
+ )
774
+ ] })
775
+ );
776
+ }
777
+ function FrameScreenshot({ frame, label }) {
778
+ const path = frame.screenshot?.path ?? "";
779
+ const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
780
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
781
+ "a",
782
+ {
783
+ href: `#${frame.stepId}`,
784
+ "aria-label": `Jump to step: ${label}`,
785
+ className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
786
+ children: src ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
787
+ "img",
788
+ {
789
+ src,
790
+ alt: frame.screenshot?.alt ?? label,
791
+ loading: "lazy",
792
+ className: "h-24 w-full bg-muted object-cover object-top"
793
+ }
794
+ ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
795
+ }
796
+ );
797
+ }
798
+ var CHANGE_TONE = {
799
+ added: "bg-pass-bg text-pass",
800
+ removed: "bg-fail-bg text-fail",
801
+ changed: "bg-skip-bg text-skip"
802
+ };
803
+ function prettyJson(value) {
804
+ try {
805
+ return JSON.stringify(value, null, 2) ?? String(value);
806
+ } catch {
807
+ return String(value);
808
+ }
809
+ }
810
+ function StateCardView({ card }) {
811
+ const json = prettyJson(card.value);
812
+ const firstCapture = card.changes === void 0;
813
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
814
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
815
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground", children: card.label ?? "State" }),
816
+ firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
817
+ ] }),
818
+ !firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
819
+ "li",
820
+ {
821
+ className: cn(
822
+ "rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
823
+ CHANGE_TONE[change.kind]
824
+ ),
825
+ children: summarizeStateChanges([change])[0]
826
+ },
827
+ i
828
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
829
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
830
+ "details",
831
+ {
832
+ open: firstCapture && json.length <= 240,
833
+ className: cn(firstCapture ? "mt-1.5" : "mt-1"),
834
+ children: [
835
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
836
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("pre", { tabIndex: 0, className: "mt-1 max-h-48 overflow-auto rounded-sm bg-muted p-1.5 font-mono text-[0.625rem] leading-snug", children: json })
837
+ ]
838
+ }
839
+ )
840
+ ] });
841
+ }
842
+
597
843
  // src/components/ReportAttachments.tsx
598
- var import_jsx_runtime18 = require("react/jsx-runtime");
844
+ var import_jsx_runtime20 = require("react/jsx-runtime");
599
845
  function ReportAttachments({ attachments }) {
600
846
  if (attachments.length === 0) return null;
601
847
  return (
602
848
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
603
849
  // blocks don't create duplicate "Attachments" region landmarks.
604
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
850
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
605
851
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
606
852
  const isImage = att.mediaType.startsWith("image/");
607
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
608
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
853
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
854
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
609
855
  "img",
610
856
  {
611
857
  src: dataUri,
@@ -614,8 +860,8 @@ function ReportAttachments({ attachments }) {
614
860
  className: "max-w-full rounded-md border border-border"
615
861
  }
616
862
  ),
617
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
618
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
863
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
864
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
619
865
  "a",
620
866
  {
621
867
  href: dataUri,
@@ -624,7 +870,7 @@ function ReportAttachments({ attachments }) {
624
870
  children: [
625
871
  att.name,
626
872
  " ",
627
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "text-muted-foreground", children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "text-muted-foreground", children: [
628
874
  "(",
629
875
  att.mediaType,
630
876
  ")"
@@ -688,15 +934,15 @@ function toTraceRows(spans) {
688
934
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
689
935
  const rows = [];
690
936
  const seen = /* @__PURE__ */ new Set();
691
- const walk = (node, depth) => {
937
+ const walk2 = (node, depth) => {
692
938
  if (seen.has(node.span.spanId)) return;
693
939
  seen.add(node.span.spanId);
694
940
  rows.push({ ...node.span, depth });
695
- for (const child of node.children) walk(child, depth + 1);
941
+ for (const child of node.children) walk2(child, depth + 1);
696
942
  };
697
- for (const root of roots) walk(root, 0);
943
+ for (const root of roots) walk2(root, 0);
698
944
  for (const node of byId.values()) {
699
- if (!seen.has(node.span.spanId)) walk(node, 0);
945
+ if (!seen.has(node.span.spanId)) walk2(node, 0);
700
946
  }
701
947
  return rows;
702
948
  }
@@ -712,7 +958,7 @@ function traceWindow(rows) {
712
958
  }
713
959
 
714
960
  // src/components/ReportTrace.tsx
715
- var import_jsx_runtime19 = require("react/jsx-runtime");
961
+ var import_jsx_runtime21 = require("react/jsx-runtime");
716
962
  var BAR_COLOR = {
717
963
  ok: "bg-pass",
718
964
  error: "bg-fail",
@@ -723,8 +969,8 @@ function ReportTrace({ spans }) {
723
969
  const rows = toTraceRows(spans);
724
970
  if (rows.length === 0) return null;
725
971
  const { minStartMs, totalMs } = traceWindow(rows);
726
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
727
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
972
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
973
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
728
974
  "Trace (",
729
975
  rows.length,
730
976
  " span",
@@ -733,11 +979,11 @@ function ReportTrace({ spans }) {
733
979
  formatDuration(totalMs),
734
980
  ")"
735
981
  ] }),
736
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
982
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
737
983
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
738
984
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
739
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: "flex items-center gap-2", children: [
740
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
985
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex items-center gap-2", children: [
986
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
741
987
  "span",
742
988
  {
743
989
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -746,14 +992,14 @@ function ReportTrace({ spans }) {
746
992
  children: row.name
747
993
  }
748
994
  ),
749
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
995
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
750
996
  "span",
751
997
  {
752
998
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
753
999
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
754
1000
  }
755
1001
  ) }),
756
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
1002
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
757
1003
  ] }, `${row.spanId}-${i}`);
758
1004
  }) })
759
1005
  ] });
@@ -804,7 +1050,7 @@ function flakinessOf(entries) {
804
1050
  }
805
1051
 
806
1052
  // src/components/ScenarioRunHistory.tsx
807
- var import_jsx_runtime20 = require("react/jsx-runtime");
1053
+ var import_jsx_runtime22 = require("react/jsx-runtime");
808
1054
  var MAX_DOTS = 10;
809
1055
  var DOT_COLOR = {
810
1056
  passed: "bg-pass",
@@ -824,16 +1070,16 @@ function ScenarioRunHistory({ scenarioId }) {
824
1070
  const recent = entries.slice(-MAX_DOTS);
825
1071
  const flaky = flakinessOf(recent) === "flaky";
826
1072
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
827
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
828
- flaky ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
829
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1073
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
1074
+ flaky ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
1075
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
830
1076
  "span",
831
1077
  {
832
1078
  role: "img",
833
1079
  "aria-label": `Run history: ${summary}`,
834
1080
  title: summary,
835
1081
  className: "flex shrink-0 items-center gap-[3px]",
836
- children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1082
+ children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
837
1083
  "span",
838
1084
  {
839
1085
  "aria-hidden": true,
@@ -872,9 +1118,9 @@ function useScenarioActions() {
872
1118
 
873
1119
  // src/components/ui/card.tsx
874
1120
  var React2 = require("react");
875
- var import_jsx_runtime21 = require("react/jsx-runtime");
1121
+ var import_jsx_runtime23 = require("react/jsx-runtime");
876
1122
  function Card({ className, ...props }) {
877
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1123
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
878
1124
  "div",
879
1125
  {
880
1126
  "data-slot": "card",
@@ -887,7 +1133,7 @@ function Card({ className, ...props }) {
887
1133
  );
888
1134
  }
889
1135
  function CardHeader({ className, ...props }) {
890
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1136
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
891
1137
  "div",
892
1138
  {
893
1139
  "data-slot": "card-header",
@@ -900,7 +1146,7 @@ function CardHeader({ className, ...props }) {
900
1146
  );
901
1147
  }
902
1148
  function CardContent({ className, ...props }) {
903
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1149
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
904
1150
  "div",
905
1151
  {
906
1152
  "data-slot": "card-content",
@@ -914,13 +1160,13 @@ function CardContent({ className, ...props }) {
914
1160
  var React3 = require("react");
915
1161
  var import_menu = require("@base-ui/react/menu");
916
1162
  var import_lucide_react = require("lucide-react");
917
- var import_jsx_runtime22 = require("react/jsx-runtime");
1163
+ var import_jsx_runtime24 = require("react/jsx-runtime");
918
1164
  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";
919
1165
  function DropdownMenu(props) {
920
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
1166
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
921
1167
  }
922
1168
  function DropdownMenuTrigger(props) {
923
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1169
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
924
1170
  }
925
1171
  function DropdownMenuContent({
926
1172
  className,
@@ -928,14 +1174,14 @@ function DropdownMenuContent({
928
1174
  sideOffset = 4,
929
1175
  ...props
930
1176
  }) {
931
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1177
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
932
1178
  import_menu.Menu.Positioner,
933
1179
  {
934
1180
  "data-slot": "dropdown-menu-positioner",
935
1181
  className: "z-50",
936
1182
  align,
937
1183
  sideOffset,
938
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1184
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
939
1185
  import_menu.Menu.Popup,
940
1186
  {
941
1187
  "data-slot": "dropdown-menu-content",
@@ -953,7 +1199,7 @@ function DropdownMenuItem({
953
1199
  className,
954
1200
  ...props
955
1201
  }) {
956
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1202
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
957
1203
  import_menu.Menu.Item,
958
1204
  {
959
1205
  "data-slot": "dropdown-menu-item",
@@ -965,7 +1211,7 @@ function DropdownMenuItem({
965
1211
 
966
1212
  // src/components/ReportScenario.tsx
967
1213
  var import_lucide_react2 = require("lucide-react");
968
- var import_jsx_runtime23 = require("react/jsx-runtime");
1214
+ var import_jsx_runtime25 = require("react/jsx-runtime");
969
1215
  var STATUS_META = {
970
1216
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
971
1217
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -981,7 +1227,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
981
1227
  const collapsible = collapse !== null && !hideTitle;
982
1228
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
983
1229
  const actions = useScenarioActions();
984
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1230
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
985
1231
  Card,
986
1232
  {
987
1233
  id: scenario.id,
@@ -989,10 +1235,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
989
1235
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
990
1236
  className: "gap-0 py-0",
991
1237
  children: [
992
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardHeader, { className: "px-4 py-3", children: [
993
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
994
- hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
995
- collapsible ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1238
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardHeader, { className: "px-4 py-3", children: [
1239
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1240
+ hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1241
+ collapsible ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
996
1242
  "button",
997
1243
  {
998
1244
  type: "button",
@@ -1001,49 +1247,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
1001
1247
  "aria-controls": bodyId,
1002
1248
  "aria-label": `Toggle ${scenario.title}`,
1003
1249
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1004
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1250
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1005
1251
  }
1006
1252
  ) : null,
1007
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1008
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: scenario.title })
1253
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1254
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: scenario.title })
1009
1255
  ] }),
1010
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1011
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1012
- scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1013
- meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1014
- actions ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenu, { children: [
1015
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1256
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1257
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1258
+ scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1259
+ meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1260
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenu, { children: [
1261
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1016
1262
  DropdownMenuTrigger,
1017
1263
  {
1018
1264
  "aria-label": `Actions for ${scenario.title}`,
1019
1265
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1020
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1266
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1021
1267
  }
1022
1268
  ),
1023
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuContent, { align: "end", children: [
1024
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1025
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.LinkIcon, {}),
1269
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuContent, { align: "end", children: [
1270
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1271
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.LinkIcon, {}),
1026
1272
  " Copy link"
1027
1273
  ] }),
1028
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1029
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.FileTextIcon, {}),
1274
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1275
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.FileTextIcon, {}),
1030
1276
  " Copy as Markdown"
1031
1277
  ] }),
1032
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1033
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.SparklesIcon, {}),
1278
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1279
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.SparklesIcon, {}),
1034
1280
  " Explain with AI"
1035
1281
  ] })
1036
1282
  ] })
1037
1283
  ] }) : null
1038
1284
  ] })
1039
1285
  ] }),
1040
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1041
- scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1042
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1286
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1287
+ scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1288
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1043
1289
  ] }) : null
1044
1290
  ] }),
1045
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1046
- scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1291
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1292
+ scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1047
1293
  "pre",
1048
1294
  {
1049
1295
  role: "alert",
@@ -1051,10 +1297,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
1051
1297
  children: scenario.errorMessage
1052
1298
  }
1053
1299
  ) : null,
1054
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportSteps, { scenario }),
1055
- scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1056
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1057
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportTrace, { spans: scenario.otelSpans })
1300
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportStoryboard, { scenario }),
1301
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportSteps, { scenario }),
1302
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1303
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1304
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportTrace, { spans: scenario.otelSpans })
1058
1305
  ] })
1059
1306
  ]
1060
1307
  }
@@ -1062,13 +1309,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1062
1309
  }
1063
1310
 
1064
1311
  // src/components/ReportScenarioList.tsx
1065
- var import_jsx_runtime24 = require("react/jsx-runtime");
1312
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1066
1313
  function ReportScenarioList({ feature }) {
1067
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenario, { scenario }, scenario.id)) });
1314
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenario, { scenario }, scenario.id)) });
1068
1315
  }
1069
1316
 
1070
1317
  // src/components/ReportFeature.tsx
1071
- var import_jsx_runtime25 = require("react/jsx-runtime");
1318
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1072
1319
  function ReportFeature({ feature }) {
1073
1320
  const titleId = `${feature.id}-title`;
1074
1321
  const bodyId = `${feature.id}-body`;
@@ -1079,7 +1326,7 @@ function ReportFeature({ feature }) {
1079
1326
  return (
1080
1327
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1081
1328
  // layer of nesting so the scenario cards below read as the primary unit.
1082
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1329
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1083
1330
  "section",
1084
1331
  {
1085
1332
  id: feature.id,
@@ -1087,9 +1334,9 @@ function ReportFeature({ feature }) {
1087
1334
  "aria-labelledby": titleId,
1088
1335
  className: "flex flex-col gap-3",
1089
1336
  children: [
1090
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1091
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "min-w-0", children: [
1092
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1337
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1338
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "min-w-0", children: [
1339
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1093
1340
  "button",
1094
1341
  {
1095
1342
  type: "button",
@@ -1098,31 +1345,31 @@ function ReportFeature({ feature }) {
1098
1345
  "aria-controls": bodyId,
1099
1346
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1100
1347
  children: [
1101
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1102
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate", children: feature.title })
1348
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: feature.title })
1103
1350
  ]
1104
1351
  }
1105
1352
  ) : feature.title }),
1106
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1353
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1107
1354
  ] }),
1108
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1355
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1109
1356
  "p",
1110
1357
  {
1111
1358
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1112
1359
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1113
1360
  children: [
1114
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1361
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
1115
1362
  s.passed,
1116
1363
  " passed"
1117
1364
  ] }),
1118
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1119
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1365
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1366
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1120
1367
  s.failed,
1121
1368
  " failed"
1122
1369
  ] }),
1123
- skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
1124
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1125
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1370
+ skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
1371
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1372
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
1126
1373
  skipped,
1127
1374
  " skipped"
1128
1375
  ] })
@@ -1131,7 +1378,7 @@ function ReportFeature({ feature }) {
1131
1378
  }
1132
1379
  )
1133
1380
  ] }),
1134
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenarioList, { feature }) })
1381
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenarioList, { feature }) })
1135
1382
  ]
1136
1383
  }
1137
1384
  )
@@ -1139,17 +1386,17 @@ function ReportFeature({ feature }) {
1139
1386
  }
1140
1387
 
1141
1388
  // src/components/ReportFeatureList.tsx
1142
- var import_jsx_runtime26 = require("react/jsx-runtime");
1389
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1143
1390
  function ReportFeatureList() {
1144
1391
  const report = useReport();
1145
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportFeature, { feature }, feature.id)) });
1392
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportFeature, { feature }, feature.id)) });
1146
1393
  }
1147
1394
 
1148
1395
  // src/components/ui/empty.tsx
1149
1396
  var import_class_variance_authority2 = require("class-variance-authority");
1150
- var import_jsx_runtime27 = require("react/jsx-runtime");
1397
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1151
1398
  function Empty({ className, ...props }) {
1152
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1399
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1153
1400
  "div",
1154
1401
  {
1155
1402
  "data-slot": "empty",
@@ -1162,7 +1409,7 @@ function Empty({ className, ...props }) {
1162
1409
  );
1163
1410
  }
1164
1411
  function EmptyHeader({ className, ...props }) {
1165
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1412
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1166
1413
  "div",
1167
1414
  {
1168
1415
  "data-slot": "empty-header",
@@ -1189,7 +1436,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
1189
1436
  }
1190
1437
  );
1191
1438
  function EmptyTitle({ className, ...props }) {
1192
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1439
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1193
1440
  "div",
1194
1441
  {
1195
1442
  "data-slot": "empty-title",
@@ -1200,16 +1447,16 @@ function EmptyTitle({ className, ...props }) {
1200
1447
  }
1201
1448
 
1202
1449
  // src/components/ReportEmpty.tsx
1203
- var import_jsx_runtime28 = require("react/jsx-runtime");
1450
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1204
1451
  function ReportEmpty({ message }) {
1205
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1452
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1206
1453
  }
1207
1454
 
1208
1455
  // src/components/ReportSummary.tsx
1209
- var import_jsx_runtime29 = require("react/jsx-runtime");
1456
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1210
1457
  function ReportSummary({ className }) {
1211
1458
  const report = useReport();
1212
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1459
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1213
1460
  ReportSummaryView,
1214
1461
  {
1215
1462
  summary: report.summary,
@@ -1235,7 +1482,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1235
1482
  if (summary.pending > 0) {
1236
1483
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1237
1484
  }
1238
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1485
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1239
1486
  "dl",
1240
1487
  {
1241
1488
  className: cn(
@@ -1248,17 +1495,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1248
1495
  "aria-label": ariaLabel,
1249
1496
  children: cards.map((c) => {
1250
1497
  const tone = TONE[c.status];
1251
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1498
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1252
1499
  "div",
1253
1500
  {
1254
1501
  "data-status": c.status,
1255
1502
  className: "rounded-lg border bg-card px-4 py-3",
1256
1503
  children: [
1257
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1258
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1504
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1505
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1259
1506
  c.label
1260
1507
  ] }),
1261
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1508
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1262
1509
  ]
1263
1510
  },
1264
1511
  c.status
@@ -1318,7 +1565,7 @@ function prUrl(ci) {
1318
1565
  }
1319
1566
 
1320
1567
  // src/components/ReportMeta.tsx
1321
- var import_jsx_runtime30 = require("react/jsx-runtime");
1568
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1322
1569
  function ReportMeta() {
1323
1570
  const report = useReport();
1324
1571
  const items = [];
@@ -1341,13 +1588,13 @@ function ReportMeta() {
1341
1588
  const short = sha.slice(0, 8);
1342
1589
  items.push({
1343
1590
  label: "Commit",
1344
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1591
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1345
1592
  });
1346
1593
  }
1347
1594
  if (report.ci) {
1348
1595
  items.push({
1349
1596
  label: "CI",
1350
- value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1597
+ value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1351
1598
  ciDisplayName(report.ci.name),
1352
1599
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1353
1600
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1358,7 +1605,7 @@ function ReportMeta() {
1358
1605
  const label = `#${report.ci.prNumber}`;
1359
1606
  items.push({
1360
1607
  label: "PR",
1361
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1608
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1362
1609
  });
1363
1610
  }
1364
1611
  if (items.length === 0) return null;
@@ -1366,48 +1613,48 @@ function ReportMeta() {
1366
1613
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1367
1614
  // collapsed disclosure so it doesn't push the result down. Native <details>
1368
1615
  // so it works with no JS (the SSR/no-hydration report still toggles).
1369
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1370
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1371
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1616
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1617
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1618
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1372
1619
  "Run details"
1373
1620
  ] }),
1374
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1375
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "font-medium", children: item.label }),
1376
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1621
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1622
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dt", { className: "font-medium", children: item.label }),
1623
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1377
1624
  ] }, item.label)) })
1378
1625
  ] })
1379
1626
  );
1380
1627
  }
1381
1628
 
1382
1629
  // src/components/ReportSchemaError.tsx
1383
- var import_jsx_runtime31 = require("react/jsx-runtime");
1630
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1384
1631
  function ReportSchemaError({ error }) {
1385
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1386
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: "Report could not be displayed." }) }),
1387
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: error.message }),
1388
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
1632
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1633
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "Report could not be displayed." }) }),
1634
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: error.message }),
1635
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { children: [
1389
1636
  "The report bundle is newer than this version of ",
1390
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { children: "executable-stories-react" }),
1637
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("code", { children: "executable-stories-react" }),
1391
1638
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1392
1639
  ] }) : null,
1393
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { children: [
1394
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { children: [
1640
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { children: [
1641
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("summary", { children: [
1395
1642
  error.issues.length,
1396
1643
  " validation issue",
1397
1644
  error.issues.length === 1 ? "" : "s"
1398
1645
  ] }),
1399
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1646
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1400
1647
  ] }) : null
1401
1648
  ] });
1402
1649
  }
1403
1650
 
1404
1651
  // src/components/ReportShell.tsx
1405
- var import_jsx_runtime32 = require("react/jsx-runtime");
1652
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1406
1653
  function ReportTitleBlock({ title }) {
1407
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
1408
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h1", { children: title ?? "Story Report" }),
1409
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSummary, {}),
1410
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportMeta, {})
1654
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
1655
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { children: title ?? "Story Report" }),
1656
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSummary, {}),
1657
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportMeta, {})
1411
1658
  ] });
1412
1659
  }
1413
1660
  function ReportErrorShell({
@@ -1416,28 +1663,28 @@ function ReportErrorShell({
1416
1663
  title,
1417
1664
  dataTheme
1418
1665
  }) {
1419
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSchemaError, { error }) });
1666
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSchemaError, { error }) });
1420
1667
  }
1421
1668
 
1422
1669
  // src/components/Report.tsx
1423
- var import_jsx_runtime33 = require("react/jsx-runtime");
1670
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1424
1671
  function Report(props) {
1425
1672
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1426
1673
  const result = unwrapReport(report);
1427
1674
  if (!result.ok) {
1428
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1675
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1429
1676
  }
1430
1677
  const data = result.data;
1431
1678
  const hasContent = data.features.length > 0;
1432
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1433
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportTitleBlock, { title }) }),
1434
- hasContent ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportEmpty, {})
1679
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1680
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportTitleBlock, { title }) }),
1681
+ hasContent ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportEmpty, {})
1435
1682
  ] }) });
1436
1683
  }
1437
1684
 
1438
1685
  // src/components/doc/MermaidView.tsx
1439
1686
  var import_react8 = require("react");
1440
- var import_jsx_runtime34 = require("react/jsx-runtime");
1687
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1441
1688
  function prefersDark(el) {
1442
1689
  const themed = el?.closest("[data-theme]");
1443
1690
  if (themed?.dataset.theme === "dark") return true;
@@ -1474,9 +1721,9 @@ function MermaidView({ entry, load }) {
1474
1721
  };
1475
1722
  }, [entry.code, load]);
1476
1723
  if (svg) {
1477
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("figure", { ref, className: "my-3", children: [
1478
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1479
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1724
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("figure", { ref, className: "my-3", children: [
1725
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1726
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1480
1727
  "div",
1481
1728
  {
1482
1729
  role: "img",
@@ -1487,18 +1734,18 @@ function MermaidView({ entry, load }) {
1487
1734
  )
1488
1735
  ] });
1489
1736
  }
1490
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MermaidSource, { entry, ref });
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MermaidSource, { entry, ref });
1491
1738
  }
1492
1739
 
1493
1740
  // src/components/doc/MermaidDiagram.tsx
1494
- var import_jsx_runtime35 = require("react/jsx-runtime");
1741
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1495
1742
  var mermaidLoader;
1496
1743
  function loadMermaid() {
1497
1744
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1498
1745
  return mermaidLoader;
1499
1746
  }
1500
1747
  function MermaidDiagram({ entry, load = loadMermaid }) {
1501
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MermaidView, { entry, load });
1748
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MermaidView, { entry, load });
1502
1749
  }
1503
1750
 
1504
1751
  // src/components/ScenarioExplorer.tsx
@@ -1508,12 +1755,12 @@ var import_react9 = require("react");
1508
1755
  var React4 = require("react");
1509
1756
  var import_cmdk = require("cmdk");
1510
1757
  var import_lucide_react3 = require("lucide-react");
1511
- var import_jsx_runtime36 = require("react/jsx-runtime");
1758
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1512
1759
  function Command({
1513
1760
  className,
1514
1761
  ...props
1515
1762
  }) {
1516
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1763
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1517
1764
  import_cmdk.Command,
1518
1765
  {
1519
1766
  "data-slot": "command",
@@ -1529,14 +1776,14 @@ function CommandInput({
1529
1776
  className,
1530
1777
  ...props
1531
1778
  }) {
1532
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
1779
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
1533
1780
  "div",
1534
1781
  {
1535
1782
  "data-slot": "command-input-wrapper",
1536
1783
  className: "flex h-9 items-center gap-2 border-b px-3",
1537
1784
  children: [
1538
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1539
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1785
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1786
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1540
1787
  import_cmdk.Command.Input,
1541
1788
  {
1542
1789
  "data-slot": "command-input",
@@ -1555,7 +1802,7 @@ function CommandList({
1555
1802
  className,
1556
1803
  ...props
1557
1804
  }) {
1558
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1805
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1559
1806
  import_cmdk.Command.List,
1560
1807
  {
1561
1808
  "data-slot": "command-list",
@@ -1570,7 +1817,7 @@ function CommandList({
1570
1817
  function CommandEmpty({
1571
1818
  ...props
1572
1819
  }) {
1573
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1820
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1574
1821
  import_cmdk.Command.Empty,
1575
1822
  {
1576
1823
  "data-slot": "command-empty",
@@ -1583,7 +1830,7 @@ function CommandGroup({
1583
1830
  className,
1584
1831
  ...props
1585
1832
  }) {
1586
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1833
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1587
1834
  import_cmdk.Command.Group,
1588
1835
  {
1589
1836
  "data-slot": "command-group",
@@ -1599,7 +1846,7 @@ function CommandItem({
1599
1846
  className,
1600
1847
  ...props
1601
1848
  }) {
1602
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1849
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1603
1850
  import_cmdk.Command.Item,
1604
1851
  {
1605
1852
  "data-slot": "command-item",
@@ -1613,7 +1860,7 @@ function CommandItem({
1613
1860
  }
1614
1861
 
1615
1862
  // src/components/ScenarioExplorer.tsx
1616
- var import_jsx_runtime37 = require("react/jsx-runtime");
1863
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1617
1864
  var STATUS_FILTERS = [
1618
1865
  { value: "all", label: "All" },
1619
1866
  { value: "passed", label: "Passed" },
@@ -1624,22 +1871,22 @@ var STATUS_FILTERS = [
1624
1871
  function ScenarioExplorer({ scenarios, summary }) {
1625
1872
  const [status, setStatus] = (0, import_react9.useState)("all");
1626
1873
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1627
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "font-sans text-foreground", children: [
1628
- summary ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1874
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "font-sans text-foreground", children: [
1875
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1629
1876
  summary.total,
1630
1877
  " scenarios \xB7 ",
1631
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-pass", children: [
1878
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-pass", children: [
1632
1879
  summary.passed,
1633
1880
  " passed"
1634
1881
  ] }),
1635
1882
  " \xB7",
1636
1883
  " ",
1637
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-fail", children: [
1884
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-fail", children: [
1638
1885
  summary.failed,
1639
1886
  " failed"
1640
1887
  ] })
1641
1888
  ] }) : null,
1642
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1889
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1643
1890
  "button",
1644
1891
  {
1645
1892
  type: "button",
@@ -1654,26 +1901,26 @@ function ScenarioExplorer({ scenarios, summary }) {
1654
1901
  },
1655
1902
  f.value
1656
1903
  )) }),
1657
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1904
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
1658
1905
  Command,
1659
1906
  {
1660
1907
  className: "rounded-lg border border-border bg-card",
1661
1908
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1662
1909
  children: [
1663
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
1664
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(CommandList, { className: "max-h-none", children: [
1665
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
1666
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1910
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
1911
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(CommandList, { className: "max-h-none", children: [
1912
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1667
1914
  CommandItem,
1668
1915
  {
1669
1916
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1670
1917
  asChild: true,
1671
1918
  className: "cursor-pointer",
1672
- children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
1673
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Badge, { variant: s.status, children: s.status }),
1674
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1675
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1676
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1919
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
1920
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: s.status, children: s.status }),
1921
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1922
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1923
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1677
1924
  ] })
1678
1925
  },
1679
1926
  s.id
@@ -2169,6 +2416,9 @@ var story_report_v1_default = {
2169
2416
  {
2170
2417
  $ref: "#/$defs/DocHtml"
2171
2418
  },
2419
+ {
2420
+ $ref: "#/$defs/DocState"
2421
+ },
2172
2422
  {
2173
2423
  $ref: "#/$defs/DocCustom"
2174
2424
  }
@@ -2544,6 +2794,33 @@ var story_report_v1_default = {
2544
2794
  }
2545
2795
  ]
2546
2796
  },
2797
+ DocState: {
2798
+ type: "object",
2799
+ properties: {
2800
+ kind: {
2801
+ const: "state"
2802
+ },
2803
+ label: {
2804
+ type: "string"
2805
+ },
2806
+ value: {},
2807
+ phase: {
2808
+ $ref: "#/$defs/DocPhase"
2809
+ },
2810
+ children: {
2811
+ type: "array",
2812
+ items: {
2813
+ $ref: "#/$defs/DocEntry"
2814
+ }
2815
+ }
2816
+ },
2817
+ required: [
2818
+ "kind",
2819
+ "value",
2820
+ "phase"
2821
+ ],
2822
+ additionalProperties: false
2823
+ },
2547
2824
  DocCustom: {
2548
2825
  type: "object",
2549
2826
  properties: {
@@ -2694,6 +2971,7 @@ function parseStoryReport(input) {
2694
2971
  ReportSchemaError,
2695
2972
  ReportStepItem,
2696
2973
  ReportSteps,
2974
+ ReportStoryboard,
2697
2975
  ReportSummary,
2698
2976
  ReportSummaryView,
2699
2977
  ReportTrace,