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.js CHANGED
@@ -216,7 +216,7 @@ function DocLink({ entry }) {
216
216
  // src/components/doc/DocSection.tsx
217
217
  import { marked } from "marked";
218
218
 
219
- // src/lib/url.ts
219
+ // ../executable-stories-core/dist/utils/url.js
220
220
  function safeUrl(value) {
221
221
  if (!value) return void 0;
222
222
  const trimmed = value.trim();
@@ -374,17 +374,29 @@ function DocHtml({ entry }) {
374
374
  ] });
375
375
  }
376
376
 
377
+ // src/components/doc/DocState.tsx
378
+ import { jsx as jsx13 } from "react/jsx-runtime";
379
+ function DocState({ entry }) {
380
+ let json;
381
+ try {
382
+ json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);
383
+ } catch {
384
+ json = String(entry.value);
385
+ }
386
+ return /* @__PURE__ */ jsx13(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx13("code", { className: "font-mono text-xs language-json", children: json }) });
387
+ }
388
+
377
389
  // src/components/doc/DocCustom.tsx
378
- import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
390
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
379
391
  function DocCustom({ entry }) {
380
392
  const renderers = useCustomRenderers();
381
393
  const renderer = renderers[entry.type];
382
394
  if (renderer) {
383
- return /* @__PURE__ */ jsx13(Fragment4, { children: renderer(entry) });
395
+ return /* @__PURE__ */ jsx14(Fragment4, { children: renderer(entry) });
384
396
  }
385
397
  return /* @__PURE__ */ jsxs9("div", { className: "my-2", "data-type": entry.type, children: [
386
- /* @__PURE__ */ jsx13("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
387
- /* @__PURE__ */ jsx13("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
398
+ /* @__PURE__ */ jsx14("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
399
+ /* @__PURE__ */ jsx14("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
388
400
  ] });
389
401
  }
390
402
  function safeStringify(value) {
@@ -396,45 +408,47 @@ function safeStringify(value) {
396
408
  }
397
409
 
398
410
  // src/components/doc/DocEntry.tsx
399
- import { jsx as jsx14 } from "react/jsx-runtime";
411
+ import { jsx as jsx15 } from "react/jsx-runtime";
400
412
  function DocEntry({ entry }) {
401
413
  switch (entry.kind) {
402
414
  case "note":
403
- return /* @__PURE__ */ jsx14(DocNote, { entry });
415
+ return /* @__PURE__ */ jsx15(DocNote, { entry });
404
416
  case "tag":
405
- return /* @__PURE__ */ jsx14(DocTag, { entry });
417
+ return /* @__PURE__ */ jsx15(DocTag, { entry });
406
418
  case "kv":
407
- return /* @__PURE__ */ jsx14(DocKv, { entry });
419
+ return /* @__PURE__ */ jsx15(DocKv, { entry });
408
420
  case "code":
409
- return /* @__PURE__ */ jsx14(DocCode, { entry });
421
+ return /* @__PURE__ */ jsx15(DocCode, { entry });
410
422
  case "table":
411
- return /* @__PURE__ */ jsx14(DocTable, { entry });
423
+ return /* @__PURE__ */ jsx15(DocTable, { entry });
412
424
  case "link":
413
- return /* @__PURE__ */ jsx14(DocLink, { entry });
425
+ return /* @__PURE__ */ jsx15(DocLink, { entry });
414
426
  case "section":
415
- return /* @__PURE__ */ jsx14(DocSection, { entry });
427
+ return /* @__PURE__ */ jsx15(DocSection, { entry });
416
428
  case "mermaid":
417
- return /* @__PURE__ */ jsx14(DocMermaid, { entry });
429
+ return /* @__PURE__ */ jsx15(DocMermaid, { entry });
418
430
  case "screenshot":
419
- return /* @__PURE__ */ jsx14(DocScreenshot, { entry });
431
+ return /* @__PURE__ */ jsx15(DocScreenshot, { entry });
420
432
  case "video":
421
- return /* @__PURE__ */ jsx14(DocVideo, { entry });
433
+ return /* @__PURE__ */ jsx15(DocVideo, { entry });
422
434
  case "html":
423
- return /* @__PURE__ */ jsx14(DocHtml, { entry });
435
+ return /* @__PURE__ */ jsx15(DocHtml, { entry });
436
+ case "state":
437
+ return /* @__PURE__ */ jsx15(DocState, { entry });
424
438
  case "custom":
425
- return /* @__PURE__ */ jsx14(DocCustom, { entry });
439
+ return /* @__PURE__ */ jsx15(DocCustom, { entry });
426
440
  }
427
441
  }
428
442
 
429
443
  // src/components/ReportDocEntries.tsx
430
- import { Fragment as Fragment5, jsx as jsx15 } from "react/jsx-runtime";
444
+ import { Fragment as Fragment5, jsx as jsx16 } from "react/jsx-runtime";
431
445
  function ReportDocEntries({ entries }) {
432
446
  if (entries.length === 0) return null;
433
- return /* @__PURE__ */ jsx15(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx15(DocEntry, { entry }, i)) });
447
+ return /* @__PURE__ */ jsx16(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx16(DocEntry, { entry }, i)) });
434
448
  }
435
449
 
436
450
  // src/lib/step-params.tsx
437
- import { jsx as jsx16 } from "react/jsx-runtime";
451
+ import { jsx as jsx17 } from "react/jsx-runtime";
438
452
  var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
439
453
  function highlightStepParams(text) {
440
454
  const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
@@ -446,7 +460,7 @@ function highlightStepParams(text) {
446
460
  const end = start + match[0].length;
447
461
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
448
462
  nodes.push(
449
- /* @__PURE__ */ jsx16("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
463
+ /* @__PURE__ */ jsx17("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
450
464
  );
451
465
  lastIndex = end;
452
466
  });
@@ -455,7 +469,7 @@ function highlightStepParams(text) {
455
469
  }
456
470
 
457
471
  // src/components/ReportSteps.tsx
458
- import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
472
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
459
473
  var STEP_GLYPH = {
460
474
  passed: "\u2713",
461
475
  failed: "\u2717",
@@ -470,7 +484,7 @@ var STEP_GLYPH_COLOR = {
470
484
  };
471
485
  function ReportSteps({ scenario }) {
472
486
  if (scenario.steps.length === 0) return null;
473
- return /* @__PURE__ */ jsx17("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx17(ReportStepItem, { step }, step.id)) });
487
+ return /* @__PURE__ */ jsx18("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx18(ReportStepItem, { step }, step.id)) });
474
488
  }
475
489
  function ReportStepItem({ step }) {
476
490
  const kw = step.keyword.toLowerCase();
@@ -483,8 +497,8 @@ function ReportStepItem({ step }) {
483
497
  className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
484
498
  children: [
485
499
  /* @__PURE__ */ jsxs10("div", { className: "flex items-baseline gap-2", children: [
486
- /* @__PURE__ */ jsx17("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" }),
487
- /* @__PURE__ */ jsx17(
500
+ /* @__PURE__ */ jsx18("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" }),
501
+ /* @__PURE__ */ jsx18(
488
502
  "span",
489
503
  {
490
504
  className: cn(
@@ -494,10 +508,10 @@ function ReportStepItem({ step }) {
494
508
  children: step.keyword
495
509
  }
496
510
  ),
497
- /* @__PURE__ */ jsx17("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
498
- step.durationMs > 0 ? /* @__PURE__ */ jsx17("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
511
+ /* @__PURE__ */ jsx18("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
512
+ step.durationMs > 0 ? /* @__PURE__ */ jsx18("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
499
513
  ] }),
500
- step.errorMessage ? /* @__PURE__ */ jsx17(
514
+ step.errorMessage ? /* @__PURE__ */ jsx18(
501
515
  "pre",
502
516
  {
503
517
  role: "alert",
@@ -505,24 +519,255 @@ function ReportStepItem({ step }) {
505
519
  children: step.errorMessage
506
520
  }
507
521
  ) : null,
508
- step.docEntries.length > 0 ? /* @__PURE__ */ jsx17("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx17(ReportDocEntries, { entries: step.docEntries }) }) : null
522
+ step.docEntries.length > 0 ? /* @__PURE__ */ jsx18("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx18(ReportDocEntries, { entries: step.docEntries }) }) : null
509
523
  ]
510
524
  }
511
525
  );
512
526
  }
513
527
 
528
+ // ../executable-stories-core/dist/state-diff.js
529
+ var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
530
+ function deepEqual(a, b) {
531
+ if (Object.is(a, b)) return true;
532
+ if (Array.isArray(a) && Array.isArray(b)) {
533
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
534
+ }
535
+ if (isPlainObject(a) && isPlainObject(b)) {
536
+ const ak = Object.keys(a);
537
+ const bk = Object.keys(b);
538
+ return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
539
+ }
540
+ return false;
541
+ }
542
+ var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
543
+ function walk(path, before, after, out) {
544
+ if (Object.is(before, after)) return;
545
+ if (Array.isArray(before) && Array.isArray(after)) {
546
+ const shared = Math.min(before.length, after.length);
547
+ for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
548
+ for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
549
+ for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
550
+ return;
551
+ }
552
+ if (isPlainObject(before) && isPlainObject(after)) {
553
+ for (const key of Object.keys(after)) {
554
+ const p = joinKey(path, key);
555
+ if (key in before) walk(p, before[key], after[key], out);
556
+ else out.push({ path: p, kind: "added", after: after[key] });
557
+ }
558
+ for (const key of Object.keys(before)) {
559
+ if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
560
+ }
561
+ return;
562
+ }
563
+ if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
564
+ }
565
+ function diffStateValues(before, after) {
566
+ const out = [];
567
+ walk("", before, after, out);
568
+ return out;
569
+ }
570
+ function formatStateValue(value, maxLen = 60) {
571
+ const s = value === void 0 ? "undefined" : JSON.stringify(value);
572
+ return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
573
+ }
574
+ function summarizeStateChanges(changes) {
575
+ return changes.map((c) => {
576
+ const at = c.path === "" ? "(root)" : c.path;
577
+ switch (c.kind) {
578
+ case "added":
579
+ return `+ ${at}: ${formatStateValue(c.after)}`;
580
+ case "removed":
581
+ return `\u2212 ${at}`;
582
+ case "changed":
583
+ return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
584
+ }
585
+ });
586
+ }
587
+
588
+ // ../executable-stories-core/dist/storyboard.js
589
+ function findScreenshot(entries) {
590
+ for (const entry of entries) {
591
+ if (entry.kind === "screenshot") return entry;
592
+ if (entry.children) {
593
+ const nested = findScreenshot(entry.children);
594
+ if (nested) return nested;
595
+ }
596
+ }
597
+ return void 0;
598
+ }
599
+ function findStates(entries, out = []) {
600
+ for (const entry of entries) {
601
+ if (entry.kind === "state") out.push(entry);
602
+ if (entry.children) findStates(entry.children, out);
603
+ }
604
+ return out;
605
+ }
606
+ var laneOf = (label) => label ?? "";
607
+ function extractStoryboardFrames(scenario) {
608
+ const frames = [];
609
+ const laneOrder = [];
610
+ const previous = /* @__PURE__ */ new Map();
611
+ for (const step of scenario.steps) {
612
+ const shot = findScreenshot(step.docEntries);
613
+ const stateDocs = findStates(step.docEntries);
614
+ if (!shot && stateDocs.length === 0) continue;
615
+ const byLane = /* @__PURE__ */ new Map();
616
+ for (const doc of stateDocs) {
617
+ const lane = laneOf(doc.label);
618
+ if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
619
+ byLane.set(lane, doc);
620
+ }
621
+ const states = [];
622
+ for (const lane of laneOrder) {
623
+ const doc = byLane.get(lane);
624
+ if (!doc) continue;
625
+ const card = {
626
+ ...doc.label !== void 0 && { label: doc.label },
627
+ value: doc.value
628
+ };
629
+ if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
630
+ previous.set(lane, doc.value);
631
+ states.push(card);
632
+ }
633
+ frames.push({
634
+ stepId: step.id,
635
+ stepIndex: step.index,
636
+ keyword: step.keyword,
637
+ text: step.text,
638
+ status: step.status,
639
+ ...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
640
+ states
641
+ });
642
+ }
643
+ return frames;
644
+ }
645
+
646
+ // src/components/ReportStoryboard.tsx
647
+ import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
648
+ var FRAME_GLYPH = {
649
+ passed: "\u2713",
650
+ failed: "\u2717",
651
+ skipped: "\u25CB",
652
+ pending: "\u25CB"
653
+ };
654
+ var FRAME_GLYPH_COLOR = {
655
+ passed: "text-pass",
656
+ failed: "text-fail",
657
+ skipped: "text-skip",
658
+ pending: "text-pend"
659
+ };
660
+ function ReportStoryboard({ scenario }) {
661
+ const frames = extractStoryboardFrames(scenario);
662
+ if (frames.length < 2) return null;
663
+ return /* @__PURE__ */ jsxs11("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
664
+ /* @__PURE__ */ jsx19("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
665
+ /* @__PURE__ */ jsx19("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx19(StoryboardFrameItem, { frame }, frame.stepId)) })
666
+ ] });
667
+ }
668
+ function StoryboardFrameItem({ frame }) {
669
+ const label = `${frame.keyword} ${frame.text}`;
670
+ const hasStates = frame.states.length > 0;
671
+ const caption = /* @__PURE__ */ jsxs11("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
672
+ /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
673
+ /* @__PURE__ */ jsxs11("span", { className: "min-w-0", children: [
674
+ /* @__PURE__ */ jsx19("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
675
+ " ",
676
+ /* @__PURE__ */ jsx19("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
677
+ ] })
678
+ ] });
679
+ return (
680
+ // State cards need room for diff rows; screenshot-only frames keep the
681
+ // original narrow film-cell width (and DOM) unchanged.
682
+ /* @__PURE__ */ jsxs11("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
683
+ frame.screenshot ? /* @__PURE__ */ jsx19(FrameScreenshot, { frame, label }) : null,
684
+ hasStates ? /* @__PURE__ */ jsx19("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ jsx19(StateCardView, { card }, card.label ?? i)) }) : null,
685
+ frame.screenshot ? caption : (
686
+ // No screenshot means no image anchor, so the caption carries the
687
+ // jump-to-step link instead.
688
+ /* @__PURE__ */ jsx19("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
689
+ )
690
+ ] })
691
+ );
692
+ }
693
+ function FrameScreenshot({ frame, label }) {
694
+ const path = frame.screenshot?.path ?? "";
695
+ const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
696
+ return /* @__PURE__ */ jsx19(
697
+ "a",
698
+ {
699
+ href: `#${frame.stepId}`,
700
+ "aria-label": `Jump to step: ${label}`,
701
+ className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
702
+ children: src ? /* @__PURE__ */ jsx19(
703
+ "img",
704
+ {
705
+ src,
706
+ alt: frame.screenshot?.alt ?? label,
707
+ loading: "lazy",
708
+ className: "h-24 w-full bg-muted object-cover object-top"
709
+ }
710
+ ) : /* @__PURE__ */ jsx19("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" })
711
+ }
712
+ );
713
+ }
714
+ var CHANGE_TONE = {
715
+ added: "bg-pass-bg text-pass",
716
+ removed: "bg-fail-bg text-fail",
717
+ changed: "bg-skip-bg text-skip"
718
+ };
719
+ function prettyJson(value) {
720
+ try {
721
+ return JSON.stringify(value, null, 2) ?? String(value);
722
+ } catch {
723
+ return String(value);
724
+ }
725
+ }
726
+ function StateCardView({ card }) {
727
+ const json = prettyJson(card.value);
728
+ const firstCapture = card.changes === void 0;
729
+ return /* @__PURE__ */ jsxs11("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
730
+ /* @__PURE__ */ jsxs11("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
731
+ /* @__PURE__ */ jsx19("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" }),
732
+ firstCapture ? /* @__PURE__ */ jsx19("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
733
+ ] }),
734
+ !firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ jsx19("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ jsx19(
735
+ "li",
736
+ {
737
+ className: cn(
738
+ "rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
739
+ CHANGE_TONE[change.kind]
740
+ ),
741
+ children: summarizeStateChanges([change])[0]
742
+ },
743
+ i
744
+ )) }) : /* @__PURE__ */ jsx19("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
745
+ /* @__PURE__ */ jsxs11(
746
+ "details",
747
+ {
748
+ open: firstCapture && json.length <= 240,
749
+ className: cn(firstCapture ? "mt-1.5" : "mt-1"),
750
+ children: [
751
+ /* @__PURE__ */ jsx19("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
752
+ /* @__PURE__ */ jsx19("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 })
753
+ ]
754
+ }
755
+ )
756
+ ] });
757
+ }
758
+
514
759
  // src/components/ReportAttachments.tsx
515
- import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
760
+ import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
516
761
  function ReportAttachments({ attachments }) {
517
762
  if (attachments.length === 0) return null;
518
763
  return (
519
764
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
520
765
  // blocks don't create duplicate "Attachments" region landmarks.
521
- /* @__PURE__ */ jsx18("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
766
+ /* @__PURE__ */ jsx20("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
522
767
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
523
768
  const isImage = att.mediaType.startsWith("image/");
524
- return /* @__PURE__ */ jsx18("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
525
- /* @__PURE__ */ jsx18(
769
+ return /* @__PURE__ */ jsx20("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
770
+ /* @__PURE__ */ jsx20(
526
771
  "img",
527
772
  {
528
773
  src: dataUri,
@@ -531,8 +776,8 @@ function ReportAttachments({ attachments }) {
531
776
  className: "max-w-full rounded-md border border-border"
532
777
  }
533
778
  ),
534
- /* @__PURE__ */ jsx18("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
535
- ] }) : /* @__PURE__ */ jsxs11(
779
+ /* @__PURE__ */ jsx20("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
780
+ ] }) : /* @__PURE__ */ jsxs12(
536
781
  "a",
537
782
  {
538
783
  href: dataUri,
@@ -541,7 +786,7 @@ function ReportAttachments({ attachments }) {
541
786
  children: [
542
787
  att.name,
543
788
  " ",
544
- /* @__PURE__ */ jsxs11("span", { className: "text-muted-foreground", children: [
789
+ /* @__PURE__ */ jsxs12("span", { className: "text-muted-foreground", children: [
545
790
  "(",
546
791
  att.mediaType,
547
792
  ")"
@@ -605,15 +850,15 @@ function toTraceRows(spans) {
605
850
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
606
851
  const rows = [];
607
852
  const seen = /* @__PURE__ */ new Set();
608
- const walk = (node, depth) => {
853
+ const walk2 = (node, depth) => {
609
854
  if (seen.has(node.span.spanId)) return;
610
855
  seen.add(node.span.spanId);
611
856
  rows.push({ ...node.span, depth });
612
- for (const child of node.children) walk(child, depth + 1);
857
+ for (const child of node.children) walk2(child, depth + 1);
613
858
  };
614
- for (const root of roots) walk(root, 0);
859
+ for (const root of roots) walk2(root, 0);
615
860
  for (const node of byId.values()) {
616
- if (!seen.has(node.span.spanId)) walk(node, 0);
861
+ if (!seen.has(node.span.spanId)) walk2(node, 0);
617
862
  }
618
863
  return rows;
619
864
  }
@@ -629,7 +874,7 @@ function traceWindow(rows) {
629
874
  }
630
875
 
631
876
  // src/components/ReportTrace.tsx
632
- import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
877
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
633
878
  var BAR_COLOR = {
634
879
  ok: "bg-pass",
635
880
  error: "bg-fail",
@@ -640,8 +885,8 @@ function ReportTrace({ spans }) {
640
885
  const rows = toTraceRows(spans);
641
886
  if (rows.length === 0) return null;
642
887
  const { minStartMs, totalMs } = traceWindow(rows);
643
- return /* @__PURE__ */ jsxs12("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
644
- /* @__PURE__ */ jsxs12("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
888
+ return /* @__PURE__ */ jsxs13("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
889
+ /* @__PURE__ */ jsxs13("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
645
890
  "Trace (",
646
891
  rows.length,
647
892
  " span",
@@ -650,11 +895,11 @@ function ReportTrace({ spans }) {
650
895
  formatDuration(totalMs),
651
896
  ")"
652
897
  ] }),
653
- /* @__PURE__ */ jsx19("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
898
+ /* @__PURE__ */ jsx21("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
654
899
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
655
900
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
656
- return /* @__PURE__ */ jsxs12("li", { className: "flex items-center gap-2", children: [
657
- /* @__PURE__ */ jsx19(
901
+ return /* @__PURE__ */ jsxs13("li", { className: "flex items-center gap-2", children: [
902
+ /* @__PURE__ */ jsx21(
658
903
  "span",
659
904
  {
660
905
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -663,14 +908,14 @@ function ReportTrace({ spans }) {
663
908
  children: row.name
664
909
  }
665
910
  ),
666
- /* @__PURE__ */ jsx19("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx19(
911
+ /* @__PURE__ */ jsx21("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx21(
667
912
  "span",
668
913
  {
669
914
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
670
915
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
671
916
  }
672
917
  ) }),
673
- /* @__PURE__ */ jsx19("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
918
+ /* @__PURE__ */ jsx21("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
674
919
  ] }, `${row.spanId}-${i}`);
675
920
  }) })
676
921
  ] });
@@ -721,7 +966,7 @@ function flakinessOf(entries) {
721
966
  }
722
967
 
723
968
  // src/components/ScenarioRunHistory.tsx
724
- import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
969
+ import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
725
970
  var MAX_DOTS = 10;
726
971
  var DOT_COLOR = {
727
972
  passed: "bg-pass",
@@ -741,16 +986,16 @@ function ScenarioRunHistory({ scenarioId }) {
741
986
  const recent = entries.slice(-MAX_DOTS);
742
987
  const flaky = flakinessOf(recent) === "flaky";
743
988
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
744
- return /* @__PURE__ */ jsxs13(Fragment7, { children: [
745
- flaky ? /* @__PURE__ */ jsx20(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
746
- /* @__PURE__ */ jsx20(
989
+ return /* @__PURE__ */ jsxs14(Fragment7, { children: [
990
+ flaky ? /* @__PURE__ */ jsx22(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
991
+ /* @__PURE__ */ jsx22(
747
992
  "span",
748
993
  {
749
994
  role: "img",
750
995
  "aria-label": `Run history: ${summary}`,
751
996
  title: summary,
752
997
  className: "flex shrink-0 items-center gap-[3px]",
753
- children: recent.map((e, i) => /* @__PURE__ */ jsx20(
998
+ children: recent.map((e, i) => /* @__PURE__ */ jsx22(
754
999
  "span",
755
1000
  {
756
1001
  "aria-hidden": true,
@@ -789,9 +1034,9 @@ function useScenarioActions() {
789
1034
 
790
1035
  // src/components/ui/card.tsx
791
1036
  import "react";
792
- import { jsx as jsx21 } from "react/jsx-runtime";
1037
+ import { jsx as jsx23 } from "react/jsx-runtime";
793
1038
  function Card({ className, ...props }) {
794
- return /* @__PURE__ */ jsx21(
1039
+ return /* @__PURE__ */ jsx23(
795
1040
  "div",
796
1041
  {
797
1042
  "data-slot": "card",
@@ -804,7 +1049,7 @@ function Card({ className, ...props }) {
804
1049
  );
805
1050
  }
806
1051
  function CardHeader({ className, ...props }) {
807
- return /* @__PURE__ */ jsx21(
1052
+ return /* @__PURE__ */ jsx23(
808
1053
  "div",
809
1054
  {
810
1055
  "data-slot": "card-header",
@@ -817,7 +1062,7 @@ function CardHeader({ className, ...props }) {
817
1062
  );
818
1063
  }
819
1064
  function CardContent({ className, ...props }) {
820
- return /* @__PURE__ */ jsx21(
1065
+ return /* @__PURE__ */ jsx23(
821
1066
  "div",
822
1067
  {
823
1068
  "data-slot": "card-content",
@@ -831,13 +1076,13 @@ function CardContent({ className, ...props }) {
831
1076
  import "react";
832
1077
  import { Menu as MenuPrimitive } from "@base-ui/react/menu";
833
1078
  import { CheckIcon } from "lucide-react";
834
- import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1079
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
835
1080
  var itemClasses = "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground";
836
1081
  function DropdownMenu(props) {
837
- return /* @__PURE__ */ jsx22(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1082
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
838
1083
  }
839
1084
  function DropdownMenuTrigger(props) {
840
- return /* @__PURE__ */ jsx22(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1085
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
841
1086
  }
842
1087
  function DropdownMenuContent({
843
1088
  className,
@@ -845,14 +1090,14 @@ function DropdownMenuContent({
845
1090
  sideOffset = 4,
846
1091
  ...props
847
1092
  }) {
848
- return /* @__PURE__ */ jsx22(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx22(
1093
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx24(
849
1094
  MenuPrimitive.Positioner,
850
1095
  {
851
1096
  "data-slot": "dropdown-menu-positioner",
852
1097
  className: "z-50",
853
1098
  align,
854
1099
  sideOffset,
855
- children: /* @__PURE__ */ jsx22(
1100
+ children: /* @__PURE__ */ jsx24(
856
1101
  MenuPrimitive.Popup,
857
1102
  {
858
1103
  "data-slot": "dropdown-menu-content",
@@ -870,7 +1115,7 @@ function DropdownMenuItem({
870
1115
  className,
871
1116
  ...props
872
1117
  }) {
873
- return /* @__PURE__ */ jsx22(
1118
+ return /* @__PURE__ */ jsx24(
874
1119
  MenuPrimitive.Item,
875
1120
  {
876
1121
  "data-slot": "dropdown-menu-item",
@@ -882,7 +1127,7 @@ function DropdownMenuItem({
882
1127
 
883
1128
  // src/components/ReportScenario.tsx
884
1129
  import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
885
- import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1130
+ import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
886
1131
  var STATUS_META = {
887
1132
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
888
1133
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -898,7 +1143,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
898
1143
  const collapsible = collapse !== null && !hideTitle;
899
1144
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
900
1145
  const actions = useScenarioActions();
901
- return /* @__PURE__ */ jsxs15(
1146
+ return /* @__PURE__ */ jsxs16(
902
1147
  Card,
903
1148
  {
904
1149
  id: scenario.id,
@@ -906,10 +1151,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
906
1151
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
907
1152
  className: "gap-0 py-0",
908
1153
  children: [
909
- /* @__PURE__ */ jsxs15(CardHeader, { className: "px-4 py-3", children: [
910
- /* @__PURE__ */ jsxs15("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
911
- hideTitle ? null : /* @__PURE__ */ jsxs15("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
912
- collapsible ? /* @__PURE__ */ jsx23(
1154
+ /* @__PURE__ */ jsxs16(CardHeader, { className: "px-4 py-3", children: [
1155
+ /* @__PURE__ */ jsxs16("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1156
+ hideTitle ? null : /* @__PURE__ */ jsxs16("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1157
+ collapsible ? /* @__PURE__ */ jsx25(
913
1158
  "button",
914
1159
  {
915
1160
  type: "button",
@@ -918,49 +1163,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
918
1163
  "aria-controls": bodyId,
919
1164
  "aria-label": `Toggle ${scenario.title}`,
920
1165
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
921
- children: /* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1166
+ children: /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
922
1167
  }
923
1168
  ) : null,
924
- /* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
925
- /* @__PURE__ */ jsx23("span", { children: scenario.title })
1169
+ /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1170
+ /* @__PURE__ */ jsx25("span", { children: scenario.title })
926
1171
  ] }),
927
- /* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 items-center gap-2", children: [
928
- /* @__PURE__ */ jsx23(ScenarioRunHistory, { scenarioId: scenario.id }),
929
- scenario.durationMs > 0 ? /* @__PURE__ */ jsx23("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
930
- meta.showPill ? /* @__PURE__ */ jsx23(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx23("span", { className: "sr-only", children: `Status: ${label}` }),
931
- actions ? /* @__PURE__ */ jsxs15(DropdownMenu, { children: [
932
- /* @__PURE__ */ jsx23(
1172
+ /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2", children: [
1173
+ /* @__PURE__ */ jsx25(ScenarioRunHistory, { scenarioId: scenario.id }),
1174
+ scenario.durationMs > 0 ? /* @__PURE__ */ jsx25("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1175
+ meta.showPill ? /* @__PURE__ */ jsx25(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx25("span", { className: "sr-only", children: `Status: ${label}` }),
1176
+ actions ? /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
1177
+ /* @__PURE__ */ jsx25(
933
1178
  DropdownMenuTrigger,
934
1179
  {
935
1180
  "aria-label": `Actions for ${scenario.title}`,
936
1181
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
937
- children: /* @__PURE__ */ jsx23(MoreHorizontalIcon, { "aria-hidden": true })
1182
+ children: /* @__PURE__ */ jsx25(MoreHorizontalIcon, { "aria-hidden": true })
938
1183
  }
939
1184
  ),
940
- /* @__PURE__ */ jsxs15(DropdownMenuContent, { align: "end", children: [
941
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
942
- /* @__PURE__ */ jsx23(LinkIcon, {}),
1185
+ /* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", children: [
1186
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1187
+ /* @__PURE__ */ jsx25(LinkIcon, {}),
943
1188
  " Copy link"
944
1189
  ] }),
945
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
946
- /* @__PURE__ */ jsx23(FileTextIcon, {}),
1190
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1191
+ /* @__PURE__ */ jsx25(FileTextIcon, {}),
947
1192
  " Copy as Markdown"
948
1193
  ] }),
949
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
950
- /* @__PURE__ */ jsx23(SparklesIcon, {}),
1194
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1195
+ /* @__PURE__ */ jsx25(SparklesIcon, {}),
951
1196
  " Explain with AI"
952
1197
  ] })
953
1198
  ] })
954
1199
  ] }) : null
955
1200
  ] })
956
1201
  ] }),
957
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs15("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
958
- scenario.tags.map((t) => /* @__PURE__ */ jsx23("li", { children: /* @__PURE__ */ jsx23(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
959
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx23("li", { children: ticket.url ? /* @__PURE__ */ jsx23("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx23(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx23(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1202
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs16("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1203
+ scenario.tags.map((t) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1204
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx25("li", { children: ticket.url ? /* @__PURE__ */ jsx25("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
960
1205
  ] }) : null
961
1206
  ] }),
962
- /* @__PURE__ */ jsxs15(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
963
- scenario.errorMessage ? /* @__PURE__ */ jsx23(
1207
+ /* @__PURE__ */ jsxs16(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1208
+ scenario.errorMessage ? /* @__PURE__ */ jsx25(
964
1209
  "pre",
965
1210
  {
966
1211
  role: "alert",
@@ -968,10 +1213,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
968
1213
  children: scenario.errorMessage
969
1214
  }
970
1215
  ) : null,
971
- /* @__PURE__ */ jsx23(ReportSteps, { scenario }),
972
- scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx23("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx23(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
973
- /* @__PURE__ */ jsx23(ReportAttachments, { attachments: scenario.attachments }),
974
- /* @__PURE__ */ jsx23(ReportTrace, { spans: scenario.otelSpans })
1216
+ /* @__PURE__ */ jsx25(ReportStoryboard, { scenario }),
1217
+ /* @__PURE__ */ jsx25(ReportSteps, { scenario }),
1218
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx25("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx25(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1219
+ /* @__PURE__ */ jsx25(ReportAttachments, { attachments: scenario.attachments }),
1220
+ /* @__PURE__ */ jsx25(ReportTrace, { spans: scenario.otelSpans })
975
1221
  ] })
976
1222
  ]
977
1223
  }
@@ -979,13 +1225,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
979
1225
  }
980
1226
 
981
1227
  // src/components/ReportScenarioList.tsx
982
- import { Fragment as Fragment8, jsx as jsx24 } from "react/jsx-runtime";
1228
+ import { Fragment as Fragment8, jsx as jsx26 } from "react/jsx-runtime";
983
1229
  function ReportScenarioList({ feature }) {
984
- return /* @__PURE__ */ jsx24(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx24(ReportScenario, { scenario }, scenario.id)) });
1230
+ return /* @__PURE__ */ jsx26(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx26(ReportScenario, { scenario }, scenario.id)) });
985
1231
  }
986
1232
 
987
1233
  // src/components/ReportFeature.tsx
988
- import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
1234
+ import { Fragment as Fragment9, jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
989
1235
  function ReportFeature({ feature }) {
990
1236
  const titleId = `${feature.id}-title`;
991
1237
  const bodyId = `${feature.id}-body`;
@@ -996,7 +1242,7 @@ function ReportFeature({ feature }) {
996
1242
  return (
997
1243
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
998
1244
  // layer of nesting so the scenario cards below read as the primary unit.
999
- /* @__PURE__ */ jsxs16(
1245
+ /* @__PURE__ */ jsxs17(
1000
1246
  "section",
1001
1247
  {
1002
1248
  id: feature.id,
@@ -1004,9 +1250,9 @@ function ReportFeature({ feature }) {
1004
1250
  "aria-labelledby": titleId,
1005
1251
  className: "flex flex-col gap-3",
1006
1252
  children: [
1007
- /* @__PURE__ */ jsxs16("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1008
- /* @__PURE__ */ jsxs16("div", { className: "min-w-0", children: [
1009
- /* @__PURE__ */ jsx25("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs16(
1253
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1254
+ /* @__PURE__ */ jsxs17("div", { className: "min-w-0", children: [
1255
+ /* @__PURE__ */ jsx27("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
1010
1256
  "button",
1011
1257
  {
1012
1258
  type: "button",
@@ -1015,31 +1261,31 @@ function ReportFeature({ feature }) {
1015
1261
  "aria-controls": bodyId,
1016
1262
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1017
1263
  children: [
1018
- /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1019
- /* @__PURE__ */ jsx25("span", { className: "truncate", children: feature.title })
1264
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1265
+ /* @__PURE__ */ jsx27("span", { className: "truncate", children: feature.title })
1020
1266
  ]
1021
1267
  }
1022
1268
  ) : feature.title }),
1023
- /* @__PURE__ */ jsx25("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1269
+ /* @__PURE__ */ jsx27("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1024
1270
  ] }),
1025
- /* @__PURE__ */ jsxs16(
1271
+ /* @__PURE__ */ jsxs17(
1026
1272
  "p",
1027
1273
  {
1028
1274
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1029
1275
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1030
1276
  children: [
1031
- /* @__PURE__ */ jsxs16("span", { children: [
1277
+ /* @__PURE__ */ jsxs17("span", { children: [
1032
1278
  s.passed,
1033
1279
  " passed"
1034
1280
  ] }),
1035
- /* @__PURE__ */ jsx25("span", { "aria-hidden": true, children: "\xB7" }),
1036
- /* @__PURE__ */ jsxs16("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1281
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1282
+ /* @__PURE__ */ jsxs17("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1037
1283
  s.failed,
1038
1284
  " failed"
1039
1285
  ] }),
1040
- skipped > 0 ? /* @__PURE__ */ jsxs16(Fragment9, { children: [
1041
- /* @__PURE__ */ jsx25("span", { "aria-hidden": true, children: "\xB7" }),
1042
- /* @__PURE__ */ jsxs16("span", { children: [
1286
+ skipped > 0 ? /* @__PURE__ */ jsxs17(Fragment9, { children: [
1287
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1288
+ /* @__PURE__ */ jsxs17("span", { children: [
1043
1289
  skipped,
1044
1290
  " skipped"
1045
1291
  ] })
@@ -1048,7 +1294,7 @@ function ReportFeature({ feature }) {
1048
1294
  }
1049
1295
  )
1050
1296
  ] }),
1051
- /* @__PURE__ */ jsx25("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx25(ReportScenarioList, { feature }) })
1297
+ /* @__PURE__ */ jsx27("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx27(ReportScenarioList, { feature }) })
1052
1298
  ]
1053
1299
  }
1054
1300
  )
@@ -1056,17 +1302,17 @@ function ReportFeature({ feature }) {
1056
1302
  }
1057
1303
 
1058
1304
  // src/components/ReportFeatureList.tsx
1059
- import { jsx as jsx26 } from "react/jsx-runtime";
1305
+ import { jsx as jsx28 } from "react/jsx-runtime";
1060
1306
  function ReportFeatureList() {
1061
1307
  const report = useReport();
1062
- return /* @__PURE__ */ jsx26("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx26(ReportFeature, { feature }, feature.id)) });
1308
+ return /* @__PURE__ */ jsx28("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx28(ReportFeature, { feature }, feature.id)) });
1063
1309
  }
1064
1310
 
1065
1311
  // src/components/ui/empty.tsx
1066
1312
  import { cva as cva2 } from "class-variance-authority";
1067
- import { jsx as jsx27 } from "react/jsx-runtime";
1313
+ import { jsx as jsx29 } from "react/jsx-runtime";
1068
1314
  function Empty({ className, ...props }) {
1069
- return /* @__PURE__ */ jsx27(
1315
+ return /* @__PURE__ */ jsx29(
1070
1316
  "div",
1071
1317
  {
1072
1318
  "data-slot": "empty",
@@ -1079,7 +1325,7 @@ function Empty({ className, ...props }) {
1079
1325
  );
1080
1326
  }
1081
1327
  function EmptyHeader({ className, ...props }) {
1082
- return /* @__PURE__ */ jsx27(
1328
+ return /* @__PURE__ */ jsx29(
1083
1329
  "div",
1084
1330
  {
1085
1331
  "data-slot": "empty-header",
@@ -1106,7 +1352,7 @@ var emptyMediaVariants = cva2(
1106
1352
  }
1107
1353
  );
1108
1354
  function EmptyTitle({ className, ...props }) {
1109
- return /* @__PURE__ */ jsx27(
1355
+ return /* @__PURE__ */ jsx29(
1110
1356
  "div",
1111
1357
  {
1112
1358
  "data-slot": "empty-title",
@@ -1117,16 +1363,16 @@ function EmptyTitle({ className, ...props }) {
1117
1363
  }
1118
1364
 
1119
1365
  // src/components/ReportEmpty.tsx
1120
- import { jsx as jsx28 } from "react/jsx-runtime";
1366
+ import { jsx as jsx30 } from "react/jsx-runtime";
1121
1367
  function ReportEmpty({ message }) {
1122
- return /* @__PURE__ */ jsx28(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx28(EmptyHeader, { children: /* @__PURE__ */ jsx28(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1368
+ return /* @__PURE__ */ jsx30(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx30(EmptyHeader, { children: /* @__PURE__ */ jsx30(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1123
1369
  }
1124
1370
 
1125
1371
  // src/components/ReportSummary.tsx
1126
- import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
1372
+ import { jsx as jsx31, jsxs as jsxs18 } from "react/jsx-runtime";
1127
1373
  function ReportSummary({ className }) {
1128
1374
  const report = useReport();
1129
- return /* @__PURE__ */ jsx29(
1375
+ return /* @__PURE__ */ jsx31(
1130
1376
  ReportSummaryView,
1131
1377
  {
1132
1378
  summary: report.summary,
@@ -1152,7 +1398,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1152
1398
  if (summary.pending > 0) {
1153
1399
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1154
1400
  }
1155
- return /* @__PURE__ */ jsx29(
1401
+ return /* @__PURE__ */ jsx31(
1156
1402
  "dl",
1157
1403
  {
1158
1404
  className: cn(
@@ -1165,17 +1411,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1165
1411
  "aria-label": ariaLabel,
1166
1412
  children: cards.map((c) => {
1167
1413
  const tone = TONE[c.status];
1168
- return /* @__PURE__ */ jsxs17(
1414
+ return /* @__PURE__ */ jsxs18(
1169
1415
  "div",
1170
1416
  {
1171
1417
  "data-status": c.status,
1172
1418
  className: "rounded-lg border bg-card px-4 py-3",
1173
1419
  children: [
1174
- /* @__PURE__ */ jsxs17("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1175
- /* @__PURE__ */ jsx29("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1420
+ /* @__PURE__ */ jsxs18("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1421
+ /* @__PURE__ */ jsx31("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1176
1422
  c.label
1177
1423
  ] }),
1178
- /* @__PURE__ */ jsx29("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1424
+ /* @__PURE__ */ jsx31("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1179
1425
  ]
1180
1426
  },
1181
1427
  c.status
@@ -1235,7 +1481,7 @@ function prUrl(ci) {
1235
1481
  }
1236
1482
 
1237
1483
  // src/components/ReportMeta.tsx
1238
- import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
1484
+ import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
1239
1485
  function ReportMeta() {
1240
1486
  const report = useReport();
1241
1487
  const items = [];
@@ -1258,13 +1504,13 @@ function ReportMeta() {
1258
1504
  const short = sha.slice(0, 8);
1259
1505
  items.push({
1260
1506
  label: "Commit",
1261
- value: url ? /* @__PURE__ */ jsx30("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1507
+ value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1262
1508
  });
1263
1509
  }
1264
1510
  if (report.ci) {
1265
1511
  items.push({
1266
1512
  label: "CI",
1267
- value: report.ci.url ? /* @__PURE__ */ jsxs18("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1513
+ value: report.ci.url ? /* @__PURE__ */ jsxs19("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1268
1514
  ciDisplayName(report.ci.name),
1269
1515
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1270
1516
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1275,7 +1521,7 @@ function ReportMeta() {
1275
1521
  const label = `#${report.ci.prNumber}`;
1276
1522
  items.push({
1277
1523
  label: "PR",
1278
- value: url ? /* @__PURE__ */ jsx30("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1524
+ value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1279
1525
  });
1280
1526
  }
1281
1527
  if (items.length === 0) return null;
@@ -1283,48 +1529,48 @@ function ReportMeta() {
1283
1529
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1284
1530
  // collapsed disclosure so it doesn't push the result down. Native <details>
1285
1531
  // so it works with no JS (the SSR/no-hydration report still toggles).
1286
- /* @__PURE__ */ jsxs18("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1287
- /* @__PURE__ */ jsxs18("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1288
- /* @__PURE__ */ jsx30("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1532
+ /* @__PURE__ */ jsxs19("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1533
+ /* @__PURE__ */ jsxs19("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1534
+ /* @__PURE__ */ jsx32("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1289
1535
  "Run details"
1290
1536
  ] }),
1291
- /* @__PURE__ */ jsx30("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ jsxs18("div", { className: "flex items-baseline gap-1.5", children: [
1292
- /* @__PURE__ */ jsx30("dt", { className: "font-medium", children: item.label }),
1293
- /* @__PURE__ */ jsx30("dd", { className: "font-mono text-foreground", children: item.value })
1537
+ /* @__PURE__ */ jsx32("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ jsxs19("div", { className: "flex items-baseline gap-1.5", children: [
1538
+ /* @__PURE__ */ jsx32("dt", { className: "font-medium", children: item.label }),
1539
+ /* @__PURE__ */ jsx32("dd", { className: "font-mono text-foreground", children: item.value })
1294
1540
  ] }, item.label)) })
1295
1541
  ] })
1296
1542
  );
1297
1543
  }
1298
1544
 
1299
1545
  // src/components/ReportSchemaError.tsx
1300
- import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
1546
+ import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
1301
1547
  function ReportSchemaError({ error }) {
1302
- return /* @__PURE__ */ jsxs19("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1303
- /* @__PURE__ */ jsx31("p", { children: /* @__PURE__ */ jsx31("strong", { children: "Report could not be displayed." }) }),
1304
- /* @__PURE__ */ jsx31("p", { children: error.message }),
1305
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs19("p", { children: [
1548
+ return /* @__PURE__ */ jsxs20("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1549
+ /* @__PURE__ */ jsx33("p", { children: /* @__PURE__ */ jsx33("strong", { children: "Report could not be displayed." }) }),
1550
+ /* @__PURE__ */ jsx33("p", { children: error.message }),
1551
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs20("p", { children: [
1306
1552
  "The report bundle is newer than this version of ",
1307
- /* @__PURE__ */ jsx31("code", { children: "executable-stories-react" }),
1553
+ /* @__PURE__ */ jsx33("code", { children: "executable-stories-react" }),
1308
1554
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1309
1555
  ] }) : null,
1310
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs19("details", { children: [
1311
- /* @__PURE__ */ jsxs19("summary", { children: [
1556
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs20("details", { children: [
1557
+ /* @__PURE__ */ jsxs20("summary", { children: [
1312
1558
  error.issues.length,
1313
1559
  " validation issue",
1314
1560
  error.issues.length === 1 ? "" : "s"
1315
1561
  ] }),
1316
- /* @__PURE__ */ jsx31("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1562
+ /* @__PURE__ */ jsx33("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1317
1563
  ] }) : null
1318
1564
  ] });
1319
1565
  }
1320
1566
 
1321
1567
  // src/components/ReportShell.tsx
1322
- import { Fragment as Fragment10, jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
1568
+ import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
1323
1569
  function ReportTitleBlock({ title }) {
1324
- return /* @__PURE__ */ jsxs20(Fragment10, { children: [
1325
- /* @__PURE__ */ jsx32("h1", { children: title ?? "Story Report" }),
1326
- /* @__PURE__ */ jsx32(ReportSummary, {}),
1327
- /* @__PURE__ */ jsx32(ReportMeta, {})
1570
+ return /* @__PURE__ */ jsxs21(Fragment10, { children: [
1571
+ /* @__PURE__ */ jsx34("h1", { children: title ?? "Story Report" }),
1572
+ /* @__PURE__ */ jsx34(ReportSummary, {}),
1573
+ /* @__PURE__ */ jsx34(ReportMeta, {})
1328
1574
  ] });
1329
1575
  }
1330
1576
  function ReportErrorShell({
@@ -1333,28 +1579,28 @@ function ReportErrorShell({
1333
1579
  title,
1334
1580
  dataTheme
1335
1581
  }) {
1336
- return /* @__PURE__ */ jsx32("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx32(ReportSchemaError, { error }) });
1582
+ return /* @__PURE__ */ jsx34("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx34(ReportSchemaError, { error }) });
1337
1583
  }
1338
1584
 
1339
1585
  // src/components/Report.tsx
1340
- import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1586
+ import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
1341
1587
  function Report(props) {
1342
1588
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1343
1589
  const result = unwrapReport(report);
1344
1590
  if (!result.ok) {
1345
- return /* @__PURE__ */ jsx33(ReportErrorShell, { error: result.error, className, title, dataTheme });
1591
+ return /* @__PURE__ */ jsx35(ReportErrorShell, { error: result.error, className, title, dataTheme });
1346
1592
  }
1347
1593
  const data = result.data;
1348
1594
  const hasContent = data.features.length > 0;
1349
- return /* @__PURE__ */ jsx33(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs21("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1350
- /* @__PURE__ */ jsx33("header", { className: "es-report-header", children: /* @__PURE__ */ jsx33(ReportTitleBlock, { title }) }),
1351
- hasContent ? /* @__PURE__ */ jsx33(ReportFeatureList, {}) : /* @__PURE__ */ jsx33(ReportEmpty, {})
1595
+ return /* @__PURE__ */ jsx35(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs22("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1596
+ /* @__PURE__ */ jsx35("header", { className: "es-report-header", children: /* @__PURE__ */ jsx35(ReportTitleBlock, { title }) }),
1597
+ hasContent ? /* @__PURE__ */ jsx35(ReportFeatureList, {}) : /* @__PURE__ */ jsx35(ReportEmpty, {})
1352
1598
  ] }) });
1353
1599
  }
1354
1600
 
1355
1601
  // src/components/doc/MermaidView.tsx
1356
1602
  import { useEffect, useRef, useState as useState2 } from "react";
1357
- import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1603
+ import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1358
1604
  function prefersDark(el) {
1359
1605
  const themed = el?.closest("[data-theme]");
1360
1606
  if (themed?.dataset.theme === "dark") return true;
@@ -1391,9 +1637,9 @@ function MermaidView({ entry, load }) {
1391
1637
  };
1392
1638
  }, [entry.code, load]);
1393
1639
  if (svg) {
1394
- return /* @__PURE__ */ jsxs22("figure", { ref, className: "my-3", children: [
1395
- entry.title ? /* @__PURE__ */ jsx34("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1396
- /* @__PURE__ */ jsx34(
1640
+ return /* @__PURE__ */ jsxs23("figure", { ref, className: "my-3", children: [
1641
+ entry.title ? /* @__PURE__ */ jsx36("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1642
+ /* @__PURE__ */ jsx36(
1397
1643
  "div",
1398
1644
  {
1399
1645
  role: "img",
@@ -1404,18 +1650,18 @@ function MermaidView({ entry, load }) {
1404
1650
  )
1405
1651
  ] });
1406
1652
  }
1407
- return /* @__PURE__ */ jsx34(MermaidSource, { entry, ref });
1653
+ return /* @__PURE__ */ jsx36(MermaidSource, { entry, ref });
1408
1654
  }
1409
1655
 
1410
1656
  // src/components/doc/MermaidDiagram.tsx
1411
- import { jsx as jsx35 } from "react/jsx-runtime";
1657
+ import { jsx as jsx37 } from "react/jsx-runtime";
1412
1658
  var mermaidLoader;
1413
1659
  function loadMermaid() {
1414
1660
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1415
1661
  return mermaidLoader;
1416
1662
  }
1417
1663
  function MermaidDiagram({ entry, load = loadMermaid }) {
1418
- return /* @__PURE__ */ jsx35(MermaidView, { entry, load });
1664
+ return /* @__PURE__ */ jsx37(MermaidView, { entry, load });
1419
1665
  }
1420
1666
 
1421
1667
  // src/components/ScenarioExplorer.tsx
@@ -1425,12 +1671,12 @@ import { useState as useState3 } from "react";
1425
1671
  import "react";
1426
1672
  import { Command as CommandPrimitive } from "cmdk";
1427
1673
  import { SearchIcon } from "lucide-react";
1428
- import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1674
+ import { jsx as jsx38, jsxs as jsxs24 } from "react/jsx-runtime";
1429
1675
  function Command({
1430
1676
  className,
1431
1677
  ...props
1432
1678
  }) {
1433
- return /* @__PURE__ */ jsx36(
1679
+ return /* @__PURE__ */ jsx38(
1434
1680
  CommandPrimitive,
1435
1681
  {
1436
1682
  "data-slot": "command",
@@ -1446,14 +1692,14 @@ function CommandInput({
1446
1692
  className,
1447
1693
  ...props
1448
1694
  }) {
1449
- return /* @__PURE__ */ jsxs23(
1695
+ return /* @__PURE__ */ jsxs24(
1450
1696
  "div",
1451
1697
  {
1452
1698
  "data-slot": "command-input-wrapper",
1453
1699
  className: "flex h-9 items-center gap-2 border-b px-3",
1454
1700
  children: [
1455
- /* @__PURE__ */ jsx36(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1456
- /* @__PURE__ */ jsx36(
1701
+ /* @__PURE__ */ jsx38(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1702
+ /* @__PURE__ */ jsx38(
1457
1703
  CommandPrimitive.Input,
1458
1704
  {
1459
1705
  "data-slot": "command-input",
@@ -1472,7 +1718,7 @@ function CommandList({
1472
1718
  className,
1473
1719
  ...props
1474
1720
  }) {
1475
- return /* @__PURE__ */ jsx36(
1721
+ return /* @__PURE__ */ jsx38(
1476
1722
  CommandPrimitive.List,
1477
1723
  {
1478
1724
  "data-slot": "command-list",
@@ -1487,7 +1733,7 @@ function CommandList({
1487
1733
  function CommandEmpty({
1488
1734
  ...props
1489
1735
  }) {
1490
- return /* @__PURE__ */ jsx36(
1736
+ return /* @__PURE__ */ jsx38(
1491
1737
  CommandPrimitive.Empty,
1492
1738
  {
1493
1739
  "data-slot": "command-empty",
@@ -1500,7 +1746,7 @@ function CommandGroup({
1500
1746
  className,
1501
1747
  ...props
1502
1748
  }) {
1503
- return /* @__PURE__ */ jsx36(
1749
+ return /* @__PURE__ */ jsx38(
1504
1750
  CommandPrimitive.Group,
1505
1751
  {
1506
1752
  "data-slot": "command-group",
@@ -1516,7 +1762,7 @@ function CommandItem({
1516
1762
  className,
1517
1763
  ...props
1518
1764
  }) {
1519
- return /* @__PURE__ */ jsx36(
1765
+ return /* @__PURE__ */ jsx38(
1520
1766
  CommandPrimitive.Item,
1521
1767
  {
1522
1768
  "data-slot": "command-item",
@@ -1530,7 +1776,7 @@ function CommandItem({
1530
1776
  }
1531
1777
 
1532
1778
  // src/components/ScenarioExplorer.tsx
1533
- import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1779
+ import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
1534
1780
  var STATUS_FILTERS = [
1535
1781
  { value: "all", label: "All" },
1536
1782
  { value: "passed", label: "Passed" },
@@ -1541,22 +1787,22 @@ var STATUS_FILTERS = [
1541
1787
  function ScenarioExplorer({ scenarios, summary }) {
1542
1788
  const [status, setStatus] = useState3("all");
1543
1789
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1544
- return /* @__PURE__ */ jsxs24("div", { className: "font-sans text-foreground", children: [
1545
- summary ? /* @__PURE__ */ jsxs24("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1790
+ return /* @__PURE__ */ jsxs25("div", { className: "font-sans text-foreground", children: [
1791
+ summary ? /* @__PURE__ */ jsxs25("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1546
1792
  summary.total,
1547
1793
  " scenarios \xB7 ",
1548
- /* @__PURE__ */ jsxs24("span", { className: "text-pass", children: [
1794
+ /* @__PURE__ */ jsxs25("span", { className: "text-pass", children: [
1549
1795
  summary.passed,
1550
1796
  " passed"
1551
1797
  ] }),
1552
1798
  " \xB7",
1553
1799
  " ",
1554
- /* @__PURE__ */ jsxs24("span", { className: "text-fail", children: [
1800
+ /* @__PURE__ */ jsxs25("span", { className: "text-fail", children: [
1555
1801
  summary.failed,
1556
1802
  " failed"
1557
1803
  ] })
1558
1804
  ] }) : null,
1559
- /* @__PURE__ */ jsx37("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx37(
1805
+ /* @__PURE__ */ jsx39("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx39(
1560
1806
  "button",
1561
1807
  {
1562
1808
  type: "button",
@@ -1571,26 +1817,26 @@ function ScenarioExplorer({ scenarios, summary }) {
1571
1817
  },
1572
1818
  f.value
1573
1819
  )) }),
1574
- /* @__PURE__ */ jsxs24(
1820
+ /* @__PURE__ */ jsxs25(
1575
1821
  Command,
1576
1822
  {
1577
1823
  className: "rounded-lg border border-border bg-card",
1578
1824
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1579
1825
  children: [
1580
- /* @__PURE__ */ jsx37(CommandInput, { placeholder: "Search scenarios\u2026" }),
1581
- /* @__PURE__ */ jsxs24(CommandList, { className: "max-h-none", children: [
1582
- /* @__PURE__ */ jsx37(CommandEmpty, { children: "No scenarios match your filters." }),
1583
- /* @__PURE__ */ jsx37(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx37(
1826
+ /* @__PURE__ */ jsx39(CommandInput, { placeholder: "Search scenarios\u2026" }),
1827
+ /* @__PURE__ */ jsxs25(CommandList, { className: "max-h-none", children: [
1828
+ /* @__PURE__ */ jsx39(CommandEmpty, { children: "No scenarios match your filters." }),
1829
+ /* @__PURE__ */ jsx39(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx39(
1584
1830
  CommandItem,
1585
1831
  {
1586
1832
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1587
1833
  asChild: true,
1588
1834
  className: "cursor-pointer",
1589
- children: /* @__PURE__ */ jsxs24("a", { href: s.href, className: "flex items-center gap-3", children: [
1590
- /* @__PURE__ */ jsx37(Badge, { variant: s.status, children: s.status }),
1591
- /* @__PURE__ */ jsx37("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1592
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx37(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1593
- /* @__PURE__ */ jsx37("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1835
+ children: /* @__PURE__ */ jsxs25("a", { href: s.href, className: "flex items-center gap-3", children: [
1836
+ /* @__PURE__ */ jsx39(Badge, { variant: s.status, children: s.status }),
1837
+ /* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1838
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx39(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1839
+ /* @__PURE__ */ jsx39("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1594
1840
  ] })
1595
1841
  },
1596
1842
  s.id
@@ -2086,6 +2332,9 @@ var story_report_v1_default = {
2086
2332
  {
2087
2333
  $ref: "#/$defs/DocHtml"
2088
2334
  },
2335
+ {
2336
+ $ref: "#/$defs/DocState"
2337
+ },
2089
2338
  {
2090
2339
  $ref: "#/$defs/DocCustom"
2091
2340
  }
@@ -2461,6 +2710,33 @@ var story_report_v1_default = {
2461
2710
  }
2462
2711
  ]
2463
2712
  },
2713
+ DocState: {
2714
+ type: "object",
2715
+ properties: {
2716
+ kind: {
2717
+ const: "state"
2718
+ },
2719
+ label: {
2720
+ type: "string"
2721
+ },
2722
+ value: {},
2723
+ phase: {
2724
+ $ref: "#/$defs/DocPhase"
2725
+ },
2726
+ children: {
2727
+ type: "array",
2728
+ items: {
2729
+ $ref: "#/$defs/DocEntry"
2730
+ }
2731
+ }
2732
+ },
2733
+ required: [
2734
+ "kind",
2735
+ "value",
2736
+ "phase"
2737
+ ],
2738
+ additionalProperties: false
2739
+ },
2464
2740
  DocCustom: {
2465
2741
  type: "object",
2466
2742
  properties: {
@@ -2610,6 +2886,7 @@ export {
2610
2886
  ReportSchemaError,
2611
2887
  ReportStepItem,
2612
2888
  ReportSteps,
2889
+ ReportStoryboard,
2613
2890
  ReportSummary,
2614
2891
  ReportSummaryView,
2615
2892
  ReportTrace,