executable-stories-react 0.11.0 → 0.13.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
@@ -289,23 +289,48 @@ function useReport() {
289
289
  // src/components/ReportScenario.tsx
290
290
  import { formatDuration as formatDuration3 } from "executable-stories-core/utils/duration";
291
291
 
292
+ // src/lib/step-params.tsx
293
+ import { jsx as jsx3 } from "react/jsx-runtime";
294
+ var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
295
+ function highlightStepParams(text) {
296
+ const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
297
+ if (matches.length === 0) return text;
298
+ const nodes = [];
299
+ let lastIndex = 0;
300
+ matches.forEach((match, i) => {
301
+ const start = match.index;
302
+ const end = start + match[0].length;
303
+ if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
304
+ nodes.push(
305
+ /* @__PURE__ */ jsx3("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
306
+ );
307
+ lastIndex = end;
308
+ });
309
+ if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
310
+ return nodes;
311
+ }
312
+
292
313
  // src/components/ReportSteps.tsx
314
+ import {
315
+ assertionState,
316
+ assertiveSteps
317
+ } from "executable-stories-core/utils/assertive-steps";
293
318
  import { formatDuration } from "executable-stories-core/utils/duration";
294
319
 
295
320
  // src/components/doc/DocNote.tsx
296
- import { jsx as jsx3 } from "react/jsx-runtime";
321
+ import { jsx as jsx4 } from "react/jsx-runtime";
297
322
  function DocNote({ entry }) {
298
- return /* @__PURE__ */ jsx3("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
323
+ return /* @__PURE__ */ jsx4("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
299
324
  }
300
325
 
301
326
  // src/components/doc/DocTag.tsx
302
- import { jsx as jsx4 } from "react/jsx-runtime";
327
+ import { jsx as jsx5 } from "react/jsx-runtime";
303
328
  function DocTag({ entry }) {
304
- return /* @__PURE__ */ jsx4("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(Badge, { variant: "tag", children: n }) }, n)) });
329
+ return /* @__PURE__ */ jsx5("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsx5(Badge, { variant: "tag", children: n }) }, n)) });
305
330
  }
306
331
 
307
332
  // src/components/doc/DocKv.tsx
308
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
333
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
309
334
  function formatValue(value) {
310
335
  if (value === null) return "null";
311
336
  if (typeof value === "string") return value;
@@ -318,8 +343,8 @@ function formatValue(value) {
318
343
  }
319
344
  function DocKv({ entry }) {
320
345
  return /* @__PURE__ */ jsxs2("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
321
- /* @__PURE__ */ jsx5("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
322
- /* @__PURE__ */ jsx5("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
346
+ /* @__PURE__ */ jsx6("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
347
+ /* @__PURE__ */ jsx6("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
323
348
  ] });
324
349
  }
325
350
 
@@ -337,37 +362,37 @@ function useBuiltinRenderers() {
337
362
  }
338
363
 
339
364
  // src/components/doc/DocCode.tsx
340
- import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
365
+ import { Fragment, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
341
366
  function CodeFigure({ label, children }) {
342
367
  return /* @__PURE__ */ jsxs3("figure", { className: "my-3", children: [
343
- label ? /* @__PURE__ */ jsx6("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
344
- /* @__PURE__ */ jsx6("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
368
+ label ? /* @__PURE__ */ jsx7("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
369
+ /* @__PURE__ */ jsx7("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
345
370
  ] });
346
371
  }
347
372
  function DocCode({ entry }) {
348
373
  const renderers = useBuiltinRenderers();
349
374
  if (renderers.code) {
350
- return /* @__PURE__ */ jsx6(Fragment, { children: renderers.code(entry) });
375
+ return /* @__PURE__ */ jsx7(Fragment, { children: renderers.code(entry) });
351
376
  }
352
- return /* @__PURE__ */ jsx6(CodeFigure, { label: entry.label, children: /* @__PURE__ */ jsx6("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
377
+ return /* @__PURE__ */ jsx7(CodeFigure, { label: entry.label, children: /* @__PURE__ */ jsx7("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
353
378
  }
354
379
 
355
380
  // src/components/doc/DocTable.tsx
356
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
381
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
357
382
  function DocTable({ entry }) {
358
383
  return /* @__PURE__ */ jsxs4("figure", { className: "my-3", children: [
359
- entry.label ? /* @__PURE__ */ jsx7("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
360
- /* @__PURE__ */ jsx7("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs4("table", { className: "w-full border-collapse text-sm", children: [
361
- /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsx7("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ jsx7("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
362
- /* @__PURE__ */ jsx7("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ jsx7("tr", { children: row.map((cell, j) => /* @__PURE__ */ jsx7("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
384
+ entry.label ? /* @__PURE__ */ jsx8("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
385
+ /* @__PURE__ */ jsx8("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs4("table", { className: "w-full border-collapse text-sm", children: [
386
+ /* @__PURE__ */ jsx8("thead", { children: /* @__PURE__ */ jsx8("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ jsx8("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
387
+ /* @__PURE__ */ jsx8("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ jsx8("tr", { children: row.map((cell, j) => /* @__PURE__ */ jsx8("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
363
388
  ] }) })
364
389
  ] });
365
390
  }
366
391
 
367
392
  // src/components/doc/DocLink.tsx
368
- import { jsx as jsx8 } from "react/jsx-runtime";
393
+ import { jsx as jsx9 } from "react/jsx-runtime";
369
394
  function DocLink({ entry }) {
370
- return /* @__PURE__ */ jsx8(
395
+ return /* @__PURE__ */ jsx9(
371
396
  "a",
372
397
  {
373
398
  className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
@@ -401,16 +426,16 @@ function neutralizeUrl(value) {
401
426
  }
402
427
 
403
428
  // src/components/doc/DocSection.tsx
404
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
429
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
405
430
  function DocSection({ entry }) {
406
431
  const renderers = useBuiltinRenderers();
407
432
  if (renderers.section) {
408
- return /* @__PURE__ */ jsx9(Fragment2, { children: renderers.section(entry) });
433
+ return /* @__PURE__ */ jsx10(Fragment2, { children: renderers.section(entry) });
409
434
  }
410
435
  const html = safeMarkdownHtml(entry.markdown);
411
436
  return /* @__PURE__ */ jsxs5("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
412
- entry.title ? /* @__PURE__ */ jsx9("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
413
- /* @__PURE__ */ jsx9(
437
+ entry.title ? /* @__PURE__ */ jsx10("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
438
+ /* @__PURE__ */ jsx10(
414
439
  "div",
415
440
  {
416
441
  className: "es-doc-prose prose prose-sm max-w-none",
@@ -421,11 +446,11 @@ function DocSection({ entry }) {
421
446
  }
422
447
 
423
448
  // src/components/doc/DocMermaid.tsx
424
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
449
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
425
450
  function MermaidSource({ entry, ref }) {
426
451
  return /* @__PURE__ */ jsxs6("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
427
- entry.title ? /* @__PURE__ */ jsx10("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
428
- /* @__PURE__ */ jsx10(
452
+ entry.title ? /* @__PURE__ */ jsx11("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
453
+ /* @__PURE__ */ jsx11(
429
454
  "pre",
430
455
  {
431
456
  "data-mermaid": true,
@@ -439,24 +464,24 @@ function MermaidSource({ entry, ref }) {
439
464
  function DocMermaid({ entry }) {
440
465
  const renderers = useBuiltinRenderers();
441
466
  if (renderers.mermaid) {
442
- return /* @__PURE__ */ jsx10(Fragment3, { children: renderers.mermaid(entry) });
467
+ return /* @__PURE__ */ jsx11(Fragment3, { children: renderers.mermaid(entry) });
443
468
  }
444
- return /* @__PURE__ */ jsx10(MermaidSource, { entry });
469
+ return /* @__PURE__ */ jsx11(MermaidSource, { entry });
445
470
  }
446
471
 
447
472
  // src/components/doc/DocScreenshot.tsx
448
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
473
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
449
474
  function DocScreenshot({ entry }) {
450
475
  const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
451
476
  if (!src) {
452
477
  return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
453
- /* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Screenshot unavailable" }),
454
- /* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
455
- entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
478
+ /* @__PURE__ */ jsx12("div", { className: "font-medium", children: "Screenshot unavailable" }),
479
+ /* @__PURE__ */ jsx12("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
480
+ entry.alt ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
456
481
  ] });
457
482
  }
458
483
  return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
459
- /* @__PURE__ */ jsx11(
484
+ /* @__PURE__ */ jsx12(
460
485
  "img",
461
486
  {
462
487
  src,
@@ -465,24 +490,24 @@ function DocScreenshot({ entry }) {
465
490
  className: "max-w-full rounded-md border border-border"
466
491
  }
467
492
  ),
468
- entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
493
+ entry.alt ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
469
494
  ] });
470
495
  }
471
496
 
472
497
  // src/components/doc/DocVideo.tsx
473
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
498
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
474
499
  function DocVideo({ entry }) {
475
500
  if (isLocalFsPath(entry.path)) {
476
501
  return /* @__PURE__ */ jsxs8("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
477
- /* @__PURE__ */ jsx12("div", { className: "font-medium", children: "Video unavailable" }),
478
- /* @__PURE__ */ jsx12("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
479
- entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
502
+ /* @__PURE__ */ jsx13("div", { className: "font-medium", children: "Video unavailable" }),
503
+ /* @__PURE__ */ jsx13("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
504
+ entry.caption ? /* @__PURE__ */ jsx13("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
480
505
  ] });
481
506
  }
482
507
  const src = safeUrl(entry.path);
483
508
  const poster = safeUrl(entry.poster);
484
509
  return /* @__PURE__ */ jsxs8("figure", { className: "my-3", children: [
485
- /* @__PURE__ */ jsx12(
510
+ /* @__PURE__ */ jsx13(
486
511
  "video",
487
512
  {
488
513
  controls: true,
@@ -492,12 +517,12 @@ function DocVideo({ entry }) {
492
517
  className: "max-w-full rounded-md border border-border"
493
518
  }
494
519
  ),
495
- entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
520
+ entry.caption ? /* @__PURE__ */ jsx13("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
496
521
  ] });
497
522
  }
498
523
 
499
524
  // src/components/doc/DocHtml.tsx
500
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
525
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
501
526
  function DocHtml({ entry }) {
502
527
  const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
503
528
  const title = entry.title ?? "Embedded HTML";
@@ -505,8 +530,8 @@ function DocHtml({ entry }) {
505
530
  const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
506
531
  return /* @__PURE__ */ jsxs9("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
507
532
  /* @__PURE__ */ jsxs9("figcaption", { className: "flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground", children: [
508
- /* @__PURE__ */ jsx13("span", { children: entry.title ?? "HTML" }),
509
- safeHref ? /* @__PURE__ */ jsx13(
533
+ /* @__PURE__ */ jsx14("span", { children: entry.title ?? "HTML" }),
534
+ safeHref ? /* @__PURE__ */ jsx14(
510
535
  "a",
511
536
  {
512
537
  href: safeHref,
@@ -519,7 +544,7 @@ function DocHtml({ entry }) {
519
544
  }
520
545
  ) : null
521
546
  ] }),
522
- /* @__PURE__ */ jsx13(
547
+ /* @__PURE__ */ jsx14(
523
548
  "iframe",
524
549
  {
525
550
  ...frameProps,
@@ -534,7 +559,7 @@ function DocHtml({ entry }) {
534
559
  }
535
560
 
536
561
  // src/components/doc/DocState.tsx
537
- import { jsx as jsx14 } from "react/jsx-runtime";
562
+ import { jsx as jsx15 } from "react/jsx-runtime";
538
563
  function DocState({ entry }) {
539
564
  let json;
540
565
  try {
@@ -542,20 +567,20 @@ function DocState({ entry }) {
542
567
  } catch {
543
568
  json = String(entry.value);
544
569
  }
545
- return /* @__PURE__ */ jsx14(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx14("code", { className: "font-mono text-xs language-json", children: json }) });
570
+ return /* @__PURE__ */ jsx15(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx15("code", { className: "font-mono text-xs language-json", children: json }) });
546
571
  }
547
572
 
548
573
  // src/components/doc/DocCustom.tsx
549
- import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
574
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
550
575
  function DocCustom({ entry }) {
551
576
  const renderers = useCustomRenderers();
552
577
  const renderer = renderers[entry.type];
553
578
  if (renderer) {
554
- return /* @__PURE__ */ jsx15(Fragment4, { children: renderer(entry) });
579
+ return /* @__PURE__ */ jsx16(Fragment4, { children: renderer(entry) });
555
580
  }
556
581
  return /* @__PURE__ */ jsxs10("div", { className: "my-2", "data-type": entry.type, children: [
557
- /* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
558
- /* @__PURE__ */ jsx15("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify2(entry.data) })
582
+ /* @__PURE__ */ jsx16("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
583
+ /* @__PURE__ */ jsx16("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify2(entry.data) })
559
584
  ] });
560
585
  }
561
586
  function safeStringify2(value) {
@@ -567,64 +592,43 @@ function safeStringify2(value) {
567
592
  }
568
593
 
569
594
  // src/components/doc/DocEntry.tsx
570
- import { jsx as jsx16 } from "react/jsx-runtime";
595
+ import { jsx as jsx17 } from "react/jsx-runtime";
571
596
  function DocEntry({ entry }) {
572
597
  switch (entry.kind) {
573
598
  case "note":
574
- return /* @__PURE__ */ jsx16(DocNote, { entry });
599
+ return /* @__PURE__ */ jsx17(DocNote, { entry });
575
600
  case "tag":
576
- return /* @__PURE__ */ jsx16(DocTag, { entry });
601
+ return /* @__PURE__ */ jsx17(DocTag, { entry });
577
602
  case "kv":
578
- return /* @__PURE__ */ jsx16(DocKv, { entry });
603
+ return /* @__PURE__ */ jsx17(DocKv, { entry });
579
604
  case "code":
580
- return /* @__PURE__ */ jsx16(DocCode, { entry });
605
+ return /* @__PURE__ */ jsx17(DocCode, { entry });
581
606
  case "table":
582
- return /* @__PURE__ */ jsx16(DocTable, { entry });
607
+ return /* @__PURE__ */ jsx17(DocTable, { entry });
583
608
  case "link":
584
- return /* @__PURE__ */ jsx16(DocLink, { entry });
609
+ return /* @__PURE__ */ jsx17(DocLink, { entry });
585
610
  case "section":
586
- return /* @__PURE__ */ jsx16(DocSection, { entry });
611
+ return /* @__PURE__ */ jsx17(DocSection, { entry });
587
612
  case "mermaid":
588
- return /* @__PURE__ */ jsx16(DocMermaid, { entry });
613
+ return /* @__PURE__ */ jsx17(DocMermaid, { entry });
589
614
  case "screenshot":
590
- return /* @__PURE__ */ jsx16(DocScreenshot, { entry });
615
+ return /* @__PURE__ */ jsx17(DocScreenshot, { entry });
591
616
  case "video":
592
- return /* @__PURE__ */ jsx16(DocVideo, { entry });
617
+ return /* @__PURE__ */ jsx17(DocVideo, { entry });
593
618
  case "html":
594
- return /* @__PURE__ */ jsx16(DocHtml, { entry });
619
+ return /* @__PURE__ */ jsx17(DocHtml, { entry });
595
620
  case "state":
596
- return /* @__PURE__ */ jsx16(DocState, { entry });
621
+ return /* @__PURE__ */ jsx17(DocState, { entry });
597
622
  case "custom":
598
- return /* @__PURE__ */ jsx16(DocCustom, { entry });
623
+ return /* @__PURE__ */ jsx17(DocCustom, { entry });
599
624
  }
600
625
  }
601
626
 
602
627
  // src/components/ReportDocEntries.tsx
603
- import { Fragment as Fragment5, jsx as jsx17 } from "react/jsx-runtime";
628
+ import { Fragment as Fragment5, jsx as jsx18 } from "react/jsx-runtime";
604
629
  function ReportDocEntries({ entries }) {
605
630
  if (entries.length === 0) return null;
606
- return /* @__PURE__ */ jsx17(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx17(DocEntry, { entry }, i)) });
607
- }
608
-
609
- // src/lib/step-params.tsx
610
- import { jsx as jsx18 } from "react/jsx-runtime";
611
- var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
612
- function highlightStepParams(text) {
613
- const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
614
- if (matches.length === 0) return text;
615
- const nodes = [];
616
- let lastIndex = 0;
617
- matches.forEach((match, i) => {
618
- const start = match.index;
619
- const end = start + match[0].length;
620
- if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
621
- nodes.push(
622
- /* @__PURE__ */ jsx18("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
623
- );
624
- lastIndex = end;
625
- });
626
- if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
627
- return nodes;
631
+ return /* @__PURE__ */ jsx18(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx18(DocEntry, { entry }, i)) });
628
632
  }
629
633
 
630
634
  // src/components/ReportSteps.tsx
@@ -643,9 +647,22 @@ var STEP_GLYPH_COLOR = {
643
647
  };
644
648
  function ReportSteps({ scenario }) {
645
649
  if (scenario.steps.length === 0) return null;
646
- return /* @__PURE__ */ jsx19("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx19(ReportStepItem, { step }, step.id)) });
650
+ const unasserted = new Set(
651
+ assertionState(scenario.steps) === "unasserted" ? assertiveSteps(scenario.steps).map((step) => step.id) : []
652
+ );
653
+ return /* @__PURE__ */ jsx19("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx19(
654
+ ReportStepItem,
655
+ {
656
+ step,
657
+ unasserted: unasserted.has(step.id)
658
+ },
659
+ step.id
660
+ )) });
647
661
  }
648
- function ReportStepItem({ step }) {
662
+ function ReportStepItem({
663
+ step,
664
+ unasserted = false
665
+ }) {
649
666
  const kw = step.keyword.toLowerCase();
650
667
  const continuation = kw === "and" || kw === "but";
651
668
  return /* @__PURE__ */ jsxs11(
@@ -653,10 +670,23 @@ function ReportStepItem({ step }) {
653
670
  {
654
671
  id: step.id,
655
672
  "data-status": step.status,
656
- className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
673
+ className: cn(
674
+ "py-1.5 text-[0.8125rem] leading-normal",
675
+ continuation && "pl-5"
676
+ ),
657
677
  children: [
658
678
  /* @__PURE__ */ jsxs11("div", { className: "flex items-baseline gap-2", children: [
659
- /* @__PURE__ */ jsx19("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" }),
679
+ /* @__PURE__ */ jsx19(
680
+ "span",
681
+ {
682
+ "aria-hidden": true,
683
+ className: cn(
684
+ "w-4 shrink-0 text-center text-xs",
685
+ STEP_GLYPH_COLOR[step.status]
686
+ ),
687
+ children: STEP_GLYPH[step.status] ?? "\u25CB"
688
+ }
689
+ ),
660
690
  /* @__PURE__ */ jsx19(
661
691
  "span",
662
692
  {
@@ -668,6 +698,7 @@ function ReportStepItem({ step }) {
668
698
  }
669
699
  ),
670
700
  /* @__PURE__ */ jsx19("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
701
+ unasserted ? /* @__PURE__ */ jsx19("span", { className: "shrink-0 rounded-full border border-pend-border bg-pend-bg px-2 py-0.5 text-[0.6875rem] font-medium text-pend", children: "No assertion" }) : null,
671
702
  step.durationMs > 0 ? /* @__PURE__ */ jsx19("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
672
703
  ] }),
673
704
  step.errorMessage ? /* @__PURE__ */ jsx19(
@@ -1063,21 +1094,104 @@ function ScenarioRunHistory({ scenarioId }) {
1063
1094
  ] });
1064
1095
  }
1065
1096
 
1097
+ // src/components/ScenarioStaleness.tsx
1098
+ import { useEffect, useState } from "react";
1099
+
1100
+ // src/lib/provenance.ts
1101
+ function reportLastRunMs(report) {
1102
+ if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
1103
+ if (report.startedAtMs && report.startedAtMs > 0) return report.startedAtMs;
1104
+ return void 0;
1105
+ }
1106
+ function scenarioLastRunMs(scenario, report) {
1107
+ if (scenario.lastRunAtMs && scenario.lastRunAtMs > 0) return scenario.lastRunAtMs;
1108
+ return reportLastRunMs(report);
1109
+ }
1110
+ function formatRelativeAge(thenMs, nowMs) {
1111
+ const deltaMs = Math.max(0, nowMs - thenMs);
1112
+ const minutes = Math.floor(deltaMs / 6e4);
1113
+ if (minutes < 1) return "just now";
1114
+ if (minutes < 60) return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
1115
+ const hours = Math.floor(minutes / 60);
1116
+ if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
1117
+ const days = Math.floor(hours / 24);
1118
+ return `${days} day${days === 1 ? "" : "s"} ago`;
1119
+ }
1120
+ function isReportStale(lastRunMs, staleAfterDays, nowMs) {
1121
+ if (lastRunMs === void 0 || staleAfterDays <= 0) return false;
1122
+ return nowMs - lastRunMs >= staleAfterDays * 864e5;
1123
+ }
1124
+ var CI_DISPLAY_NAMES = {
1125
+ github: "GitHub Actions",
1126
+ gitlab: "GitLab CI",
1127
+ circleci: "CircleCI",
1128
+ jenkins: "Jenkins",
1129
+ azure: "Azure DevOps",
1130
+ buildkite: "Buildkite",
1131
+ travis: "Travis CI",
1132
+ ci: "CI"
1133
+ };
1134
+ function ciDisplayName(name) {
1135
+ return CI_DISPLAY_NAMES[name] ?? name;
1136
+ }
1137
+ function commitUrl(ci, sha) {
1138
+ const commitSha = ci?.commitSha ?? sha;
1139
+ if (!ci?.url || !commitSha) return void 0;
1140
+ const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
1141
+ if (github) return `${github[1]}/commit/${commitSha}`;
1142
+ const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
1143
+ if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
1144
+ return void 0;
1145
+ }
1146
+ function prUrl(ci) {
1147
+ if (!ci?.url || !ci.prNumber) return void 0;
1148
+ const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
1149
+ if (github) return `${github[1]}/pull/${ci.prNumber}`;
1150
+ return void 0;
1151
+ }
1152
+
1153
+ // src/interactive/scenario-freshness-context.tsx
1154
+ import { createContext as createContext3, useContext as useContext4 } from "react";
1155
+ var ScenarioFreshnessContext = createContext3(null);
1156
+ var ScenarioFreshnessProvider = ScenarioFreshnessContext.Provider;
1157
+ function useScenarioFreshness() {
1158
+ return useContext4(ScenarioFreshnessContext);
1159
+ }
1160
+
1161
+ // src/components/ScenarioStaleness.tsx
1162
+ import { jsxs as jsxs16 } from "react/jsx-runtime";
1163
+ function ScenarioStaleness({ scenario }) {
1164
+ const freshness = useScenarioFreshness();
1165
+ const fixedNow = freshness?.nowMs;
1166
+ const [now, setNow] = useState(fixedNow);
1167
+ useEffect(() => {
1168
+ if (fixedNow === void 0) setNow(Date.now());
1169
+ }, [fixedNow]);
1170
+ if (!freshness || now === void 0) return null;
1171
+ const lastRunAtMs = scenario.lastRunAtMs;
1172
+ if (!lastRunAtMs || lastRunAtMs <= 0) return null;
1173
+ if (!isReportStale(lastRunAtMs, freshness.staleAfterDays, now)) return null;
1174
+ return /* @__PURE__ */ jsxs16(Badge, { variant: "outline", "aria-label": "Scenario freshness", children: [
1175
+ "Last ran ",
1176
+ formatRelativeAge(lastRunAtMs, now)
1177
+ ] });
1178
+ }
1179
+
1066
1180
  // src/interactive/collapse-context.ts
1067
- import { createContext as createContext3, useCallback, useContext as useContext4, useState } from "react";
1068
- var CollapseContext = createContext3(null);
1181
+ import { createContext as createContext4, useCallback, useContext as useContext5, useState as useState2 } from "react";
1182
+ var CollapseContext = createContext4(null);
1069
1183
  var CollapseProvider = CollapseContext.Provider;
1070
1184
  function useCollapse() {
1071
- return useContext4(CollapseContext);
1185
+ return useContext5(CollapseContext);
1072
1186
  }
1073
1187
 
1074
1188
  // src/interactive/scenario-actions.tsx
1075
- import { createContext as createContext4, useContext as useContext5 } from "react";
1189
+ import { createContext as createContext5, useContext as useContext6 } from "react";
1076
1190
  import { scenarioToMarkdown as coreScenarioToMarkdown } from "executable-stories-core/utils/scenario-markdown";
1077
- var ScenarioActionsContext = createContext4(null);
1191
+ var ScenarioActionsContext = createContext5(null);
1078
1192
  var ScenarioActionsProvider = ScenarioActionsContext.Provider;
1079
1193
  function useScenarioActions() {
1080
- return useContext5(ScenarioActionsContext);
1194
+ return useContext6(ScenarioActionsContext);
1081
1195
  }
1082
1196
 
1083
1197
  // src/components/ui/card.tsx
@@ -1124,7 +1238,7 @@ function CardContent({ className, ...props }) {
1124
1238
  import "react";
1125
1239
  import { Menu as MenuPrimitive } from "@base-ui/react/menu";
1126
1240
  import { CheckIcon } from "lucide-react";
1127
- import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
1241
+ import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
1128
1242
  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";
1129
1243
  function DropdownMenu(props) {
1130
1244
  return /* @__PURE__ */ jsx25(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
@@ -1175,7 +1289,7 @@ function DropdownMenuItem({
1175
1289
 
1176
1290
  // src/components/ReportScenario.tsx
1177
1291
  import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
1178
- import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
1292
+ import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
1179
1293
  var STATUS_META = {
1180
1294
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
1181
1295
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -1191,7 +1305,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
1191
1305
  const collapsible = collapse !== null && !hideTitle;
1192
1306
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
1193
1307
  const actions = useScenarioActions();
1194
- return /* @__PURE__ */ jsxs17(
1308
+ return /* @__PURE__ */ jsxs18(
1195
1309
  Card,
1196
1310
  {
1197
1311
  id: scenario.id,
@@ -1199,9 +1313,9 @@ function ReportScenario({ scenario, hideTitle = false }) {
1199
1313
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
1200
1314
  className: "gap-0 py-0",
1201
1315
  children: [
1202
- /* @__PURE__ */ jsxs17(CardHeader, { className: "px-4 py-3", children: [
1203
- /* @__PURE__ */ jsxs17("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1204
- hideTitle ? null : /* @__PURE__ */ jsxs17("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1316
+ /* @__PURE__ */ jsxs18(CardHeader, { className: "px-4 py-3", children: [
1317
+ /* @__PURE__ */ jsxs18("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1318
+ hideTitle ? null : /* @__PURE__ */ jsxs18("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1205
1319
  collapsible ? /* @__PURE__ */ jsx26(
1206
1320
  "button",
1207
1321
  {
@@ -1217,11 +1331,12 @@ function ReportScenario({ scenario, hideTitle = false }) {
1217
1331
  /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1218
1332
  /* @__PURE__ */ jsx26("span", { children: scenario.title })
1219
1333
  ] }),
1220
- /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2", children: [
1334
+ /* @__PURE__ */ jsxs18("div", { className: "flex shrink-0 items-center gap-2", children: [
1221
1335
  /* @__PURE__ */ jsx26(ScenarioRunHistory, { scenarioId: scenario.id }),
1336
+ /* @__PURE__ */ jsx26(ScenarioStaleness, { scenario }),
1222
1337
  scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration3(scenario.durationMs) }) : null,
1223
1338
  meta.showPill ? /* @__PURE__ */ jsx26(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx26("span", { className: "sr-only", children: `Status: ${label}` }),
1224
- actions ? /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
1339
+ actions ? /* @__PURE__ */ jsxs18(DropdownMenu, { children: [
1225
1340
  /* @__PURE__ */ jsx26(
1226
1341
  DropdownMenuTrigger,
1227
1342
  {
@@ -1230,16 +1345,16 @@ function ReportScenario({ scenario, hideTitle = false }) {
1230
1345
  children: /* @__PURE__ */ jsx26(MoreHorizontalIcon, { "aria-hidden": true })
1231
1346
  }
1232
1347
  ),
1233
- /* @__PURE__ */ jsxs17(DropdownMenuContent, { align: "end", children: [
1234
- /* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1348
+ /* @__PURE__ */ jsxs18(DropdownMenuContent, { align: "end", children: [
1349
+ /* @__PURE__ */ jsxs18(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1235
1350
  /* @__PURE__ */ jsx26(LinkIcon, {}),
1236
1351
  " Copy link"
1237
1352
  ] }),
1238
- /* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1353
+ /* @__PURE__ */ jsxs18(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1239
1354
  /* @__PURE__ */ jsx26(FileTextIcon, {}),
1240
1355
  " Copy as Markdown"
1241
1356
  ] }),
1242
- /* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1357
+ /* @__PURE__ */ jsxs18(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1243
1358
  /* @__PURE__ */ jsx26(SparklesIcon, {}),
1244
1359
  " Explain with AI"
1245
1360
  ] })
@@ -1247,12 +1362,12 @@ function ReportScenario({ scenario, hideTitle = false }) {
1247
1362
  ] }) : null
1248
1363
  ] })
1249
1364
  ] }),
1250
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs17("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1365
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs18("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1251
1366
  scenario.tags.map((t) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1252
1367
  (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx26("li", { children: ticket.url ? /* @__PURE__ */ jsx26("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1253
1368
  ] }) : null
1254
1369
  ] }),
1255
- /* @__PURE__ */ jsxs17(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1370
+ /* @__PURE__ */ jsxs18(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1256
1371
  scenario.errorMessage ? /* @__PURE__ */ jsx26(
1257
1372
  "pre",
1258
1373
  {
@@ -1279,12 +1394,12 @@ function ReportScenarioList({ feature }) {
1279
1394
  }
1280
1395
 
1281
1396
  // src/components/ReportFeatureIntro.tsx
1282
- import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
1397
+ import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
1283
1398
  function ReportFeatureIntro({ feature }) {
1284
1399
  const hasNarrative = Boolean(feature.narrative?.trim());
1285
1400
  const hasGlossary = Boolean(feature.glossary?.length);
1286
1401
  if (!hasNarrative && !hasGlossary) return null;
1287
- return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-3 border-l-2 border-border pl-4 text-sm", children: [
1402
+ return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-3 border-l-2 border-border pl-4 text-sm", children: [
1288
1403
  hasNarrative ? /* @__PURE__ */ jsx28(
1289
1404
  "div",
1290
1405
  {
@@ -1292,7 +1407,7 @@ function ReportFeatureIntro({ feature }) {
1292
1407
  dangerouslySetInnerHTML: { __html: safeMarkdownHtml(dedent(feature.narrative)) }
1293
1408
  }
1294
1409
  ) : null,
1295
- hasGlossary ? /* @__PURE__ */ jsx28("dl", { className: "grid gap-1.5", "aria-label": "Glossary", children: feature.glossary.map((entry) => /* @__PURE__ */ jsxs18("div", { className: "flex flex-wrap gap-x-2 text-xs", children: [
1410
+ hasGlossary ? /* @__PURE__ */ jsx28("dl", { className: "grid gap-1.5", "aria-label": "Glossary", children: feature.glossary.map((entry) => /* @__PURE__ */ jsxs19("div", { className: "flex flex-wrap gap-x-2 text-xs", children: [
1296
1411
  /* @__PURE__ */ jsx28("dt", { className: "font-medium text-foreground", children: entry.term }),
1297
1412
  /* @__PURE__ */ jsx28("dd", { className: "flex-1 text-muted-foreground", children: entry.definition })
1298
1413
  ] }, entry.term)) }) : null
@@ -1306,7 +1421,7 @@ function featureKindLabel(kind) {
1306
1421
  }
1307
1422
 
1308
1423
  // src/components/ReportFeature.tsx
1309
- import { Fragment as Fragment9, jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
1424
+ import { Fragment as Fragment9, jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
1310
1425
  function ReportFeature({ feature }) {
1311
1426
  const titleId = `${feature.id}-title`;
1312
1427
  const bodyId = `${feature.id}-body`;
@@ -1318,7 +1433,7 @@ function ReportFeature({ feature }) {
1318
1433
  return (
1319
1434
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1320
1435
  // layer of nesting so the scenario cards below read as the primary unit.
1321
- /* @__PURE__ */ jsxs19(
1436
+ /* @__PURE__ */ jsxs20(
1322
1437
  "section",
1323
1438
  {
1324
1439
  id: feature.id,
@@ -1326,9 +1441,9 @@ function ReportFeature({ feature }) {
1326
1441
  "aria-labelledby": titleId,
1327
1442
  className: "flex flex-col gap-3",
1328
1443
  children: [
1329
- /* @__PURE__ */ jsxs19("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1330
- /* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
1331
- /* @__PURE__ */ jsx29("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs19(
1444
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1445
+ /* @__PURE__ */ jsxs20("div", { className: "min-w-0", children: [
1446
+ /* @__PURE__ */ jsx29("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs20(
1332
1447
  "button",
1333
1448
  {
1334
1449
  type: "button",
@@ -1342,29 +1457,29 @@ function ReportFeature({ feature }) {
1342
1457
  ]
1343
1458
  }
1344
1459
  ) : feature.title }),
1345
- /* @__PURE__ */ jsxs19("p", { className: cn("mt-0.5 flex items-center gap-2 text-xs text-muted-foreground", collapse && "pl-5"), children: [
1460
+ /* @__PURE__ */ jsxs20("p", { className: cn("mt-0.5 flex items-center gap-2 text-xs text-muted-foreground", collapse && "pl-5"), children: [
1346
1461
  kindLabel ? /* @__PURE__ */ jsx29("span", { className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-medium text-foreground", children: kindLabel }) : null,
1347
1462
  /* @__PURE__ */ jsx29("span", { className: "truncate font-mono", children: feature.sourceFile })
1348
1463
  ] })
1349
1464
  ] }),
1350
- /* @__PURE__ */ jsxs19(
1465
+ /* @__PURE__ */ jsxs20(
1351
1466
  "p",
1352
1467
  {
1353
1468
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1354
1469
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1355
1470
  children: [
1356
- /* @__PURE__ */ jsxs19("span", { children: [
1471
+ /* @__PURE__ */ jsxs20("span", { children: [
1357
1472
  s.passed,
1358
1473
  " passed"
1359
1474
  ] }),
1360
1475
  /* @__PURE__ */ jsx29("span", { "aria-hidden": true, children: "\xB7" }),
1361
- /* @__PURE__ */ jsxs19("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1476
+ /* @__PURE__ */ jsxs20("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1362
1477
  s.failed,
1363
1478
  " failed"
1364
1479
  ] }),
1365
- skipped > 0 ? /* @__PURE__ */ jsxs19(Fragment9, { children: [
1480
+ skipped > 0 ? /* @__PURE__ */ jsxs20(Fragment9, { children: [
1366
1481
  /* @__PURE__ */ jsx29("span", { "aria-hidden": true, children: "\xB7" }),
1367
- /* @__PURE__ */ jsxs19("span", { children: [
1482
+ /* @__PURE__ */ jsxs20("span", { children: [
1368
1483
  skipped,
1369
1484
  " skipped"
1370
1485
  ] })
@@ -1373,7 +1488,7 @@ function ReportFeature({ feature }) {
1373
1488
  }
1374
1489
  )
1375
1490
  ] }),
1376
- /* @__PURE__ */ jsxs19("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: [
1491
+ /* @__PURE__ */ jsxs20("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: [
1377
1492
  /* @__PURE__ */ jsx29(ReportFeatureIntro, { feature }),
1378
1493
  /* @__PURE__ */ jsx29(ReportScenarioList, { feature })
1379
1494
  ] })
@@ -1451,7 +1566,7 @@ function ReportEmpty({ message }) {
1451
1566
  }
1452
1567
 
1453
1568
  // src/components/ReportSummary.tsx
1454
- import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
1569
+ import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1455
1570
  function ReportSummary({ className }) {
1456
1571
  const report = useReport();
1457
1572
  return /* @__PURE__ */ jsx33(
@@ -1493,13 +1608,13 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1493
1608
  "aria-label": ariaLabel,
1494
1609
  children: cards.map((c) => {
1495
1610
  const tone = TONE[c.status];
1496
- return /* @__PURE__ */ jsxs20(
1611
+ return /* @__PURE__ */ jsxs21(
1497
1612
  "div",
1498
1613
  {
1499
1614
  "data-status": c.status,
1500
1615
  className: "rounded-lg border bg-card px-4 py-3",
1501
1616
  children: [
1502
- /* @__PURE__ */ jsxs20("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1617
+ /* @__PURE__ */ jsxs21("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1503
1618
  /* @__PURE__ */ jsx33("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1504
1619
  c.label
1505
1620
  ] }),
@@ -1515,58 +1630,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1515
1630
 
1516
1631
  // src/components/ReportMeta.tsx
1517
1632
  import { formatDuration as formatDuration4 } from "executable-stories-core/utils/duration";
1518
-
1519
- // src/lib/provenance.ts
1520
- function reportLastRunMs(report) {
1521
- if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
1522
- if (report.startedAtMs && report.startedAtMs > 0) return report.startedAtMs;
1523
- return void 0;
1524
- }
1525
- function formatRelativeAge(thenMs, nowMs) {
1526
- const deltaMs = Math.max(0, nowMs - thenMs);
1527
- const minutes = Math.floor(deltaMs / 6e4);
1528
- if (minutes < 1) return "just now";
1529
- if (minutes < 60) return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
1530
- const hours = Math.floor(minutes / 60);
1531
- if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
1532
- const days = Math.floor(hours / 24);
1533
- return `${days} day${days === 1 ? "" : "s"} ago`;
1534
- }
1535
- function isReportStale(lastRunMs, staleAfterDays, nowMs) {
1536
- if (lastRunMs === void 0 || staleAfterDays <= 0) return false;
1537
- return nowMs - lastRunMs >= staleAfterDays * 864e5;
1538
- }
1539
- var CI_DISPLAY_NAMES = {
1540
- github: "GitHub Actions",
1541
- gitlab: "GitLab CI",
1542
- circleci: "CircleCI",
1543
- jenkins: "Jenkins",
1544
- azure: "Azure DevOps",
1545
- buildkite: "Buildkite",
1546
- travis: "Travis CI",
1547
- ci: "CI"
1548
- };
1549
- function ciDisplayName(name) {
1550
- return CI_DISPLAY_NAMES[name] ?? name;
1551
- }
1552
- function commitUrl(ci, sha) {
1553
- const commitSha = ci?.commitSha ?? sha;
1554
- if (!ci?.url || !commitSha) return void 0;
1555
- const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
1556
- if (github) return `${github[1]}/commit/${commitSha}`;
1557
- const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
1558
- if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
1559
- return void 0;
1560
- }
1561
- function prUrl(ci) {
1562
- if (!ci?.url || !ci.prNumber) return void 0;
1563
- const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
1564
- if (github) return `${github[1]}/pull/${ci.prNumber}`;
1565
- return void 0;
1566
- }
1567
-
1568
- // src/components/ReportMeta.tsx
1569
- import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
1633
+ import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1570
1634
  function ReportMeta() {
1571
1635
  const report = useReport();
1572
1636
  const items = [];
@@ -1595,7 +1659,7 @@ function ReportMeta() {
1595
1659
  if (report.ci) {
1596
1660
  items.push({
1597
1661
  label: "CI",
1598
- value: report.ci.url ? /* @__PURE__ */ jsxs21("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1662
+ value: report.ci.url ? /* @__PURE__ */ jsxs22("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1599
1663
  ciDisplayName(report.ci.name),
1600
1664
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1601
1665
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1614,12 +1678,12 @@ function ReportMeta() {
1614
1678
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1615
1679
  // collapsed disclosure so it doesn't push the result down. Native <details>
1616
1680
  // so it works with no JS (the SSR/no-hydration report still toggles).
1617
- /* @__PURE__ */ jsxs21("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1618
- /* @__PURE__ */ jsxs21("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: [
1681
+ /* @__PURE__ */ jsxs22("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1682
+ /* @__PURE__ */ jsxs22("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: [
1619
1683
  /* @__PURE__ */ jsx34("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1620
1684
  "Run details"
1621
1685
  ] }),
1622
- /* @__PURE__ */ jsx34("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__ */ jsxs21("div", { className: "flex items-baseline gap-1.5", children: [
1686
+ /* @__PURE__ */ jsx34("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__ */ jsxs22("div", { className: "flex items-baseline gap-1.5", children: [
1623
1687
  /* @__PURE__ */ jsx34("dt", { className: "font-medium", children: item.label }),
1624
1688
  /* @__PURE__ */ jsx34("dd", { className: "font-mono text-foreground", children: item.value })
1625
1689
  ] }, item.label)) })
@@ -1628,18 +1692,18 @@ function ReportMeta() {
1628
1692
  }
1629
1693
 
1630
1694
  // src/components/ReportSchemaError.tsx
1631
- import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
1695
+ import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
1632
1696
  function ReportSchemaError({ error }) {
1633
- return /* @__PURE__ */ jsxs22("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1697
+ return /* @__PURE__ */ jsxs23("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1634
1698
  /* @__PURE__ */ jsx35("p", { children: /* @__PURE__ */ jsx35("strong", { children: "Report could not be displayed." }) }),
1635
1699
  /* @__PURE__ */ jsx35("p", { children: error.message }),
1636
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs22("p", { children: [
1700
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs23("p", { children: [
1637
1701
  "The report bundle is newer than this version of ",
1638
1702
  /* @__PURE__ */ jsx35("code", { children: "executable-stories-react" }),
1639
1703
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1640
1704
  ] }) : null,
1641
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs22("details", { children: [
1642
- /* @__PURE__ */ jsxs22("summary", { children: [
1705
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs23("details", { children: [
1706
+ /* @__PURE__ */ jsxs23("summary", { children: [
1643
1707
  error.issues.length,
1644
1708
  " validation issue",
1645
1709
  error.issues.length === 1 ? "" : "s"
@@ -1650,9 +1714,9 @@ function ReportSchemaError({ error }) {
1650
1714
  }
1651
1715
 
1652
1716
  // src/components/ReportShell.tsx
1653
- import { Fragment as Fragment10, jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1717
+ import { Fragment as Fragment10, jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
1654
1718
  function ReportTitleBlock({ title }) {
1655
- return /* @__PURE__ */ jsxs23(Fragment10, { children: [
1719
+ return /* @__PURE__ */ jsxs24(Fragment10, { children: [
1656
1720
  /* @__PURE__ */ jsx36("h1", { children: title ?? "Story Report" }),
1657
1721
  /* @__PURE__ */ jsx36(ReportSummary, {}),
1658
1722
  /* @__PURE__ */ jsx36(ReportMeta, {})
@@ -1668,7 +1732,7 @@ function ReportErrorShell({
1668
1732
  }
1669
1733
 
1670
1734
  // src/components/Report.tsx
1671
- import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1735
+ import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
1672
1736
  function Report(props) {
1673
1737
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1674
1738
  const result = unwrapReport(report);
@@ -1677,15 +1741,15 @@ function Report(props) {
1677
1741
  }
1678
1742
  const data = result.data;
1679
1743
  const hasContent = data.features.length > 0;
1680
- return /* @__PURE__ */ jsx37(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs24("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1744
+ return /* @__PURE__ */ jsx37(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs25("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1681
1745
  /* @__PURE__ */ jsx37("header", { className: "es-report-header", children: /* @__PURE__ */ jsx37(ReportTitleBlock, { title }) }),
1682
1746
  hasContent ? /* @__PURE__ */ jsx37(ReportFeatureList, {}) : /* @__PURE__ */ jsx37(ReportEmpty, {})
1683
1747
  ] }) });
1684
1748
  }
1685
1749
 
1686
1750
  // src/components/doc/MermaidView.tsx
1687
- import { useEffect, useRef, useState as useState2 } from "react";
1688
- import { Fragment as Fragment11, jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
1751
+ import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
1752
+ import { Fragment as Fragment11, jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
1689
1753
  function prefersDark(el) {
1690
1754
  const themed = el?.closest("[data-theme]");
1691
1755
  if (themed?.dataset.theme === "dark") return true;
@@ -1694,9 +1758,9 @@ function prefersDark(el) {
1694
1758
  }
1695
1759
  function MermaidView({ entry, load }) {
1696
1760
  const ref = useRef(null);
1697
- const [svg, setSvg] = useState2(null);
1698
- const [error, setError] = useState2(null);
1699
- useEffect(() => {
1761
+ const [svg, setSvg] = useState3(null);
1762
+ const [error, setError] = useState3(null);
1763
+ useEffect2(() => {
1700
1764
  let cancelled = false;
1701
1765
  const draw = async () => {
1702
1766
  let mermaid;
@@ -1739,7 +1803,7 @@ function MermaidView({ entry, load }) {
1739
1803
  };
1740
1804
  }, [entry.code, load]);
1741
1805
  if (svg) {
1742
- return /* @__PURE__ */ jsxs25("figure", { ref, className: "my-3", children: [
1806
+ return /* @__PURE__ */ jsxs26("figure", { ref, className: "my-3", children: [
1743
1807
  entry.title ? /* @__PURE__ */ jsx38("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1744
1808
  /* @__PURE__ */ jsx38(
1745
1809
  "div",
@@ -1752,8 +1816,8 @@ function MermaidView({ entry, load }) {
1752
1816
  )
1753
1817
  ] });
1754
1818
  }
1755
- return /* @__PURE__ */ jsxs25(Fragment11, { children: [
1756
- error ? /* @__PURE__ */ jsxs25(
1819
+ return /* @__PURE__ */ jsxs26(Fragment11, { children: [
1820
+ error ? /* @__PURE__ */ jsxs26(
1757
1821
  "p",
1758
1822
  {
1759
1823
  role: "alert",
@@ -1781,13 +1845,13 @@ function MermaidDiagram({ entry, load = loadMermaid }) {
1781
1845
  }
1782
1846
 
1783
1847
  // src/components/ScenarioExplorer.tsx
1784
- import { useState as useState3 } from "react";
1848
+ import { useState as useState4 } from "react";
1785
1849
 
1786
1850
  // src/components/ui/command.tsx
1787
1851
  import "react";
1788
1852
  import { Command as CommandPrimitive } from "cmdk";
1789
1853
  import { SearchIcon } from "lucide-react";
1790
- import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
1854
+ import { jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
1791
1855
  function Command({
1792
1856
  className,
1793
1857
  ...props
@@ -1808,7 +1872,7 @@ function CommandInput({
1808
1872
  className,
1809
1873
  ...props
1810
1874
  }) {
1811
- return /* @__PURE__ */ jsxs26(
1875
+ return /* @__PURE__ */ jsxs27(
1812
1876
  "div",
1813
1877
  {
1814
1878
  "data-slot": "command-input-wrapper",
@@ -1892,7 +1956,7 @@ function CommandItem({
1892
1956
  }
1893
1957
 
1894
1958
  // src/components/ScenarioExplorer.tsx
1895
- import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
1959
+ import { jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
1896
1960
  var STATUS_FILTERS = [
1897
1961
  { value: "all", label: "All" },
1898
1962
  { value: "passed", label: "Passed" },
@@ -1901,19 +1965,19 @@ var STATUS_FILTERS = [
1901
1965
  { value: "pending", label: "Pending" }
1902
1966
  ];
1903
1967
  function ScenarioExplorer({ scenarios, summary }) {
1904
- const [status, setStatus] = useState3("all");
1968
+ const [status, setStatus] = useState4("all");
1905
1969
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1906
- return /* @__PURE__ */ jsxs27("div", { className: "font-sans text-foreground", children: [
1907
- summary ? /* @__PURE__ */ jsxs27("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1970
+ return /* @__PURE__ */ jsxs28("div", { className: "font-sans text-foreground", children: [
1971
+ summary ? /* @__PURE__ */ jsxs28("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1908
1972
  summary.total,
1909
1973
  " scenarios \xB7 ",
1910
- /* @__PURE__ */ jsxs27("span", { className: "text-pass", children: [
1974
+ /* @__PURE__ */ jsxs28("span", { className: "text-pass", children: [
1911
1975
  summary.passed,
1912
1976
  " passed"
1913
1977
  ] }),
1914
1978
  " \xB7",
1915
1979
  " ",
1916
- /* @__PURE__ */ jsxs27("span", { className: "text-fail", children: [
1980
+ /* @__PURE__ */ jsxs28("span", { className: "text-fail", children: [
1917
1981
  summary.failed,
1918
1982
  " failed"
1919
1983
  ] })
@@ -1933,14 +1997,14 @@ function ScenarioExplorer({ scenarios, summary }) {
1933
1997
  },
1934
1998
  f.value
1935
1999
  )) }),
1936
- /* @__PURE__ */ jsxs27(
2000
+ /* @__PURE__ */ jsxs28(
1937
2001
  Command,
1938
2002
  {
1939
2003
  className: "rounded-lg border border-border bg-card",
1940
2004
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1941
2005
  children: [
1942
2006
  /* @__PURE__ */ jsx41(CommandInput, { placeholder: "Search scenarios\u2026" }),
1943
- /* @__PURE__ */ jsxs27(CommandList, { className: "max-h-none", children: [
2007
+ /* @__PURE__ */ jsxs28(CommandList, { className: "max-h-none", children: [
1944
2008
  /* @__PURE__ */ jsx41(CommandEmpty, { children: "No scenarios match your filters." }),
1945
2009
  /* @__PURE__ */ jsx41(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx41(
1946
2010
  CommandItem,
@@ -1948,7 +2012,7 @@ function ScenarioExplorer({ scenarios, summary }) {
1948
2012
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1949
2013
  asChild: true,
1950
2014
  className: "cursor-pointer",
1951
- children: /* @__PURE__ */ jsxs27("a", { href: s.href, className: "flex items-center gap-3", children: [
2015
+ children: /* @__PURE__ */ jsxs28("a", { href: s.href, className: "flex items-center gap-3", children: [
1952
2016
  /* @__PURE__ */ jsx41(Badge, { variant: s.status, children: s.status }),
1953
2017
  /* @__PURE__ */ jsx41("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1954
2018
  s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx41(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
@@ -2118,11 +2182,7 @@ var story_report_v1_default = {
2118
2182
  },
2119
2183
  kind: {
2120
2184
  type: "string",
2121
- enum: [
2122
- "feature",
2123
- "ability",
2124
- "business-need"
2125
- ],
2185
+ enum: ["feature", "ability", "business-need"],
2126
2186
  description: "How the feature was declared. Absent when the title was derived rather than declared."
2127
2187
  },
2128
2188
  narrative: {
@@ -2137,13 +2197,7 @@ var story_report_v1_default = {
2137
2197
  description: "Terms this feature defines, linked wherever they appear in scenario text."
2138
2198
  }
2139
2199
  },
2140
- required: [
2141
- "id",
2142
- "title",
2143
- "sourceFile",
2144
- "summary",
2145
- "scenarios"
2146
- ],
2200
+ required: ["id", "title", "sourceFile", "summary", "scenarios"],
2147
2201
  additionalProperties: false
2148
2202
  },
2149
2203
  Scenario: {
@@ -2273,6 +2327,11 @@ var story_report_v1_default = {
2273
2327
  type: "number",
2274
2328
  minimum: 0
2275
2329
  },
2330
+ assertions: {
2331
+ type: "integer",
2332
+ minimum: 0,
2333
+ description: "Assertions observed or declared for this step. Omit when the adapter cannot observe assertions; zero means observed none."
2334
+ },
2276
2335
  errorMessage: {
2277
2336
  type: "string"
2278
2337
  },
@@ -2300,33 +2359,15 @@ var story_report_v1_default = {
2300
2359
  },
2301
2360
  StepKeyword: {
2302
2361
  type: "string",
2303
- enum: [
2304
- "Given",
2305
- "When",
2306
- "Then",
2307
- "And",
2308
- "But"
2309
- ]
2362
+ enum: ["Given", "When", "Then", "And", "But"]
2310
2363
  },
2311
2364
  StepMode: {
2312
2365
  type: "string",
2313
- enum: [
2314
- "normal",
2315
- "skip",
2316
- "only",
2317
- "todo",
2318
- "fails",
2319
- "concurrent"
2320
- ]
2366
+ enum: ["normal", "skip", "only", "todo", "fails", "concurrent"]
2321
2367
  },
2322
2368
  TestStatus: {
2323
2369
  type: "string",
2324
- enum: [
2325
- "passed",
2326
- "failed",
2327
- "skipped",
2328
- "pending"
2329
- ]
2370
+ enum: ["passed", "failed", "skipped", "pending"]
2330
2371
  },
2331
2372
  Ticket: {
2332
2373
  type: "object",
@@ -2339,9 +2380,7 @@ var story_report_v1_default = {
2339
2380
  type: "string"
2340
2381
  }
2341
2382
  },
2342
- required: [
2343
- "id"
2344
- ],
2383
+ required: ["id"],
2345
2384
  additionalProperties: false
2346
2385
  },
2347
2386
  Attachment: {
@@ -2359,18 +2398,10 @@ var story_report_v1_default = {
2359
2398
  },
2360
2399
  contentEncoding: {
2361
2400
  type: "string",
2362
- enum: [
2363
- "BASE64",
2364
- "IDENTITY"
2365
- ]
2401
+ enum: ["BASE64", "IDENTITY"]
2366
2402
  }
2367
2403
  },
2368
- required: [
2369
- "name",
2370
- "mediaType",
2371
- "body",
2372
- "contentEncoding"
2373
- ],
2404
+ required: ["name", "mediaType", "body", "contentEncoding"],
2374
2405
  additionalProperties: false
2375
2406
  },
2376
2407
  CIInfo: {
@@ -2395,9 +2426,7 @@ var story_report_v1_default = {
2395
2426
  type: "string"
2396
2427
  }
2397
2428
  },
2398
- required: [
2399
- "name"
2400
- ],
2429
+ required: ["name"],
2401
2430
  additionalProperties: false
2402
2431
  },
2403
2432
  CoverageSummary: {
@@ -2428,10 +2457,7 @@ var story_report_v1_default = {
2428
2457
  },
2429
2458
  DocPhase: {
2430
2459
  type: "string",
2431
- enum: [
2432
- "static",
2433
- "runtime"
2434
- ]
2460
+ enum: ["static", "runtime"]
2435
2461
  },
2436
2462
  DocEntry: {
2437
2463
  oneOf: [
@@ -2495,11 +2521,7 @@ var story_report_v1_default = {
2495
2521
  }
2496
2522
  }
2497
2523
  },
2498
- required: [
2499
- "kind",
2500
- "text",
2501
- "phase"
2502
- ],
2524
+ required: ["kind", "text", "phase"],
2503
2525
  additionalProperties: false
2504
2526
  },
2505
2527
  DocTag: {
@@ -2524,11 +2546,7 @@ var story_report_v1_default = {
2524
2546
  }
2525
2547
  }
2526
2548
  },
2527
- required: [
2528
- "kind",
2529
- "names",
2530
- "phase"
2531
- ],
2549
+ required: ["kind", "names", "phase"],
2532
2550
  additionalProperties: false
2533
2551
  },
2534
2552
  DocKv: {
@@ -2551,12 +2569,7 @@ var story_report_v1_default = {
2551
2569
  }
2552
2570
  }
2553
2571
  },
2554
- required: [
2555
- "kind",
2556
- "label",
2557
- "value",
2558
- "phase"
2559
- ],
2572
+ required: ["kind", "label", "value", "phase"],
2560
2573
  additionalProperties: false
2561
2574
  },
2562
2575
  DocCode: {
@@ -2584,12 +2597,7 @@ var story_report_v1_default = {
2584
2597
  }
2585
2598
  }
2586
2599
  },
2587
- required: [
2588
- "kind",
2589
- "label",
2590
- "content",
2591
- "phase"
2592
- ],
2600
+ required: ["kind", "label", "content", "phase"],
2593
2601
  additionalProperties: false
2594
2602
  },
2595
2603
  DocTable: {
@@ -2626,13 +2634,7 @@ var story_report_v1_default = {
2626
2634
  }
2627
2635
  }
2628
2636
  },
2629
- required: [
2630
- "kind",
2631
- "label",
2632
- "columns",
2633
- "rows",
2634
- "phase"
2635
- ],
2637
+ required: ["kind", "label", "columns", "rows", "phase"],
2636
2638
  additionalProperties: false
2637
2639
  },
2638
2640
  DocLink: {
@@ -2657,12 +2659,7 @@ var story_report_v1_default = {
2657
2659
  }
2658
2660
  }
2659
2661
  },
2660
- required: [
2661
- "kind",
2662
- "label",
2663
- "url",
2664
- "phase"
2665
- ],
2662
+ required: ["kind", "label", "url", "phase"],
2666
2663
  additionalProperties: false
2667
2664
  },
2668
2665
  DocSection: {
@@ -2687,12 +2684,7 @@ var story_report_v1_default = {
2687
2684
  }
2688
2685
  }
2689
2686
  },
2690
- required: [
2691
- "kind",
2692
- "title",
2693
- "markdown",
2694
- "phase"
2695
- ],
2687
+ required: ["kind", "title", "markdown", "phase"],
2696
2688
  additionalProperties: false
2697
2689
  },
2698
2690
  DocMermaid: {
@@ -2717,11 +2709,7 @@ var story_report_v1_default = {
2717
2709
  }
2718
2710
  }
2719
2711
  },
2720
- required: [
2721
- "kind",
2722
- "code",
2723
- "phase"
2724
- ],
2712
+ required: ["kind", "code", "phase"],
2725
2713
  additionalProperties: false
2726
2714
  },
2727
2715
  DocScreenshot: {
@@ -2746,11 +2734,7 @@ var story_report_v1_default = {
2746
2734
  }
2747
2735
  }
2748
2736
  },
2749
- required: [
2750
- "kind",
2751
- "path",
2752
- "phase"
2753
- ],
2737
+ required: ["kind", "path", "phase"],
2754
2738
  additionalProperties: false
2755
2739
  },
2756
2740
  DocVideo: {
@@ -2778,11 +2762,7 @@ var story_report_v1_default = {
2778
2762
  }
2779
2763
  }
2780
2764
  },
2781
- required: [
2782
- "kind",
2783
- "path",
2784
- "phase"
2785
- ],
2765
+ required: ["kind", "path", "phase"],
2786
2766
  additionalProperties: false
2787
2767
  },
2788
2768
  DocHtml: {
@@ -2823,26 +2803,17 @@ var story_report_v1_default = {
2823
2803
  }
2824
2804
  }
2825
2805
  },
2826
- required: [
2827
- "kind",
2828
- "phase"
2829
- ],
2806
+ required: ["kind", "phase"],
2830
2807
  additionalProperties: false,
2831
2808
  oneOf: [
2832
2809
  {
2833
- required: [
2834
- "path"
2835
- ]
2810
+ required: ["path"]
2836
2811
  },
2837
2812
  {
2838
- required: [
2839
- "url"
2840
- ]
2813
+ required: ["url"]
2841
2814
  },
2842
2815
  {
2843
- required: [
2844
- "content"
2845
- ]
2816
+ required: ["content"]
2846
2817
  }
2847
2818
  ]
2848
2819
  },
@@ -2866,11 +2837,7 @@ var story_report_v1_default = {
2866
2837
  }
2867
2838
  }
2868
2839
  },
2869
- required: [
2870
- "kind",
2871
- "value",
2872
- "phase"
2873
- ],
2840
+ required: ["kind", "value", "phase"],
2874
2841
  additionalProperties: false
2875
2842
  },
2876
2843
  DocCustom: {
@@ -2894,21 +2861,12 @@ var story_report_v1_default = {
2894
2861
  }
2895
2862
  }
2896
2863
  },
2897
- required: [
2898
- "kind",
2899
- "type",
2900
- "data",
2901
- "phase"
2902
- ],
2864
+ required: ["kind", "type", "data", "phase"],
2903
2865
  additionalProperties: false
2904
2866
  },
2905
2867
  OtelSpan: {
2906
2868
  type: "object",
2907
- required: [
2908
- "spanId",
2909
- "name",
2910
- "status"
2911
- ],
2869
+ required: ["spanId", "name", "status"],
2912
2870
  properties: {
2913
2871
  spanId: {
2914
2872
  type: "string"
@@ -2932,11 +2890,7 @@ var story_report_v1_default = {
2932
2890
  type: "number"
2933
2891
  },
2934
2892
  status: {
2935
- enum: [
2936
- "ok",
2937
- "error",
2938
- "unset"
2939
- ]
2893
+ enum: ["ok", "error", "unset"]
2940
2894
  },
2941
2895
  statusMessage: {
2942
2896
  type: "string"
@@ -2960,10 +2914,7 @@ var story_report_v1_default = {
2960
2914
  minLength: 1
2961
2915
  }
2962
2916
  },
2963
- required: [
2964
- "term",
2965
- "definition"
2966
- ],
2917
+ required: ["term", "definition"],
2967
2918
  additionalProperties: false
2968
2919
  }
2969
2920
  }
@@ -3066,6 +3017,7 @@ export {
3066
3017
  parseStoryReport,
3067
3018
  prUrl,
3068
3019
  reportLastRunMs,
3020
+ scenarioLastRunMs,
3069
3021
  storyReportSchema,
3070
3022
  useBuiltinRenderers,
3071
3023
  useCustomRenderers,