executable-stories-react 0.7.0 → 0.9.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
@@ -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,12 +519,72 @@ 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
+
514
588
  // ../executable-stories-core/dist/storyboard.js
515
589
  function findScreenshot(entries) {
516
590
  for (const entry of entries) {
@@ -522,26 +596,55 @@ function findScreenshot(entries) {
522
596
  }
523
597
  return void 0;
524
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 ?? "";
525
607
  function extractStoryboardFrames(scenario) {
526
608
  const frames = [];
609
+ const laneOrder = [];
610
+ const previous = /* @__PURE__ */ new Map();
527
611
  for (const step of scenario.steps) {
528
612
  const shot = findScreenshot(step.docEntries);
529
- if (!shot) continue;
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
+ }
530
633
  frames.push({
531
634
  stepId: step.id,
532
635
  stepIndex: step.index,
533
636
  keyword: step.keyword,
534
637
  text: step.text,
535
638
  status: step.status,
536
- path: shot.path,
537
- ...shot.alt !== void 0 && { alt: shot.alt }
639
+ ...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
640
+ states
538
641
  });
539
642
  }
540
643
  return frames;
541
644
  }
542
645
 
543
646
  // src/components/ReportStoryboard.tsx
544
- import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
647
+ import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
545
648
  var FRAME_GLYPH = {
546
649
  passed: "\u2713",
547
650
  failed: "\u2717",
@@ -558,54 +661,113 @@ function ReportStoryboard({ scenario }) {
558
661
  const frames = extractStoryboardFrames(scenario);
559
662
  if (frames.length < 2) return null;
560
663
  return /* @__PURE__ */ jsxs11("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
561
- /* @__PURE__ */ jsx18("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
562
- /* @__PURE__ */ jsx18("ol", { className: "flex gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx18(StoryboardFrameItem, { frame }, frame.stepId)) })
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)) })
563
666
  ] });
564
667
  }
565
668
  function StoryboardFrameItem({ frame }) {
566
- const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
567
669
  const label = `${frame.keyword} ${frame.text}`;
568
- return /* @__PURE__ */ jsxs11("li", { className: "w-40 shrink-0", children: [
569
- /* @__PURE__ */ jsx18(
570
- "a",
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",
571
736
  {
572
- href: `#${frame.stepId}`,
573
- "aria-label": `Jump to step: ${label}`,
574
- className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
575
- children: src ? /* @__PURE__ */ jsx18(
576
- "img",
577
- {
578
- src,
579
- alt: frame.alt ?? label,
580
- loading: "lazy",
581
- className: "h-24 w-full bg-muted object-cover object-top"
582
- }
583
- ) : /* @__PURE__ */ jsx18("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
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
+ ]
584
754
  }
585
- ),
586
- /* @__PURE__ */ jsxs11("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
587
- /* @__PURE__ */ jsx18("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
588
- /* @__PURE__ */ jsxs11("span", { className: "min-w-0", children: [
589
- /* @__PURE__ */ jsx18("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
590
- " ",
591
- /* @__PURE__ */ jsx18("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
592
- ] })
593
- ] })
755
+ )
594
756
  ] });
595
757
  }
596
758
 
597
759
  // src/components/ReportAttachments.tsx
598
- import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
760
+ import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
599
761
  function ReportAttachments({ attachments }) {
600
762
  if (attachments.length === 0) return null;
601
763
  return (
602
764
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
603
765
  // blocks don't create duplicate "Attachments" region landmarks.
604
- /* @__PURE__ */ jsx19("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) => {
605
767
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
606
768
  const isImage = att.mediaType.startsWith("image/");
607
- return /* @__PURE__ */ jsx19("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
608
- /* @__PURE__ */ jsx19(
769
+ return /* @__PURE__ */ jsx20("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
770
+ /* @__PURE__ */ jsx20(
609
771
  "img",
610
772
  {
611
773
  src: dataUri,
@@ -614,7 +776,7 @@ function ReportAttachments({ attachments }) {
614
776
  className: "max-w-full rounded-md border border-border"
615
777
  }
616
778
  ),
617
- /* @__PURE__ */ jsx19("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
779
+ /* @__PURE__ */ jsx20("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
618
780
  ] }) : /* @__PURE__ */ jsxs12(
619
781
  "a",
620
782
  {
@@ -688,15 +850,15 @@ function toTraceRows(spans) {
688
850
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
689
851
  const rows = [];
690
852
  const seen = /* @__PURE__ */ new Set();
691
- const walk = (node, depth) => {
853
+ const walk2 = (node, depth) => {
692
854
  if (seen.has(node.span.spanId)) return;
693
855
  seen.add(node.span.spanId);
694
856
  rows.push({ ...node.span, depth });
695
- for (const child of node.children) walk(child, depth + 1);
857
+ for (const child of node.children) walk2(child, depth + 1);
696
858
  };
697
- for (const root of roots) walk(root, 0);
859
+ for (const root of roots) walk2(root, 0);
698
860
  for (const node of byId.values()) {
699
- if (!seen.has(node.span.spanId)) walk(node, 0);
861
+ if (!seen.has(node.span.spanId)) walk2(node, 0);
700
862
  }
701
863
  return rows;
702
864
  }
@@ -712,7 +874,7 @@ function traceWindow(rows) {
712
874
  }
713
875
 
714
876
  // src/components/ReportTrace.tsx
715
- import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
877
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
716
878
  var BAR_COLOR = {
717
879
  ok: "bg-pass",
718
880
  error: "bg-fail",
@@ -733,11 +895,11 @@ function ReportTrace({ spans }) {
733
895
  formatDuration(totalMs),
734
896
  ")"
735
897
  ] }),
736
- /* @__PURE__ */ jsx20("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
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) => {
737
899
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
738
900
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
739
901
  return /* @__PURE__ */ jsxs13("li", { className: "flex items-center gap-2", children: [
740
- /* @__PURE__ */ jsx20(
902
+ /* @__PURE__ */ jsx21(
741
903
  "span",
742
904
  {
743
905
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -746,14 +908,14 @@ function ReportTrace({ spans }) {
746
908
  children: row.name
747
909
  }
748
910
  ),
749
- /* @__PURE__ */ jsx20("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx20(
911
+ /* @__PURE__ */ jsx21("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx21(
750
912
  "span",
751
913
  {
752
914
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
753
915
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
754
916
  }
755
917
  ) }),
756
- /* @__PURE__ */ jsx20("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) })
757
919
  ] }, `${row.spanId}-${i}`);
758
920
  }) })
759
921
  ] });
@@ -804,7 +966,7 @@ function flakinessOf(entries) {
804
966
  }
805
967
 
806
968
  // src/components/ScenarioRunHistory.tsx
807
- import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
969
+ import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
808
970
  var MAX_DOTS = 10;
809
971
  var DOT_COLOR = {
810
972
  passed: "bg-pass",
@@ -825,15 +987,15 @@ function ScenarioRunHistory({ scenarioId }) {
825
987
  const flaky = flakinessOf(recent) === "flaky";
826
988
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
827
989
  return /* @__PURE__ */ jsxs14(Fragment7, { children: [
828
- flaky ? /* @__PURE__ */ jsx21(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
829
- /* @__PURE__ */ jsx21(
990
+ flaky ? /* @__PURE__ */ jsx22(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
991
+ /* @__PURE__ */ jsx22(
830
992
  "span",
831
993
  {
832
994
  role: "img",
833
995
  "aria-label": `Run history: ${summary}`,
834
996
  title: summary,
835
997
  className: "flex shrink-0 items-center gap-[3px]",
836
- children: recent.map((e, i) => /* @__PURE__ */ jsx21(
998
+ children: recent.map((e, i) => /* @__PURE__ */ jsx22(
837
999
  "span",
838
1000
  {
839
1001
  "aria-hidden": true,
@@ -872,9 +1034,9 @@ function useScenarioActions() {
872
1034
 
873
1035
  // src/components/ui/card.tsx
874
1036
  import "react";
875
- import { jsx as jsx22 } from "react/jsx-runtime";
1037
+ import { jsx as jsx23 } from "react/jsx-runtime";
876
1038
  function Card({ className, ...props }) {
877
- return /* @__PURE__ */ jsx22(
1039
+ return /* @__PURE__ */ jsx23(
878
1040
  "div",
879
1041
  {
880
1042
  "data-slot": "card",
@@ -887,7 +1049,7 @@ function Card({ className, ...props }) {
887
1049
  );
888
1050
  }
889
1051
  function CardHeader({ className, ...props }) {
890
- return /* @__PURE__ */ jsx22(
1052
+ return /* @__PURE__ */ jsx23(
891
1053
  "div",
892
1054
  {
893
1055
  "data-slot": "card-header",
@@ -900,7 +1062,7 @@ function CardHeader({ className, ...props }) {
900
1062
  );
901
1063
  }
902
1064
  function CardContent({ className, ...props }) {
903
- return /* @__PURE__ */ jsx22(
1065
+ return /* @__PURE__ */ jsx23(
904
1066
  "div",
905
1067
  {
906
1068
  "data-slot": "card-content",
@@ -914,13 +1076,13 @@ function CardContent({ className, ...props }) {
914
1076
  import "react";
915
1077
  import { Menu as MenuPrimitive } from "@base-ui/react/menu";
916
1078
  import { CheckIcon } from "lucide-react";
917
- import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1079
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
918
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";
919
1081
  function DropdownMenu(props) {
920
- return /* @__PURE__ */ jsx23(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1082
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
921
1083
  }
922
1084
  function DropdownMenuTrigger(props) {
923
- return /* @__PURE__ */ jsx23(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1085
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
924
1086
  }
925
1087
  function DropdownMenuContent({
926
1088
  className,
@@ -928,14 +1090,14 @@ function DropdownMenuContent({
928
1090
  sideOffset = 4,
929
1091
  ...props
930
1092
  }) {
931
- return /* @__PURE__ */ jsx23(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx23(
1093
+ return /* @__PURE__ */ jsx24(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx24(
932
1094
  MenuPrimitive.Positioner,
933
1095
  {
934
1096
  "data-slot": "dropdown-menu-positioner",
935
1097
  className: "z-50",
936
1098
  align,
937
1099
  sideOffset,
938
- children: /* @__PURE__ */ jsx23(
1100
+ children: /* @__PURE__ */ jsx24(
939
1101
  MenuPrimitive.Popup,
940
1102
  {
941
1103
  "data-slot": "dropdown-menu-content",
@@ -953,7 +1115,7 @@ function DropdownMenuItem({
953
1115
  className,
954
1116
  ...props
955
1117
  }) {
956
- return /* @__PURE__ */ jsx23(
1118
+ return /* @__PURE__ */ jsx24(
957
1119
  MenuPrimitive.Item,
958
1120
  {
959
1121
  "data-slot": "dropdown-menu-item",
@@ -965,7 +1127,7 @@ function DropdownMenuItem({
965
1127
 
966
1128
  // src/components/ReportScenario.tsx
967
1129
  import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
968
- import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
1130
+ import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
969
1131
  var STATUS_META = {
970
1132
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
971
1133
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -992,7 +1154,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
992
1154
  /* @__PURE__ */ jsxs16(CardHeader, { className: "px-4 py-3", children: [
993
1155
  /* @__PURE__ */ jsxs16("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
994
1156
  hideTitle ? null : /* @__PURE__ */ jsxs16("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
995
- collapsible ? /* @__PURE__ */ jsx24(
1157
+ collapsible ? /* @__PURE__ */ jsx25(
996
1158
  "button",
997
1159
  {
998
1160
  type: "button",
@@ -1001,36 +1163,36 @@ function ReportScenario({ scenario, hideTitle = false }) {
1001
1163
  "aria-controls": bodyId,
1002
1164
  "aria-label": `Toggle ${scenario.title}`,
1003
1165
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1004
- children: /* @__PURE__ */ jsx24("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" })
1005
1167
  }
1006
1168
  ) : null,
1007
- /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1008
- /* @__PURE__ */ jsx24("span", { children: scenario.title })
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 })
1009
1171
  ] }),
1010
1172
  /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2", children: [
1011
- /* @__PURE__ */ jsx24(ScenarioRunHistory, { scenarioId: scenario.id }),
1012
- scenario.durationMs > 0 ? /* @__PURE__ */ jsx24("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1013
- meta.showPill ? /* @__PURE__ */ jsx24(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx24("span", { className: "sr-only", children: `Status: ${label}` }),
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}` }),
1014
1176
  actions ? /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
1015
- /* @__PURE__ */ jsx24(
1177
+ /* @__PURE__ */ jsx25(
1016
1178
  DropdownMenuTrigger,
1017
1179
  {
1018
1180
  "aria-label": `Actions for ${scenario.title}`,
1019
1181
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1020
- children: /* @__PURE__ */ jsx24(MoreHorizontalIcon, { "aria-hidden": true })
1182
+ children: /* @__PURE__ */ jsx25(MoreHorizontalIcon, { "aria-hidden": true })
1021
1183
  }
1022
1184
  ),
1023
1185
  /* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", children: [
1024
1186
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1025
- /* @__PURE__ */ jsx24(LinkIcon, {}),
1187
+ /* @__PURE__ */ jsx25(LinkIcon, {}),
1026
1188
  " Copy link"
1027
1189
  ] }),
1028
1190
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1029
- /* @__PURE__ */ jsx24(FileTextIcon, {}),
1191
+ /* @__PURE__ */ jsx25(FileTextIcon, {}),
1030
1192
  " Copy as Markdown"
1031
1193
  ] }),
1032
1194
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1033
- /* @__PURE__ */ jsx24(SparklesIcon, {}),
1195
+ /* @__PURE__ */ jsx25(SparklesIcon, {}),
1034
1196
  " Explain with AI"
1035
1197
  ] })
1036
1198
  ] })
@@ -1038,12 +1200,12 @@ function ReportScenario({ scenario, hideTitle = false }) {
1038
1200
  ] })
1039
1201
  ] }),
1040
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: [
1041
- scenario.tags.map((t) => /* @__PURE__ */ jsx24("li", { children: /* @__PURE__ */ jsx24(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1042
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx24("li", { children: ticket.url ? /* @__PURE__ */ jsx24("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx24(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx24(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
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}`))
1043
1205
  ] }) : null
1044
1206
  ] }),
1045
1207
  /* @__PURE__ */ jsxs16(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1046
- scenario.errorMessage ? /* @__PURE__ */ jsx24(
1208
+ scenario.errorMessage ? /* @__PURE__ */ jsx25(
1047
1209
  "pre",
1048
1210
  {
1049
1211
  role: "alert",
@@ -1051,11 +1213,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
1051
1213
  children: scenario.errorMessage
1052
1214
  }
1053
1215
  ) : null,
1054
- /* @__PURE__ */ jsx24(ReportStoryboard, { scenario }),
1055
- /* @__PURE__ */ jsx24(ReportSteps, { scenario }),
1056
- scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx24("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx24(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1057
- /* @__PURE__ */ jsx24(ReportAttachments, { attachments: scenario.attachments }),
1058
- /* @__PURE__ */ jsx24(ReportTrace, { spans: scenario.otelSpans })
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 })
1059
1221
  ] })
1060
1222
  ]
1061
1223
  }
@@ -1063,13 +1225,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1063
1225
  }
1064
1226
 
1065
1227
  // src/components/ReportScenarioList.tsx
1066
- import { Fragment as Fragment8, jsx as jsx25 } from "react/jsx-runtime";
1228
+ import { Fragment as Fragment8, jsx as jsx26 } from "react/jsx-runtime";
1067
1229
  function ReportScenarioList({ feature }) {
1068
- return /* @__PURE__ */ jsx25(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx25(ReportScenario, { scenario }, scenario.id)) });
1230
+ return /* @__PURE__ */ jsx26(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx26(ReportScenario, { scenario }, scenario.id)) });
1069
1231
  }
1070
1232
 
1071
1233
  // src/components/ReportFeature.tsx
1072
- import { Fragment as Fragment9, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
1234
+ import { Fragment as Fragment9, jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
1073
1235
  function ReportFeature({ feature }) {
1074
1236
  const titleId = `${feature.id}-title`;
1075
1237
  const bodyId = `${feature.id}-body`;
@@ -1090,7 +1252,7 @@ function ReportFeature({ feature }) {
1090
1252
  children: [
1091
1253
  /* @__PURE__ */ jsxs17("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1092
1254
  /* @__PURE__ */ jsxs17("div", { className: "min-w-0", children: [
1093
- /* @__PURE__ */ jsx26("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
1255
+ /* @__PURE__ */ jsx27("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
1094
1256
  "button",
1095
1257
  {
1096
1258
  type: "button",
@@ -1099,12 +1261,12 @@ function ReportFeature({ feature }) {
1099
1261
  "aria-controls": bodyId,
1100
1262
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1101
1263
  children: [
1102
- /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1103
- /* @__PURE__ */ jsx26("span", { className: "truncate", children: feature.title })
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 })
1104
1266
  ]
1105
1267
  }
1106
1268
  ) : feature.title }),
1107
- /* @__PURE__ */ jsx26("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 })
1108
1270
  ] }),
1109
1271
  /* @__PURE__ */ jsxs17(
1110
1272
  "p",
@@ -1116,13 +1278,13 @@ function ReportFeature({ feature }) {
1116
1278
  s.passed,
1117
1279
  " passed"
1118
1280
  ] }),
1119
- /* @__PURE__ */ jsx26("span", { "aria-hidden": true, children: "\xB7" }),
1281
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1120
1282
  /* @__PURE__ */ jsxs17("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1121
1283
  s.failed,
1122
1284
  " failed"
1123
1285
  ] }),
1124
1286
  skipped > 0 ? /* @__PURE__ */ jsxs17(Fragment9, { children: [
1125
- /* @__PURE__ */ jsx26("span", { "aria-hidden": true, children: "\xB7" }),
1287
+ /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1126
1288
  /* @__PURE__ */ jsxs17("span", { children: [
1127
1289
  skipped,
1128
1290
  " skipped"
@@ -1132,7 +1294,7 @@ function ReportFeature({ feature }) {
1132
1294
  }
1133
1295
  )
1134
1296
  ] }),
1135
- /* @__PURE__ */ jsx26("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx26(ReportScenarioList, { feature }) })
1297
+ /* @__PURE__ */ jsx27("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx27(ReportScenarioList, { feature }) })
1136
1298
  ]
1137
1299
  }
1138
1300
  )
@@ -1140,17 +1302,17 @@ function ReportFeature({ feature }) {
1140
1302
  }
1141
1303
 
1142
1304
  // src/components/ReportFeatureList.tsx
1143
- import { jsx as jsx27 } from "react/jsx-runtime";
1305
+ import { jsx as jsx28 } from "react/jsx-runtime";
1144
1306
  function ReportFeatureList() {
1145
1307
  const report = useReport();
1146
- return /* @__PURE__ */ jsx27("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx27(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)) });
1147
1309
  }
1148
1310
 
1149
1311
  // src/components/ui/empty.tsx
1150
1312
  import { cva as cva2 } from "class-variance-authority";
1151
- import { jsx as jsx28 } from "react/jsx-runtime";
1313
+ import { jsx as jsx29 } from "react/jsx-runtime";
1152
1314
  function Empty({ className, ...props }) {
1153
- return /* @__PURE__ */ jsx28(
1315
+ return /* @__PURE__ */ jsx29(
1154
1316
  "div",
1155
1317
  {
1156
1318
  "data-slot": "empty",
@@ -1163,7 +1325,7 @@ function Empty({ className, ...props }) {
1163
1325
  );
1164
1326
  }
1165
1327
  function EmptyHeader({ className, ...props }) {
1166
- return /* @__PURE__ */ jsx28(
1328
+ return /* @__PURE__ */ jsx29(
1167
1329
  "div",
1168
1330
  {
1169
1331
  "data-slot": "empty-header",
@@ -1190,7 +1352,7 @@ var emptyMediaVariants = cva2(
1190
1352
  }
1191
1353
  );
1192
1354
  function EmptyTitle({ className, ...props }) {
1193
- return /* @__PURE__ */ jsx28(
1355
+ return /* @__PURE__ */ jsx29(
1194
1356
  "div",
1195
1357
  {
1196
1358
  "data-slot": "empty-title",
@@ -1201,16 +1363,16 @@ function EmptyTitle({ className, ...props }) {
1201
1363
  }
1202
1364
 
1203
1365
  // src/components/ReportEmpty.tsx
1204
- import { jsx as jsx29 } from "react/jsx-runtime";
1366
+ import { jsx as jsx30 } from "react/jsx-runtime";
1205
1367
  function ReportEmpty({ message }) {
1206
- return /* @__PURE__ */ jsx29(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx29(EmptyHeader, { children: /* @__PURE__ */ jsx29(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
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." }) }) });
1207
1369
  }
1208
1370
 
1209
1371
  // src/components/ReportSummary.tsx
1210
- import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
1372
+ import { jsx as jsx31, jsxs as jsxs18 } from "react/jsx-runtime";
1211
1373
  function ReportSummary({ className }) {
1212
1374
  const report = useReport();
1213
- return /* @__PURE__ */ jsx30(
1375
+ return /* @__PURE__ */ jsx31(
1214
1376
  ReportSummaryView,
1215
1377
  {
1216
1378
  summary: report.summary,
@@ -1236,7 +1398,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1236
1398
  if (summary.pending > 0) {
1237
1399
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1238
1400
  }
1239
- return /* @__PURE__ */ jsx30(
1401
+ return /* @__PURE__ */ jsx31(
1240
1402
  "dl",
1241
1403
  {
1242
1404
  className: cn(
@@ -1256,10 +1418,10 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1256
1418
  className: "rounded-lg border bg-card px-4 py-3",
1257
1419
  children: [
1258
1420
  /* @__PURE__ */ jsxs18("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1259
- /* @__PURE__ */ jsx30("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1421
+ /* @__PURE__ */ jsx31("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1260
1422
  c.label
1261
1423
  ] }),
1262
- /* @__PURE__ */ jsx30("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 })
1263
1425
  ]
1264
1426
  },
1265
1427
  c.status
@@ -1319,7 +1481,7 @@ function prUrl(ci) {
1319
1481
  }
1320
1482
 
1321
1483
  // src/components/ReportMeta.tsx
1322
- import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
1484
+ import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
1323
1485
  function ReportMeta() {
1324
1486
  const report = useReport();
1325
1487
  const items = [];
@@ -1342,7 +1504,7 @@ function ReportMeta() {
1342
1504
  const short = sha.slice(0, 8);
1343
1505
  items.push({
1344
1506
  label: "Commit",
1345
- value: url ? /* @__PURE__ */ jsx31("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
1346
1508
  });
1347
1509
  }
1348
1510
  if (report.ci) {
@@ -1359,7 +1521,7 @@ function ReportMeta() {
1359
1521
  const label = `#${report.ci.prNumber}`;
1360
1522
  items.push({
1361
1523
  label: "PR",
1362
- value: url ? /* @__PURE__ */ jsx31("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
1363
1525
  });
1364
1526
  }
1365
1527
  if (items.length === 0) return null;
@@ -1369,26 +1531,26 @@ function ReportMeta() {
1369
1531
  // so it works with no JS (the SSR/no-hydration report still toggles).
1370
1532
  /* @__PURE__ */ jsxs19("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1371
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: [
1372
- /* @__PURE__ */ jsx31("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1534
+ /* @__PURE__ */ jsx32("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1373
1535
  "Run details"
1374
1536
  ] }),
1375
- /* @__PURE__ */ jsx31("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ jsxs19("div", { className: "flex items-baseline gap-1.5", children: [
1376
- /* @__PURE__ */ jsx31("dt", { className: "font-medium", children: item.label }),
1377
- /* @__PURE__ */ jsx31("dd", { className: "font-mono text-foreground", children: item.value })
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 })
1378
1540
  ] }, item.label)) })
1379
1541
  ] })
1380
1542
  );
1381
1543
  }
1382
1544
 
1383
1545
  // src/components/ReportSchemaError.tsx
1384
- import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
1546
+ import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
1385
1547
  function ReportSchemaError({ error }) {
1386
1548
  return /* @__PURE__ */ jsxs20("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1387
- /* @__PURE__ */ jsx32("p", { children: /* @__PURE__ */ jsx32("strong", { children: "Report could not be displayed." }) }),
1388
- /* @__PURE__ */ jsx32("p", { children: error.message }),
1549
+ /* @__PURE__ */ jsx33("p", { children: /* @__PURE__ */ jsx33("strong", { children: "Report could not be displayed." }) }),
1550
+ /* @__PURE__ */ jsx33("p", { children: error.message }),
1389
1551
  error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs20("p", { children: [
1390
1552
  "The report bundle is newer than this version of ",
1391
- /* @__PURE__ */ jsx32("code", { children: "executable-stories-react" }),
1553
+ /* @__PURE__ */ jsx33("code", { children: "executable-stories-react" }),
1392
1554
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1393
1555
  ] }) : null,
1394
1556
  error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs20("details", { children: [
@@ -1397,18 +1559,18 @@ function ReportSchemaError({ error }) {
1397
1559
  " validation issue",
1398
1560
  error.issues.length === 1 ? "" : "s"
1399
1561
  ] }),
1400
- /* @__PURE__ */ jsx32("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") })
1401
1563
  ] }) : null
1402
1564
  ] });
1403
1565
  }
1404
1566
 
1405
1567
  // src/components/ReportShell.tsx
1406
- import { Fragment as Fragment10, jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1568
+ import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
1407
1569
  function ReportTitleBlock({ title }) {
1408
1570
  return /* @__PURE__ */ jsxs21(Fragment10, { children: [
1409
- /* @__PURE__ */ jsx33("h1", { children: title ?? "Story Report" }),
1410
- /* @__PURE__ */ jsx33(ReportSummary, {}),
1411
- /* @__PURE__ */ jsx33(ReportMeta, {})
1571
+ /* @__PURE__ */ jsx34("h1", { children: title ?? "Story Report" }),
1572
+ /* @__PURE__ */ jsx34(ReportSummary, {}),
1573
+ /* @__PURE__ */ jsx34(ReportMeta, {})
1412
1574
  ] });
1413
1575
  }
1414
1576
  function ReportErrorShell({
@@ -1417,28 +1579,28 @@ function ReportErrorShell({
1417
1579
  title,
1418
1580
  dataTheme
1419
1581
  }) {
1420
- return /* @__PURE__ */ jsx33("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx33(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 }) });
1421
1583
  }
1422
1584
 
1423
1585
  // src/components/Report.tsx
1424
- import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1586
+ import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
1425
1587
  function Report(props) {
1426
1588
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1427
1589
  const result = unwrapReport(report);
1428
1590
  if (!result.ok) {
1429
- return /* @__PURE__ */ jsx34(ReportErrorShell, { error: result.error, className, title, dataTheme });
1591
+ return /* @__PURE__ */ jsx35(ReportErrorShell, { error: result.error, className, title, dataTheme });
1430
1592
  }
1431
1593
  const data = result.data;
1432
1594
  const hasContent = data.features.length > 0;
1433
- return /* @__PURE__ */ jsx34(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs22("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1434
- /* @__PURE__ */ jsx34("header", { className: "es-report-header", children: /* @__PURE__ */ jsx34(ReportTitleBlock, { title }) }),
1435
- hasContent ? /* @__PURE__ */ jsx34(ReportFeatureList, {}) : /* @__PURE__ */ jsx34(ReportEmpty, {})
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, {})
1436
1598
  ] }) });
1437
1599
  }
1438
1600
 
1439
1601
  // src/components/doc/MermaidView.tsx
1440
1602
  import { useEffect, useRef, useState as useState2 } from "react";
1441
- import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
1603
+ import { Fragment as Fragment11, jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1442
1604
  function prefersDark(el) {
1443
1605
  const themed = el?.closest("[data-theme]");
1444
1606
  if (themed?.dataset.theme === "dark") return true;
@@ -1448,21 +1610,38 @@ function prefersDark(el) {
1448
1610
  function MermaidView({ entry, load }) {
1449
1611
  const ref = useRef(null);
1450
1612
  const [svg, setSvg] = useState2(null);
1613
+ const [error, setError] = useState2(null);
1451
1614
  useEffect(() => {
1452
1615
  let cancelled = false;
1453
1616
  const draw = async () => {
1617
+ let mermaid;
1618
+ try {
1619
+ mermaid = await load();
1620
+ } catch {
1621
+ if (!cancelled) {
1622
+ setSvg(null);
1623
+ setError(null);
1624
+ }
1625
+ return;
1626
+ }
1454
1627
  try {
1455
- const mermaid = await load();
1456
1628
  mermaid.initialize({
1457
1629
  startOnLoad: false,
1458
1630
  securityLevel: "strict",
1459
1631
  theme: prefersDark(ref.current) ? "dark" : "default"
1460
1632
  });
1633
+ await mermaid.parse(entry.code);
1461
1634
  const id = `es-mermaid-${Math.random().toString(36).slice(2)}`;
1462
1635
  const { svg: rendered } = await mermaid.render(id, entry.code);
1463
- if (!cancelled) setSvg(rendered);
1464
- } catch {
1465
- if (!cancelled) setSvg(null);
1636
+ if (!cancelled) {
1637
+ setSvg(rendered);
1638
+ setError(null);
1639
+ }
1640
+ } catch (err2) {
1641
+ if (!cancelled) {
1642
+ setSvg(null);
1643
+ setError(err2 instanceof Error ? err2.message : String(err2));
1644
+ }
1466
1645
  }
1467
1646
  };
1468
1647
  void draw();
@@ -1476,8 +1655,8 @@ function MermaidView({ entry, load }) {
1476
1655
  }, [entry.code, load]);
1477
1656
  if (svg) {
1478
1657
  return /* @__PURE__ */ jsxs23("figure", { ref, className: "my-3", children: [
1479
- entry.title ? /* @__PURE__ */ jsx35("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1480
- /* @__PURE__ */ jsx35(
1658
+ entry.title ? /* @__PURE__ */ jsx36("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1659
+ /* @__PURE__ */ jsx36(
1481
1660
  "div",
1482
1661
  {
1483
1662
  role: "img",
@@ -1488,18 +1667,32 @@ function MermaidView({ entry, load }) {
1488
1667
  )
1489
1668
  ] });
1490
1669
  }
1491
- return /* @__PURE__ */ jsx35(MermaidSource, { entry, ref });
1670
+ return /* @__PURE__ */ jsxs23(Fragment11, { children: [
1671
+ error ? /* @__PURE__ */ jsxs23(
1672
+ "p",
1673
+ {
1674
+ role: "alert",
1675
+ "data-es-mermaid-error": true,
1676
+ className: "mt-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
1677
+ children: [
1678
+ "Diagram failed to render: ",
1679
+ error
1680
+ ]
1681
+ }
1682
+ ) : null,
1683
+ /* @__PURE__ */ jsx36(MermaidSource, { entry, ref })
1684
+ ] });
1492
1685
  }
1493
1686
 
1494
1687
  // src/components/doc/MermaidDiagram.tsx
1495
- import { jsx as jsx36 } from "react/jsx-runtime";
1688
+ import { jsx as jsx37 } from "react/jsx-runtime";
1496
1689
  var mermaidLoader;
1497
1690
  function loadMermaid() {
1498
1691
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1499
1692
  return mermaidLoader;
1500
1693
  }
1501
1694
  function MermaidDiagram({ entry, load = loadMermaid }) {
1502
- return /* @__PURE__ */ jsx36(MermaidView, { entry, load });
1695
+ return /* @__PURE__ */ jsx37(MermaidView, { entry, load });
1503
1696
  }
1504
1697
 
1505
1698
  // src/components/ScenarioExplorer.tsx
@@ -1509,12 +1702,12 @@ import { useState as useState3 } from "react";
1509
1702
  import "react";
1510
1703
  import { Command as CommandPrimitive } from "cmdk";
1511
1704
  import { SearchIcon } from "lucide-react";
1512
- import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1705
+ import { jsx as jsx38, jsxs as jsxs24 } from "react/jsx-runtime";
1513
1706
  function Command({
1514
1707
  className,
1515
1708
  ...props
1516
1709
  }) {
1517
- return /* @__PURE__ */ jsx37(
1710
+ return /* @__PURE__ */ jsx38(
1518
1711
  CommandPrimitive,
1519
1712
  {
1520
1713
  "data-slot": "command",
@@ -1536,8 +1729,8 @@ function CommandInput({
1536
1729
  "data-slot": "command-input-wrapper",
1537
1730
  className: "flex h-9 items-center gap-2 border-b px-3",
1538
1731
  children: [
1539
- /* @__PURE__ */ jsx37(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1540
- /* @__PURE__ */ jsx37(
1732
+ /* @__PURE__ */ jsx38(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1733
+ /* @__PURE__ */ jsx38(
1541
1734
  CommandPrimitive.Input,
1542
1735
  {
1543
1736
  "data-slot": "command-input",
@@ -1556,7 +1749,7 @@ function CommandList({
1556
1749
  className,
1557
1750
  ...props
1558
1751
  }) {
1559
- return /* @__PURE__ */ jsx37(
1752
+ return /* @__PURE__ */ jsx38(
1560
1753
  CommandPrimitive.List,
1561
1754
  {
1562
1755
  "data-slot": "command-list",
@@ -1571,7 +1764,7 @@ function CommandList({
1571
1764
  function CommandEmpty({
1572
1765
  ...props
1573
1766
  }) {
1574
- return /* @__PURE__ */ jsx37(
1767
+ return /* @__PURE__ */ jsx38(
1575
1768
  CommandPrimitive.Empty,
1576
1769
  {
1577
1770
  "data-slot": "command-empty",
@@ -1584,7 +1777,7 @@ function CommandGroup({
1584
1777
  className,
1585
1778
  ...props
1586
1779
  }) {
1587
- return /* @__PURE__ */ jsx37(
1780
+ return /* @__PURE__ */ jsx38(
1588
1781
  CommandPrimitive.Group,
1589
1782
  {
1590
1783
  "data-slot": "command-group",
@@ -1600,7 +1793,7 @@ function CommandItem({
1600
1793
  className,
1601
1794
  ...props
1602
1795
  }) {
1603
- return /* @__PURE__ */ jsx37(
1796
+ return /* @__PURE__ */ jsx38(
1604
1797
  CommandPrimitive.Item,
1605
1798
  {
1606
1799
  "data-slot": "command-item",
@@ -1614,7 +1807,7 @@ function CommandItem({
1614
1807
  }
1615
1808
 
1616
1809
  // src/components/ScenarioExplorer.tsx
1617
- import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
1810
+ import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
1618
1811
  var STATUS_FILTERS = [
1619
1812
  { value: "all", label: "All" },
1620
1813
  { value: "passed", label: "Passed" },
@@ -1640,7 +1833,7 @@ function ScenarioExplorer({ scenarios, summary }) {
1640
1833
  " failed"
1641
1834
  ] })
1642
1835
  ] }) : null,
1643
- /* @__PURE__ */ jsx38("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx38(
1836
+ /* @__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(
1644
1837
  "button",
1645
1838
  {
1646
1839
  type: "button",
@@ -1661,20 +1854,20 @@ function ScenarioExplorer({ scenarios, summary }) {
1661
1854
  className: "rounded-lg border border-border bg-card",
1662
1855
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1663
1856
  children: [
1664
- /* @__PURE__ */ jsx38(CommandInput, { placeholder: "Search scenarios\u2026" }),
1857
+ /* @__PURE__ */ jsx39(CommandInput, { placeholder: "Search scenarios\u2026" }),
1665
1858
  /* @__PURE__ */ jsxs25(CommandList, { className: "max-h-none", children: [
1666
- /* @__PURE__ */ jsx38(CommandEmpty, { children: "No scenarios match your filters." }),
1667
- /* @__PURE__ */ jsx38(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx38(
1859
+ /* @__PURE__ */ jsx39(CommandEmpty, { children: "No scenarios match your filters." }),
1860
+ /* @__PURE__ */ jsx39(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx39(
1668
1861
  CommandItem,
1669
1862
  {
1670
1863
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1671
1864
  asChild: true,
1672
1865
  className: "cursor-pointer",
1673
1866
  children: /* @__PURE__ */ jsxs25("a", { href: s.href, className: "flex items-center gap-3", children: [
1674
- /* @__PURE__ */ jsx38(Badge, { variant: s.status, children: s.status }),
1675
- /* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1676
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx38(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1677
- /* @__PURE__ */ jsx38("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1867
+ /* @__PURE__ */ jsx39(Badge, { variant: s.status, children: s.status }),
1868
+ /* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1869
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx39(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1870
+ /* @__PURE__ */ jsx39("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1678
1871
  ] })
1679
1872
  },
1680
1873
  s.id
@@ -2170,6 +2363,9 @@ var story_report_v1_default = {
2170
2363
  {
2171
2364
  $ref: "#/$defs/DocHtml"
2172
2365
  },
2366
+ {
2367
+ $ref: "#/$defs/DocState"
2368
+ },
2173
2369
  {
2174
2370
  $ref: "#/$defs/DocCustom"
2175
2371
  }
@@ -2545,6 +2741,33 @@ var story_report_v1_default = {
2545
2741
  }
2546
2742
  ]
2547
2743
  },
2744
+ DocState: {
2745
+ type: "object",
2746
+ properties: {
2747
+ kind: {
2748
+ const: "state"
2749
+ },
2750
+ label: {
2751
+ type: "string"
2752
+ },
2753
+ value: {},
2754
+ phase: {
2755
+ $ref: "#/$defs/DocPhase"
2756
+ },
2757
+ children: {
2758
+ type: "array",
2759
+ items: {
2760
+ $ref: "#/$defs/DocEntry"
2761
+ }
2762
+ }
2763
+ },
2764
+ required: [
2765
+ "kind",
2766
+ "value",
2767
+ "phase"
2768
+ ],
2769
+ additionalProperties: false
2770
+ },
2548
2771
  DocCustom: {
2549
2772
  type: "object",
2550
2773
  properties: {