executable-stories-react 0.7.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
@@ -458,17 +458,29 @@ function DocHtml({ entry }) {
458
458
  ] });
459
459
  }
460
460
 
461
- // src/components/doc/DocCustom.tsx
461
+ // src/components/doc/DocState.tsx
462
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");
463
475
  function DocCustom({ entry }) {
464
476
  const renderers = useCustomRenderers();
465
477
  const renderer = renderers[entry.type];
466
478
  if (renderer) {
467
- 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) });
468
480
  }
469
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
470
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
471
- /* @__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) })
472
484
  ] });
473
485
  }
474
486
  function safeStringify(value) {
@@ -480,45 +492,47 @@ function safeStringify(value) {
480
492
  }
481
493
 
482
494
  // src/components/doc/DocEntry.tsx
483
- var import_jsx_runtime14 = require("react/jsx-runtime");
495
+ var import_jsx_runtime15 = require("react/jsx-runtime");
484
496
  function DocEntry({ entry }) {
485
497
  switch (entry.kind) {
486
498
  case "note":
487
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocNote, { entry });
499
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocNote, { entry });
488
500
  case "tag":
489
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocTag, { entry });
501
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTag, { entry });
490
502
  case "kv":
491
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocKv, { entry });
503
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocKv, { entry });
492
504
  case "code":
493
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocCode, { entry });
505
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCode, { entry });
494
506
  case "table":
495
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocTable, { entry });
507
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTable, { entry });
496
508
  case "link":
497
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocLink, { entry });
509
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocLink, { entry });
498
510
  case "section":
499
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocSection, { entry });
511
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocSection, { entry });
500
512
  case "mermaid":
501
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocMermaid, { entry });
513
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocMermaid, { entry });
502
514
  case "screenshot":
503
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocScreenshot, { entry });
515
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocScreenshot, { entry });
504
516
  case "video":
505
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocVideo, { entry });
517
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocVideo, { entry });
506
518
  case "html":
507
- 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 });
508
522
  case "custom":
509
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocCustom, { entry });
523
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCustom, { entry });
510
524
  }
511
525
  }
512
526
 
513
527
  // src/components/ReportDocEntries.tsx
514
- var import_jsx_runtime15 = require("react/jsx-runtime");
528
+ var import_jsx_runtime16 = require("react/jsx-runtime");
515
529
  function ReportDocEntries({ entries }) {
516
530
  if (entries.length === 0) return null;
517
- 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)) });
518
532
  }
519
533
 
520
534
  // src/lib/step-params.tsx
521
- var import_jsx_runtime16 = require("react/jsx-runtime");
535
+ var import_jsx_runtime17 = require("react/jsx-runtime");
522
536
  var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
523
537
  function highlightStepParams(text) {
524
538
  const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
@@ -530,7 +544,7 @@ function highlightStepParams(text) {
530
544
  const end = start + match[0].length;
531
545
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
532
546
  nodes.push(
533
- /* @__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)
534
548
  );
535
549
  lastIndex = end;
536
550
  });
@@ -539,7 +553,7 @@ function highlightStepParams(text) {
539
553
  }
540
554
 
541
555
  // src/components/ReportSteps.tsx
542
- var import_jsx_runtime17 = require("react/jsx-runtime");
556
+ var import_jsx_runtime18 = require("react/jsx-runtime");
543
557
  var STEP_GLYPH = {
544
558
  passed: "\u2713",
545
559
  failed: "\u2717",
@@ -554,21 +568,21 @@ var STEP_GLYPH_COLOR = {
554
568
  };
555
569
  function ReportSteps({ scenario }) {
556
570
  if (scenario.steps.length === 0) return null;
557
- 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)) });
558
572
  }
559
573
  function ReportStepItem({ step }) {
560
574
  const kw = step.keyword.toLowerCase();
561
575
  const continuation = kw === "and" || kw === "but";
562
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
576
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
563
577
  "li",
564
578
  {
565
579
  id: step.id,
566
580
  "data-status": step.status,
567
581
  className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
568
582
  children: [
569
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-baseline gap-2", children: [
570
- /* @__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" }),
571
- /* @__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)(
572
586
  "span",
573
587
  {
574
588
  className: cn(
@@ -578,10 +592,10 @@ function ReportStepItem({ step }) {
578
592
  children: step.keyword
579
593
  }
580
594
  ),
581
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
582
- 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
583
597
  ] }),
584
- step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
598
+ step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
585
599
  "pre",
586
600
  {
587
601
  role: "alert",
@@ -589,12 +603,72 @@ function ReportStepItem({ step }) {
589
603
  children: step.errorMessage
590
604
  }
591
605
  ) : null,
592
- 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
593
607
  ]
594
608
  }
595
609
  );
596
610
  }
597
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
+
598
672
  // ../executable-stories-core/dist/storyboard.js
599
673
  function findScreenshot(entries) {
600
674
  for (const entry of entries) {
@@ -606,26 +680,55 @@ function findScreenshot(entries) {
606
680
  }
607
681
  return void 0;
608
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 ?? "";
609
691
  function extractStoryboardFrames(scenario) {
610
692
  const frames = [];
693
+ const laneOrder = [];
694
+ const previous = /* @__PURE__ */ new Map();
611
695
  for (const step of scenario.steps) {
612
696
  const shot = findScreenshot(step.docEntries);
613
- if (!shot) continue;
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
+ }
614
717
  frames.push({
615
718
  stepId: step.id,
616
719
  stepIndex: step.index,
617
720
  keyword: step.keyword,
618
721
  text: step.text,
619
722
  status: step.status,
620
- path: shot.path,
621
- ...shot.alt !== void 0 && { alt: shot.alt }
723
+ ...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
724
+ states
622
725
  });
623
726
  }
624
727
  return frames;
625
728
  }
626
729
 
627
730
  // src/components/ReportStoryboard.tsx
628
- var import_jsx_runtime18 = require("react/jsx-runtime");
731
+ var import_jsx_runtime19 = require("react/jsx-runtime");
629
732
  var FRAME_GLYPH = {
630
733
  passed: "\u2713",
631
734
  failed: "\u2717",
@@ -641,55 +744,114 @@ var FRAME_GLYPH_COLOR = {
641
744
  function ReportStoryboard({ scenario }) {
642
745
  const frames = extractStoryboardFrames(scenario);
643
746
  if (frames.length < 2) return null;
644
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
645
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
646
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { className: "flex gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
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)) })
647
750
  ] });
648
751
  }
649
752
  function StoryboardFrameItem({ frame }) {
650
- const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
651
753
  const label = `${frame.keyword} ${frame.text}`;
652
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("li", { className: "w-40 shrink-0", children: [
653
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
654
- "a",
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",
655
820
  {
656
- href: `#${frame.stepId}`,
657
- "aria-label": `Jump to step: ${label}`,
658
- className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
659
- children: src ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
660
- "img",
661
- {
662
- src,
663
- alt: frame.alt ?? label,
664
- loading: "lazy",
665
- className: "h-24 w-full bg-muted object-cover object-top"
666
- }
667
- ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
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
+ ]
668
838
  }
669
- ),
670
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
671
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
672
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "min-w-0", children: [
673
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
674
- " ",
675
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
676
- ] })
677
- ] })
839
+ )
678
840
  ] });
679
841
  }
680
842
 
681
843
  // src/components/ReportAttachments.tsx
682
- var import_jsx_runtime19 = require("react/jsx-runtime");
844
+ var import_jsx_runtime20 = require("react/jsx-runtime");
683
845
  function ReportAttachments({ attachments }) {
684
846
  if (attachments.length === 0) return null;
685
847
  return (
686
848
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
687
849
  // blocks don't create duplicate "Attachments" region landmarks.
688
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
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) => {
689
851
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
690
852
  const isImage = att.mediaType.startsWith("image/");
691
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
692
- /* @__PURE__ */ (0, import_jsx_runtime19.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)(
693
855
  "img",
694
856
  {
695
857
  src: dataUri,
@@ -698,8 +860,8 @@ function ReportAttachments({ attachments }) {
698
860
  className: "max-w-full rounded-md border border-border"
699
861
  }
700
862
  ),
701
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
702
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime19.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)(
703
865
  "a",
704
866
  {
705
867
  href: dataUri,
@@ -708,7 +870,7 @@ function ReportAttachments({ attachments }) {
708
870
  children: [
709
871
  att.name,
710
872
  " ",
711
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "text-muted-foreground", children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "text-muted-foreground", children: [
712
874
  "(",
713
875
  att.mediaType,
714
876
  ")"
@@ -772,15 +934,15 @@ function toTraceRows(spans) {
772
934
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
773
935
  const rows = [];
774
936
  const seen = /* @__PURE__ */ new Set();
775
- const walk = (node, depth) => {
937
+ const walk2 = (node, depth) => {
776
938
  if (seen.has(node.span.spanId)) return;
777
939
  seen.add(node.span.spanId);
778
940
  rows.push({ ...node.span, depth });
779
- for (const child of node.children) walk(child, depth + 1);
941
+ for (const child of node.children) walk2(child, depth + 1);
780
942
  };
781
- for (const root of roots) walk(root, 0);
943
+ for (const root of roots) walk2(root, 0);
782
944
  for (const node of byId.values()) {
783
- if (!seen.has(node.span.spanId)) walk(node, 0);
945
+ if (!seen.has(node.span.spanId)) walk2(node, 0);
784
946
  }
785
947
  return rows;
786
948
  }
@@ -796,7 +958,7 @@ function traceWindow(rows) {
796
958
  }
797
959
 
798
960
  // src/components/ReportTrace.tsx
799
- var import_jsx_runtime20 = require("react/jsx-runtime");
961
+ var import_jsx_runtime21 = require("react/jsx-runtime");
800
962
  var BAR_COLOR = {
801
963
  ok: "bg-pass",
802
964
  error: "bg-fail",
@@ -807,8 +969,8 @@ function ReportTrace({ spans }) {
807
969
  const rows = toTraceRows(spans);
808
970
  if (rows.length === 0) return null;
809
971
  const { minStartMs, totalMs } = traceWindow(rows);
810
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
811
- /* @__PURE__ */ (0, import_jsx_runtime20.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: [
812
974
  "Trace (",
813
975
  rows.length,
814
976
  " span",
@@ -817,11 +979,11 @@ function ReportTrace({ spans }) {
817
979
  formatDuration(totalMs),
818
980
  ")"
819
981
  ] }),
820
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
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) => {
821
983
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
822
984
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
823
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: "flex items-center gap-2", children: [
824
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
985
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex items-center gap-2", children: [
986
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
825
987
  "span",
826
988
  {
827
989
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -830,14 +992,14 @@ function ReportTrace({ spans }) {
830
992
  children: row.name
831
993
  }
832
994
  ),
833
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
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)(
834
996
  "span",
835
997
  {
836
998
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
837
999
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
838
1000
  }
839
1001
  ) }),
840
- /* @__PURE__ */ (0, import_jsx_runtime20.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) })
841
1003
  ] }, `${row.spanId}-${i}`);
842
1004
  }) })
843
1005
  ] });
@@ -888,7 +1050,7 @@ function flakinessOf(entries) {
888
1050
  }
889
1051
 
890
1052
  // src/components/ScenarioRunHistory.tsx
891
- var import_jsx_runtime21 = require("react/jsx-runtime");
1053
+ var import_jsx_runtime22 = require("react/jsx-runtime");
892
1054
  var MAX_DOTS = 10;
893
1055
  var DOT_COLOR = {
894
1056
  passed: "bg-pass",
@@ -908,16 +1070,16 @@ function ScenarioRunHistory({ scenarioId }) {
908
1070
  const recent = entries.slice(-MAX_DOTS);
909
1071
  const flaky = flakinessOf(recent) === "flaky";
910
1072
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
911
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
912
- flaky ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
913
- /* @__PURE__ */ (0, import_jsx_runtime21.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)(
914
1076
  "span",
915
1077
  {
916
1078
  role: "img",
917
1079
  "aria-label": `Run history: ${summary}`,
918
1080
  title: summary,
919
1081
  className: "flex shrink-0 items-center gap-[3px]",
920
- children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1082
+ children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
921
1083
  "span",
922
1084
  {
923
1085
  "aria-hidden": true,
@@ -956,9 +1118,9 @@ function useScenarioActions() {
956
1118
 
957
1119
  // src/components/ui/card.tsx
958
1120
  var React2 = require("react");
959
- var import_jsx_runtime22 = require("react/jsx-runtime");
1121
+ var import_jsx_runtime23 = require("react/jsx-runtime");
960
1122
  function Card({ className, ...props }) {
961
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1123
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
962
1124
  "div",
963
1125
  {
964
1126
  "data-slot": "card",
@@ -971,7 +1133,7 @@ function Card({ className, ...props }) {
971
1133
  );
972
1134
  }
973
1135
  function CardHeader({ className, ...props }) {
974
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1136
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
975
1137
  "div",
976
1138
  {
977
1139
  "data-slot": "card-header",
@@ -984,7 +1146,7 @@ function CardHeader({ className, ...props }) {
984
1146
  );
985
1147
  }
986
1148
  function CardContent({ className, ...props }) {
987
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1149
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
988
1150
  "div",
989
1151
  {
990
1152
  "data-slot": "card-content",
@@ -998,13 +1160,13 @@ function CardContent({ className, ...props }) {
998
1160
  var React3 = require("react");
999
1161
  var import_menu = require("@base-ui/react/menu");
1000
1162
  var import_lucide_react = require("lucide-react");
1001
- var import_jsx_runtime23 = require("react/jsx-runtime");
1163
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1002
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";
1003
1165
  function DropdownMenu(props) {
1004
- return /* @__PURE__ */ (0, import_jsx_runtime23.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 });
1005
1167
  }
1006
1168
  function DropdownMenuTrigger(props) {
1007
- return /* @__PURE__ */ (0, import_jsx_runtime23.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 });
1008
1170
  }
1009
1171
  function DropdownMenuContent({
1010
1172
  className,
@@ -1012,14 +1174,14 @@ function DropdownMenuContent({
1012
1174
  sideOffset = 4,
1013
1175
  ...props
1014
1176
  }) {
1015
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1177
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1016
1178
  import_menu.Menu.Positioner,
1017
1179
  {
1018
1180
  "data-slot": "dropdown-menu-positioner",
1019
1181
  className: "z-50",
1020
1182
  align,
1021
1183
  sideOffset,
1022
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1184
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1023
1185
  import_menu.Menu.Popup,
1024
1186
  {
1025
1187
  "data-slot": "dropdown-menu-content",
@@ -1037,7 +1199,7 @@ function DropdownMenuItem({
1037
1199
  className,
1038
1200
  ...props
1039
1201
  }) {
1040
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1202
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1041
1203
  import_menu.Menu.Item,
1042
1204
  {
1043
1205
  "data-slot": "dropdown-menu-item",
@@ -1049,7 +1211,7 @@ function DropdownMenuItem({
1049
1211
 
1050
1212
  // src/components/ReportScenario.tsx
1051
1213
  var import_lucide_react2 = require("lucide-react");
1052
- var import_jsx_runtime24 = require("react/jsx-runtime");
1214
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1053
1215
  var STATUS_META = {
1054
1216
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
1055
1217
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -1065,7 +1227,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
1065
1227
  const collapsible = collapse !== null && !hideTitle;
1066
1228
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
1067
1229
  const actions = useScenarioActions();
1068
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1230
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1069
1231
  Card,
1070
1232
  {
1071
1233
  id: scenario.id,
@@ -1073,10 +1235,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
1073
1235
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
1074
1236
  className: "gap-0 py-0",
1075
1237
  children: [
1076
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CardHeader, { className: "px-4 py-3", children: [
1077
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1078
- hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1079
- collapsible ? /* @__PURE__ */ (0, import_jsx_runtime24.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)(
1080
1242
  "button",
1081
1243
  {
1082
1244
  type: "button",
@@ -1085,49 +1247,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
1085
1247
  "aria-controls": bodyId,
1086
1248
  "aria-label": `Toggle ${scenario.title}`,
1087
1249
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1088
- children: /* @__PURE__ */ (0, import_jsx_runtime24.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" })
1089
1251
  }
1090
1252
  ) : null,
1091
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1092
- /* @__PURE__ */ (0, import_jsx_runtime24.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 })
1093
1255
  ] }),
1094
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1095
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1096
- scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1097
- meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1098
- actions ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenu, { children: [
1099
- /* @__PURE__ */ (0, import_jsx_runtime24.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)(
1100
1262
  DropdownMenuTrigger,
1101
1263
  {
1102
1264
  "aria-label": `Actions for ${scenario.title}`,
1103
1265
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1104
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1266
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1105
1267
  }
1106
1268
  ),
1107
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuContent, { align: "end", children: [
1108
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1109
- /* @__PURE__ */ (0, import_jsx_runtime24.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, {}),
1110
1272
  " Copy link"
1111
1273
  ] }),
1112
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1113
- /* @__PURE__ */ (0, import_jsx_runtime24.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, {}),
1114
1276
  " Copy as Markdown"
1115
1277
  ] }),
1116
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1117
- /* @__PURE__ */ (0, import_jsx_runtime24.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, {}),
1118
1280
  " Explain with AI"
1119
1281
  ] })
1120
1282
  ] })
1121
1283
  ] }) : null
1122
1284
  ] })
1123
1285
  ] }),
1124
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1125
- scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1126
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
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}`))
1127
1289
  ] }) : null
1128
1290
  ] }),
1129
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1130
- scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime24.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)(
1131
1293
  "pre",
1132
1294
  {
1133
1295
  role: "alert",
@@ -1135,11 +1297,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
1135
1297
  children: scenario.errorMessage
1136
1298
  }
1137
1299
  ) : null,
1138
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportStoryboard, { scenario }),
1139
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportSteps, { scenario }),
1140
- scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1141
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1142
- /* @__PURE__ */ (0, import_jsx_runtime24.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 })
1143
1305
  ] })
1144
1306
  ]
1145
1307
  }
@@ -1147,13 +1309,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1147
1309
  }
1148
1310
 
1149
1311
  // src/components/ReportScenarioList.tsx
1150
- var import_jsx_runtime25 = require("react/jsx-runtime");
1312
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1151
1313
  function ReportScenarioList({ feature }) {
1152
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenario, { scenario }, scenario.id)) });
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)) });
1153
1315
  }
1154
1316
 
1155
1317
  // src/components/ReportFeature.tsx
1156
- var import_jsx_runtime26 = require("react/jsx-runtime");
1318
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1157
1319
  function ReportFeature({ feature }) {
1158
1320
  const titleId = `${feature.id}-title`;
1159
1321
  const bodyId = `${feature.id}-body`;
@@ -1164,7 +1326,7 @@ function ReportFeature({ feature }) {
1164
1326
  return (
1165
1327
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1166
1328
  // layer of nesting so the scenario cards below read as the primary unit.
1167
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1329
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1168
1330
  "section",
1169
1331
  {
1170
1332
  id: feature.id,
@@ -1172,9 +1334,9 @@ function ReportFeature({ feature }) {
1172
1334
  "aria-labelledby": titleId,
1173
1335
  className: "flex flex-col gap-3",
1174
1336
  children: [
1175
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1176
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "min-w-0", children: [
1177
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
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)(
1178
1340
  "button",
1179
1341
  {
1180
1342
  type: "button",
@@ -1183,31 +1345,31 @@ function ReportFeature({ feature }) {
1183
1345
  "aria-controls": bodyId,
1184
1346
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1185
1347
  children: [
1186
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1187
- /* @__PURE__ */ (0, import_jsx_runtime26.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 })
1188
1350
  ]
1189
1351
  }
1190
1352
  ) : feature.title }),
1191
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
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 })
1192
1354
  ] }),
1193
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1355
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1194
1356
  "p",
1195
1357
  {
1196
1358
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1197
1359
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1198
1360
  children: [
1199
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { children: [
1361
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
1200
1362
  s.passed,
1201
1363
  " passed"
1202
1364
  ] }),
1203
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1204
- /* @__PURE__ */ (0, import_jsx_runtime26.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: [
1205
1367
  s.failed,
1206
1368
  " failed"
1207
1369
  ] }),
1208
- skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
1209
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1210
- /* @__PURE__ */ (0, import_jsx_runtime26.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: [
1211
1373
  skipped,
1212
1374
  " skipped"
1213
1375
  ] })
@@ -1216,7 +1378,7 @@ function ReportFeature({ feature }) {
1216
1378
  }
1217
1379
  )
1218
1380
  ] }),
1219
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenarioList, { feature }) })
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 }) })
1220
1382
  ]
1221
1383
  }
1222
1384
  )
@@ -1224,17 +1386,17 @@ function ReportFeature({ feature }) {
1224
1386
  }
1225
1387
 
1226
1388
  // src/components/ReportFeatureList.tsx
1227
- var import_jsx_runtime27 = require("react/jsx-runtime");
1389
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1228
1390
  function ReportFeatureList() {
1229
1391
  const report = useReport();
1230
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportFeature, { feature }, feature.id)) });
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)) });
1231
1393
  }
1232
1394
 
1233
1395
  // src/components/ui/empty.tsx
1234
1396
  var import_class_variance_authority2 = require("class-variance-authority");
1235
- var import_jsx_runtime28 = require("react/jsx-runtime");
1397
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1236
1398
  function Empty({ className, ...props }) {
1237
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1399
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1238
1400
  "div",
1239
1401
  {
1240
1402
  "data-slot": "empty",
@@ -1247,7 +1409,7 @@ function Empty({ className, ...props }) {
1247
1409
  );
1248
1410
  }
1249
1411
  function EmptyHeader({ className, ...props }) {
1250
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1412
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1251
1413
  "div",
1252
1414
  {
1253
1415
  "data-slot": "empty-header",
@@ -1274,7 +1436,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
1274
1436
  }
1275
1437
  );
1276
1438
  function EmptyTitle({ className, ...props }) {
1277
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1439
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1278
1440
  "div",
1279
1441
  {
1280
1442
  "data-slot": "empty-title",
@@ -1285,16 +1447,16 @@ function EmptyTitle({ className, ...props }) {
1285
1447
  }
1286
1448
 
1287
1449
  // src/components/ReportEmpty.tsx
1288
- var import_jsx_runtime29 = require("react/jsx-runtime");
1450
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1289
1451
  function ReportEmpty({ message }) {
1290
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
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." }) }) });
1291
1453
  }
1292
1454
 
1293
1455
  // src/components/ReportSummary.tsx
1294
- var import_jsx_runtime30 = require("react/jsx-runtime");
1456
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1295
1457
  function ReportSummary({ className }) {
1296
1458
  const report = useReport();
1297
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1459
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1298
1460
  ReportSummaryView,
1299
1461
  {
1300
1462
  summary: report.summary,
@@ -1320,7 +1482,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1320
1482
  if (summary.pending > 0) {
1321
1483
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1322
1484
  }
1323
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1485
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1324
1486
  "dl",
1325
1487
  {
1326
1488
  className: cn(
@@ -1333,17 +1495,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1333
1495
  "aria-label": ariaLabel,
1334
1496
  children: cards.map((c) => {
1335
1497
  const tone = TONE[c.status];
1336
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1498
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1337
1499
  "div",
1338
1500
  {
1339
1501
  "data-status": c.status,
1340
1502
  className: "rounded-lg border bg-card px-4 py-3",
1341
1503
  children: [
1342
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1343
- /* @__PURE__ */ (0, import_jsx_runtime30.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" }),
1344
1506
  c.label
1345
1507
  ] }),
1346
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
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 })
1347
1509
  ]
1348
1510
  },
1349
1511
  c.status
@@ -1403,7 +1565,7 @@ function prUrl(ci) {
1403
1565
  }
1404
1566
 
1405
1567
  // src/components/ReportMeta.tsx
1406
- var import_jsx_runtime31 = require("react/jsx-runtime");
1568
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1407
1569
  function ReportMeta() {
1408
1570
  const report = useReport();
1409
1571
  const items = [];
@@ -1426,13 +1588,13 @@ function ReportMeta() {
1426
1588
  const short = sha.slice(0, 8);
1427
1589
  items.push({
1428
1590
  label: "Commit",
1429
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime31.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
1430
1592
  });
1431
1593
  }
1432
1594
  if (report.ci) {
1433
1595
  items.push({
1434
1596
  label: "CI",
1435
- value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime31.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: [
1436
1598
  ciDisplayName(report.ci.name),
1437
1599
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1438
1600
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1443,7 +1605,7 @@ function ReportMeta() {
1443
1605
  const label = `#${report.ci.prNumber}`;
1444
1606
  items.push({
1445
1607
  label: "PR",
1446
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime31.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
1447
1609
  });
1448
1610
  }
1449
1611
  if (items.length === 0) return null;
@@ -1451,48 +1613,48 @@ function ReportMeta() {
1451
1613
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1452
1614
  // collapsed disclosure so it doesn't push the result down. Native <details>
1453
1615
  // so it works with no JS (the SSR/no-hydration report still toggles).
1454
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1455
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1456
- /* @__PURE__ */ (0, import_jsx_runtime31.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" }),
1457
1619
  "Run details"
1458
1620
  ] }),
1459
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1460
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dt", { className: "font-medium", children: item.label }),
1461
- /* @__PURE__ */ (0, import_jsx_runtime31.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 })
1462
1624
  ] }, item.label)) })
1463
1625
  ] })
1464
1626
  );
1465
1627
  }
1466
1628
 
1467
1629
  // src/components/ReportSchemaError.tsx
1468
- var import_jsx_runtime32 = require("react/jsx-runtime");
1630
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1469
1631
  function ReportSchemaError({ error }) {
1470
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1471
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("strong", { children: "Report could not be displayed." }) }),
1472
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { children: error.message }),
1473
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime32.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: [
1474
1636
  "The report bundle is newer than this version of ",
1475
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("code", { children: "executable-stories-react" }),
1637
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("code", { children: "executable-stories-react" }),
1476
1638
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1477
1639
  ] }) : null,
1478
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { children: [
1479
- /* @__PURE__ */ (0, import_jsx_runtime32.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: [
1480
1642
  error.issues.length,
1481
1643
  " validation issue",
1482
1644
  error.issues.length === 1 ? "" : "s"
1483
1645
  ] }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime32.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") })
1485
1647
  ] }) : null
1486
1648
  ] });
1487
1649
  }
1488
1650
 
1489
1651
  // src/components/ReportShell.tsx
1490
- var import_jsx_runtime33 = require("react/jsx-runtime");
1652
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1491
1653
  function ReportTitleBlock({ title }) {
1492
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
1493
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h1", { children: title ?? "Story Report" }),
1494
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportSummary, {}),
1495
- /* @__PURE__ */ (0, import_jsx_runtime33.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, {})
1496
1658
  ] });
1497
1659
  }
1498
1660
  function ReportErrorShell({
@@ -1501,28 +1663,28 @@ function ReportErrorShell({
1501
1663
  title,
1502
1664
  dataTheme
1503
1665
  }) {
1504
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportSchemaError, { error }) });
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 }) });
1505
1667
  }
1506
1668
 
1507
1669
  // src/components/Report.tsx
1508
- var import_jsx_runtime34 = require("react/jsx-runtime");
1670
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1509
1671
  function Report(props) {
1510
1672
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1511
1673
  const result = unwrapReport(report);
1512
1674
  if (!result.ok) {
1513
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1675
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1514
1676
  }
1515
1677
  const data = result.data;
1516
1678
  const hasContent = data.features.length > 0;
1517
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1518
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportTitleBlock, { title }) }),
1519
- hasContent ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime34.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, {})
1520
1682
  ] }) });
1521
1683
  }
1522
1684
 
1523
1685
  // src/components/doc/MermaidView.tsx
1524
1686
  var import_react8 = require("react");
1525
- var import_jsx_runtime35 = require("react/jsx-runtime");
1687
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1526
1688
  function prefersDark(el) {
1527
1689
  const themed = el?.closest("[data-theme]");
1528
1690
  if (themed?.dataset.theme === "dark") return true;
@@ -1559,9 +1721,9 @@ function MermaidView({ entry, load }) {
1559
1721
  };
1560
1722
  }, [entry.code, load]);
1561
1723
  if (svg) {
1562
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("figure", { ref, className: "my-3", children: [
1563
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1564
- /* @__PURE__ */ (0, import_jsx_runtime35.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)(
1565
1727
  "div",
1566
1728
  {
1567
1729
  role: "img",
@@ -1572,18 +1734,18 @@ function MermaidView({ entry, load }) {
1572
1734
  )
1573
1735
  ] });
1574
1736
  }
1575
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MermaidSource, { entry, ref });
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MermaidSource, { entry, ref });
1576
1738
  }
1577
1739
 
1578
1740
  // src/components/doc/MermaidDiagram.tsx
1579
- var import_jsx_runtime36 = require("react/jsx-runtime");
1741
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1580
1742
  var mermaidLoader;
1581
1743
  function loadMermaid() {
1582
1744
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1583
1745
  return mermaidLoader;
1584
1746
  }
1585
1747
  function MermaidDiagram({ entry, load = loadMermaid }) {
1586
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MermaidView, { entry, load });
1748
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MermaidView, { entry, load });
1587
1749
  }
1588
1750
 
1589
1751
  // src/components/ScenarioExplorer.tsx
@@ -1593,12 +1755,12 @@ var import_react9 = require("react");
1593
1755
  var React4 = require("react");
1594
1756
  var import_cmdk = require("cmdk");
1595
1757
  var import_lucide_react3 = require("lucide-react");
1596
- var import_jsx_runtime37 = require("react/jsx-runtime");
1758
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1597
1759
  function Command({
1598
1760
  className,
1599
1761
  ...props
1600
1762
  }) {
1601
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1763
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1602
1764
  import_cmdk.Command,
1603
1765
  {
1604
1766
  "data-slot": "command",
@@ -1614,14 +1776,14 @@ function CommandInput({
1614
1776
  className,
1615
1777
  ...props
1616
1778
  }) {
1617
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1779
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
1618
1780
  "div",
1619
1781
  {
1620
1782
  "data-slot": "command-input-wrapper",
1621
1783
  className: "flex h-9 items-center gap-2 border-b px-3",
1622
1784
  children: [
1623
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1624
- /* @__PURE__ */ (0, import_jsx_runtime37.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)(
1625
1787
  import_cmdk.Command.Input,
1626
1788
  {
1627
1789
  "data-slot": "command-input",
@@ -1640,7 +1802,7 @@ function CommandList({
1640
1802
  className,
1641
1803
  ...props
1642
1804
  }) {
1643
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1805
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1644
1806
  import_cmdk.Command.List,
1645
1807
  {
1646
1808
  "data-slot": "command-list",
@@ -1655,7 +1817,7 @@ function CommandList({
1655
1817
  function CommandEmpty({
1656
1818
  ...props
1657
1819
  }) {
1658
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1820
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1659
1821
  import_cmdk.Command.Empty,
1660
1822
  {
1661
1823
  "data-slot": "command-empty",
@@ -1668,7 +1830,7 @@ function CommandGroup({
1668
1830
  className,
1669
1831
  ...props
1670
1832
  }) {
1671
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1833
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1672
1834
  import_cmdk.Command.Group,
1673
1835
  {
1674
1836
  "data-slot": "command-group",
@@ -1684,7 +1846,7 @@ function CommandItem({
1684
1846
  className,
1685
1847
  ...props
1686
1848
  }) {
1687
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1849
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1688
1850
  import_cmdk.Command.Item,
1689
1851
  {
1690
1852
  "data-slot": "command-item",
@@ -1698,7 +1860,7 @@ function CommandItem({
1698
1860
  }
1699
1861
 
1700
1862
  // src/components/ScenarioExplorer.tsx
1701
- var import_jsx_runtime38 = require("react/jsx-runtime");
1863
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1702
1864
  var STATUS_FILTERS = [
1703
1865
  { value: "all", label: "All" },
1704
1866
  { value: "passed", label: "Passed" },
@@ -1709,22 +1871,22 @@ var STATUS_FILTERS = [
1709
1871
  function ScenarioExplorer({ scenarios, summary }) {
1710
1872
  const [status, setStatus] = (0, import_react9.useState)("all");
1711
1873
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1712
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "font-sans text-foreground", children: [
1713
- summary ? /* @__PURE__ */ (0, import_jsx_runtime38.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: [
1714
1876
  summary.total,
1715
1877
  " scenarios \xB7 ",
1716
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "text-pass", children: [
1878
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-pass", children: [
1717
1879
  summary.passed,
1718
1880
  " passed"
1719
1881
  ] }),
1720
1882
  " \xB7",
1721
1883
  " ",
1722
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "text-fail", children: [
1884
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-fail", children: [
1723
1885
  summary.failed,
1724
1886
  " failed"
1725
1887
  ] })
1726
1888
  ] }) : null,
1727
- /* @__PURE__ */ (0, import_jsx_runtime38.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_runtime38.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)(
1728
1890
  "button",
1729
1891
  {
1730
1892
  type: "button",
@@ -1739,26 +1901,26 @@ function ScenarioExplorer({ scenarios, summary }) {
1739
1901
  },
1740
1902
  f.value
1741
1903
  )) }),
1742
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
1904
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
1743
1905
  Command,
1744
1906
  {
1745
1907
  className: "rounded-lg border border-border bg-card",
1746
1908
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1747
1909
  children: [
1748
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
1749
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(CommandList, { className: "max-h-none", children: [
1750
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
1751
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime38.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)(
1752
1914
  CommandItem,
1753
1915
  {
1754
1916
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1755
1917
  asChild: true,
1756
1918
  className: "cursor-pointer",
1757
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
1758
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Badge, { variant: s.status, children: s.status }),
1759
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1760
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1761
- /* @__PURE__ */ (0, import_jsx_runtime38.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 })
1762
1924
  ] })
1763
1925
  },
1764
1926
  s.id
@@ -2254,6 +2416,9 @@ var story_report_v1_default = {
2254
2416
  {
2255
2417
  $ref: "#/$defs/DocHtml"
2256
2418
  },
2419
+ {
2420
+ $ref: "#/$defs/DocState"
2421
+ },
2257
2422
  {
2258
2423
  $ref: "#/$defs/DocCustom"
2259
2424
  }
@@ -2629,6 +2794,33 @@ var story_report_v1_default = {
2629
2794
  }
2630
2795
  ]
2631
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
+ },
2632
2824
  DocCustom: {
2633
2825
  type: "object",
2634
2826
  properties: {