executable-stories-react 0.9.0 → 0.10.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
@@ -17,63 +17,6 @@ import { useMemo } from "react";
17
17
  import { createContext } from "react";
18
18
  var ReportContext = createContext(null);
19
19
 
20
- // src/context/ReportRoot.tsx
21
- import { jsx } from "react/jsx-runtime";
22
- var EMPTY_CUSTOM = {};
23
- var EMPTY_RENDERERS = {};
24
- function ReportRoot({
25
- report,
26
- customRenderers,
27
- renderers,
28
- children
29
- }) {
30
- const value = useMemo(
31
- () => ({
32
- report,
33
- customRenderers: customRenderers ?? EMPTY_CUSTOM,
34
- renderers: renderers ?? EMPTY_RENDERERS
35
- }),
36
- [report, customRenderers, renderers]
37
- );
38
- return /* @__PURE__ */ jsx(ReportContext.Provider, { value, children });
39
- }
40
-
41
- // src/hooks/useReport.ts
42
- import { useContext } from "react";
43
- function useReport() {
44
- const ctx = useContext(ReportContext);
45
- if (!ctx) {
46
- throw new Error(
47
- "useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
48
- );
49
- }
50
- return ctx.report;
51
- }
52
-
53
- // ../executable-stories-core/dist/utils/duration.js
54
- function formatDuration(ms) {
55
- if (ms < 1e3) {
56
- return `${Math.round(ms)} ms`;
57
- }
58
- if (ms < 6e4) {
59
- return `${(ms / 1e3).toFixed(2)} s`;
60
- }
61
- const minutes = Math.floor(ms / 6e4);
62
- const seconds = Math.floor(ms % 6e4 / 1e3);
63
- if (minutes < 60) {
64
- return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
65
- }
66
- const hours = Math.floor(minutes / 60);
67
- const remainingMinutes = minutes % 60;
68
- return `${hours}h ${remainingMinutes}m`;
69
- }
70
-
71
- // src/components/doc/DocNote.tsx
72
- import { jsx as jsx2 } from "react/jsx-runtime";
73
- function DocNote({ entry }) {
74
- return /* @__PURE__ */ jsx2("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
75
- }
76
-
77
20
  // src/components/ui/badge.tsx
78
21
  import "react";
79
22
  import { cva } from "class-variance-authority";
@@ -132,14 +75,249 @@ function Badge({
132
75
  });
133
76
  }
134
77
 
135
- // src/components/doc/DocTag.tsx
78
+ // src/components/doc/NarrativeBlocks.tsx
79
+ import { jsx, jsxs } from "react/jsx-runtime";
80
+ var FILE_TREE_TYPE = "file-tree";
81
+ var DATA_MODEL_TYPE = "data-model";
82
+ function isChangeKind(value) {
83
+ return value === "added" || value === "modified" || value === "removed" || value === "renamed";
84
+ }
85
+ function isRecord(value) {
86
+ return typeof value === "object" && value !== null && !Array.isArray(value);
87
+ }
88
+ function str(value) {
89
+ return typeof value === "string" && value !== "" ? value : void 0;
90
+ }
91
+ function AuthoredMarker({ authored }) {
92
+ if (authored !== "agent") return null;
93
+ return /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
94
+ }
95
+ function BlockFrame({
96
+ title,
97
+ authored,
98
+ children
99
+ }) {
100
+ return /* @__PURE__ */ jsxs("figure", { className: "my-3", children: [
101
+ title || authored === "agent" ? /* @__PURE__ */ jsxs("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
102
+ title ? /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
103
+ /* @__PURE__ */ jsx(AuthoredMarker, { authored })
104
+ ] }) : null,
105
+ children
106
+ ] });
107
+ }
108
+ function ChangeBadge({ change }) {
109
+ return /* @__PURE__ */ jsx(Badge, { variant: "tag", className: "text-[10px]", children: change });
110
+ }
111
+ function parseFileTree(data) {
112
+ if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
113
+ const files = [];
114
+ for (const raw of data.files) {
115
+ if (typeof raw === "string") {
116
+ if (raw) files.push({ path: raw });
117
+ continue;
118
+ }
119
+ if (!isRecord(raw)) continue;
120
+ const path = str(raw.path);
121
+ if (!path) continue;
122
+ files.push({
123
+ path,
124
+ change: isChangeKind(raw.change) ? raw.change : void 0,
125
+ note: str(raw.note)
126
+ });
127
+ }
128
+ if (files.length === 0) return void 0;
129
+ return { title: str(data.title), authored: str(data.authored), files };
130
+ }
131
+ function buildTree(files) {
132
+ const root = { name: "", children: /* @__PURE__ */ new Map() };
133
+ for (const file of files) {
134
+ const segments = file.path.split("/").filter(Boolean);
135
+ let node = root;
136
+ segments.forEach((segment, index) => {
137
+ let child = node.children.get(segment);
138
+ if (!child) {
139
+ child = { name: segment, children: /* @__PURE__ */ new Map() };
140
+ node.children.set(segment, child);
141
+ }
142
+ if (index === segments.length - 1) child.file = file;
143
+ node = child;
144
+ });
145
+ }
146
+ return root;
147
+ }
148
+ function sortedChildren(node) {
149
+ return [...node.children.values()].sort((a, b) => {
150
+ const aDir = a.children.size > 0;
151
+ const bDir = b.children.size > 0;
152
+ if (aDir !== bDir) return aDir ? -1 : 1;
153
+ return a.name.localeCompare(b.name);
154
+ });
155
+ }
156
+ function TreeBranch({ node, depth }) {
157
+ const children = sortedChildren(node);
158
+ return /* @__PURE__ */ jsx("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
159
+ const isDir = child.children.size > 0;
160
+ return /* @__PURE__ */ jsxs("li", { children: [
161
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-2", children: [
162
+ /* @__PURE__ */ jsx(
163
+ "span",
164
+ {
165
+ className: cn(
166
+ "font-mono text-xs",
167
+ isDir ? "text-muted-foreground" : "text-foreground"
168
+ ),
169
+ children: isDir ? `${child.name}/` : child.name
170
+ }
171
+ ),
172
+ child.file?.change ? /* @__PURE__ */ jsx(ChangeBadge, { change: child.file.change }) : null,
173
+ child.file?.note ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
174
+ ] }),
175
+ isDir ? /* @__PURE__ */ jsx(TreeBranch, { node: child, depth: depth + 1 }) : null
176
+ ] }, child.name);
177
+ }) });
178
+ }
179
+ function FileTreeBlock({ entry }) {
180
+ const data = parseFileTree(entry.data);
181
+ if (!data) return /* @__PURE__ */ jsx(UnreadableBlock, { entry });
182
+ return /* @__PURE__ */ jsx(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ jsx("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ jsx(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
183
+ }
184
+ function parseDataModel(data) {
185
+ if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
186
+ const fields = [];
187
+ for (const raw of data.fields) {
188
+ if (!isRecord(raw)) continue;
189
+ const name = str(raw.name);
190
+ if (!name) continue;
191
+ fields.push({
192
+ name,
193
+ type: str(raw.type),
194
+ note: str(raw.note),
195
+ change: isChangeKind(raw.change) ? raw.change : void 0
196
+ });
197
+ }
198
+ if (fields.length === 0) return void 0;
199
+ return {
200
+ title: str(data.title),
201
+ authored: str(data.authored),
202
+ name: str(data.name),
203
+ fields
204
+ };
205
+ }
206
+ function DataModelBlock({ entry }) {
207
+ const data = parseDataModel(entry.data);
208
+ if (!data) return /* @__PURE__ */ jsx(UnreadableBlock, { entry });
209
+ const hasNotes = data.fields.some((f) => f.note);
210
+ return /* @__PURE__ */ jsx(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ jsx("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
211
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "bg-muted/50", children: [
212
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
213
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
214
+ hasNotes ? /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
215
+ ] }) }),
216
+ /* @__PURE__ */ jsx("tbody", { children: data.fields.map((field) => /* @__PURE__ */ jsxs("tr", { children: [
217
+ /* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [
218
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-xs text-foreground", children: field.name }),
219
+ field.change ? /* @__PURE__ */ jsx(ChangeBadge, { change: field.change }) : null
220
+ ] }) }),
221
+ /* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
222
+ hasNotes ? /* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
223
+ ] }, field.name)) })
224
+ ] }) }) });
225
+ }
226
+ function UnreadableBlock({ entry }) {
227
+ return /* @__PURE__ */ jsxs("div", { className: "my-2", "data-type": entry.type, children: [
228
+ /* @__PURE__ */ jsxs("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
229
+ entry.type,
230
+ " (unrecognised shape)"
231
+ ] }),
232
+ /* @__PURE__ */ jsx(
233
+ "pre",
234
+ {
235
+ tabIndex: 0,
236
+ className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground",
237
+ children: safeStringify(entry.data)
238
+ }
239
+ )
240
+ ] });
241
+ }
242
+ function safeStringify(value) {
243
+ try {
244
+ return JSON.stringify(value, null, 2);
245
+ } catch {
246
+ return String(value);
247
+ }
248
+ }
249
+ var narrativeBlockRenderers = {
250
+ [FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ jsx(FileTreeBlock, { entry }),
251
+ [DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ jsx(DataModelBlock, { entry })
252
+ };
253
+
254
+ // src/context/ReportRoot.tsx
255
+ import { jsx as jsx2 } from "react/jsx-runtime";
256
+ var EMPTY_RENDERERS = {};
257
+ function ReportRoot({
258
+ report,
259
+ customRenderers,
260
+ renderers,
261
+ children
262
+ }) {
263
+ const value = useMemo(
264
+ () => ({
265
+ report,
266
+ // Narrative blocks render everywhere the report does (static SSR, the
267
+ // island, Astro) without every host wiring them up. A host renderer for
268
+ // the same type still wins.
269
+ customRenderers: { ...narrativeBlockRenderers, ...customRenderers },
270
+ renderers: renderers ?? EMPTY_RENDERERS
271
+ }),
272
+ [report, customRenderers, renderers]
273
+ );
274
+ return /* @__PURE__ */ jsx2(ReportContext.Provider, { value, children });
275
+ }
276
+
277
+ // src/hooks/useReport.ts
278
+ import { useContext } from "react";
279
+ function useReport() {
280
+ const ctx = useContext(ReportContext);
281
+ if (!ctx) {
282
+ throw new Error(
283
+ "useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
284
+ );
285
+ }
286
+ return ctx.report;
287
+ }
288
+
289
+ // ../executable-stories-core/dist/utils/duration.js
290
+ function formatDuration(ms) {
291
+ if (ms < 1e3) {
292
+ return `${Math.round(ms)} ms`;
293
+ }
294
+ if (ms < 6e4) {
295
+ return `${(ms / 1e3).toFixed(2)} s`;
296
+ }
297
+ const minutes = Math.floor(ms / 6e4);
298
+ const seconds = Math.floor(ms % 6e4 / 1e3);
299
+ if (minutes < 60) {
300
+ return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
301
+ }
302
+ const hours = Math.floor(minutes / 60);
303
+ const remainingMinutes = minutes % 60;
304
+ return `${hours}h ${remainingMinutes}m`;
305
+ }
306
+
307
+ // src/components/doc/DocNote.tsx
136
308
  import { jsx as jsx3 } from "react/jsx-runtime";
309
+ function DocNote({ entry }) {
310
+ return /* @__PURE__ */ jsx3("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
311
+ }
312
+
313
+ // src/components/doc/DocTag.tsx
314
+ import { jsx as jsx4 } from "react/jsx-runtime";
137
315
  function DocTag({ entry }) {
138
- return /* @__PURE__ */ jsx3("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsx3(Badge, { variant: "tag", children: n }) }, n)) });
316
+ 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)) });
139
317
  }
140
318
 
141
319
  // src/components/doc/DocKv.tsx
142
- import { jsx as jsx4, jsxs } from "react/jsx-runtime";
320
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
143
321
  function formatValue(value) {
144
322
  if (value === null) return "null";
145
323
  if (typeof value === "string") return value;
@@ -151,19 +329,19 @@ function formatValue(value) {
151
329
  }
152
330
  }
153
331
  function DocKv({ entry }) {
154
- return /* @__PURE__ */ jsxs("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
155
- /* @__PURE__ */ jsx4("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
156
- /* @__PURE__ */ jsx4("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
332
+ return /* @__PURE__ */ jsxs2("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
333
+ /* @__PURE__ */ jsx5("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
334
+ /* @__PURE__ */ jsx5("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
157
335
  ] });
158
336
  }
159
337
 
160
338
  // src/hooks/useRenderers.ts
161
339
  import { useContext as useContext2 } from "react";
162
- var EMPTY_CUSTOM2 = {};
340
+ var EMPTY_CUSTOM = {};
163
341
  var EMPTY_RENDERERS2 = {};
164
342
  function useCustomRenderers() {
165
343
  const ctx = useContext2(ReportContext);
166
- return ctx?.customRenderers ?? EMPTY_CUSTOM2;
344
+ return ctx?.customRenderers ?? EMPTY_CUSTOM;
167
345
  }
168
346
  function useBuiltinRenderers() {
169
347
  const ctx = useContext2(ReportContext);
@@ -171,37 +349,37 @@ function useBuiltinRenderers() {
171
349
  }
172
350
 
173
351
  // src/components/doc/DocCode.tsx
174
- import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
352
+ import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
175
353
  function CodeFigure({ label, children }) {
176
- return /* @__PURE__ */ jsxs2("figure", { className: "my-3", children: [
177
- label ? /* @__PURE__ */ jsx5("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
178
- /* @__PURE__ */ jsx5("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
354
+ return /* @__PURE__ */ jsxs3("figure", { className: "my-3", children: [
355
+ label ? /* @__PURE__ */ jsx6("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
356
+ /* @__PURE__ */ jsx6("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
179
357
  ] });
180
358
  }
181
359
  function DocCode({ entry }) {
182
360
  const renderers = useBuiltinRenderers();
183
361
  if (renderers.code) {
184
- return /* @__PURE__ */ jsx5(Fragment, { children: renderers.code(entry) });
362
+ return /* @__PURE__ */ jsx6(Fragment, { children: renderers.code(entry) });
185
363
  }
186
- return /* @__PURE__ */ jsx5(CodeFigure, { label: entry.label, children: /* @__PURE__ */ jsx5("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
364
+ 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 }) });
187
365
  }
188
366
 
189
367
  // src/components/doc/DocTable.tsx
190
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
368
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
191
369
  function DocTable({ entry }) {
192
- return /* @__PURE__ */ jsxs3("figure", { className: "my-3", children: [
193
- entry.label ? /* @__PURE__ */ jsx6("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
194
- /* @__PURE__ */ jsx6("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs3("table", { className: "w-full border-collapse text-sm", children: [
195
- /* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsx6("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ jsx6("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
196
- /* @__PURE__ */ jsx6("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ jsx6("tr", { children: row.map((cell, j) => /* @__PURE__ */ jsx6("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
370
+ return /* @__PURE__ */ jsxs4("figure", { className: "my-3", children: [
371
+ entry.label ? /* @__PURE__ */ jsx7("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
372
+ /* @__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: [
373
+ /* @__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)) }) }),
374
+ /* @__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)) })
197
375
  ] }) })
198
376
  ] });
199
377
  }
200
378
 
201
379
  // src/components/doc/DocLink.tsx
202
- import { jsx as jsx7 } from "react/jsx-runtime";
380
+ import { jsx as jsx8 } from "react/jsx-runtime";
203
381
  function DocLink({ entry }) {
204
- return /* @__PURE__ */ jsx7(
382
+ return /* @__PURE__ */ jsx8(
205
383
  "a",
206
384
  {
207
385
  className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
@@ -235,7 +413,7 @@ function isLocalFsPath(value) {
235
413
  }
236
414
 
237
415
  // src/components/doc/DocSection.tsx
238
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
416
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
239
417
  function neutralizeUrl(value) {
240
418
  return safeUrl(value) ?? "#";
241
419
  }
@@ -246,12 +424,12 @@ function safeMarkdownHtml(markdown) {
246
424
  function DocSection({ entry }) {
247
425
  const renderers = useBuiltinRenderers();
248
426
  if (renderers.section) {
249
- return /* @__PURE__ */ jsx8(Fragment2, { children: renderers.section(entry) });
427
+ return /* @__PURE__ */ jsx9(Fragment2, { children: renderers.section(entry) });
250
428
  }
251
429
  const html = safeMarkdownHtml(entry.markdown);
252
- return /* @__PURE__ */ jsxs4("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
253
- entry.title ? /* @__PURE__ */ jsx8("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
254
- /* @__PURE__ */ jsx8(
430
+ return /* @__PURE__ */ jsxs5("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
431
+ entry.title ? /* @__PURE__ */ jsx9("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
432
+ /* @__PURE__ */ jsx9(
255
433
  "div",
256
434
  {
257
435
  className: "es-doc-prose prose prose-sm max-w-none",
@@ -262,11 +440,11 @@ function DocSection({ entry }) {
262
440
  }
263
441
 
264
442
  // src/components/doc/DocMermaid.tsx
265
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
443
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
266
444
  function MermaidSource({ entry, ref }) {
267
- return /* @__PURE__ */ jsxs5("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
268
- entry.title ? /* @__PURE__ */ jsx9("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
269
- /* @__PURE__ */ jsx9(
445
+ return /* @__PURE__ */ jsxs6("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
446
+ entry.title ? /* @__PURE__ */ jsx10("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
447
+ /* @__PURE__ */ jsx10(
270
448
  "pre",
271
449
  {
272
450
  "data-mermaid": true,
@@ -280,24 +458,24 @@ function MermaidSource({ entry, ref }) {
280
458
  function DocMermaid({ entry }) {
281
459
  const renderers = useBuiltinRenderers();
282
460
  if (renderers.mermaid) {
283
- return /* @__PURE__ */ jsx9(Fragment3, { children: renderers.mermaid(entry) });
461
+ return /* @__PURE__ */ jsx10(Fragment3, { children: renderers.mermaid(entry) });
284
462
  }
285
- return /* @__PURE__ */ jsx9(MermaidSource, { entry });
463
+ return /* @__PURE__ */ jsx10(MermaidSource, { entry });
286
464
  }
287
465
 
288
466
  // src/components/doc/DocScreenshot.tsx
289
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
467
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
290
468
  function DocScreenshot({ entry }) {
291
469
  const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
292
470
  if (!src) {
293
- return /* @__PURE__ */ jsxs6("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
294
- /* @__PURE__ */ jsx10("div", { className: "font-medium", children: "Screenshot unavailable" }),
295
- /* @__PURE__ */ jsx10("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
296
- entry.alt ? /* @__PURE__ */ jsx10("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
471
+ return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
472
+ /* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Screenshot unavailable" }),
473
+ /* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
474
+ entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
297
475
  ] });
298
476
  }
299
- return /* @__PURE__ */ jsxs6("figure", { className: "my-3", children: [
300
- /* @__PURE__ */ jsx10(
477
+ return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
478
+ /* @__PURE__ */ jsx11(
301
479
  "img",
302
480
  {
303
481
  src,
@@ -306,24 +484,24 @@ function DocScreenshot({ entry }) {
306
484
  className: "max-w-full rounded-md border border-border"
307
485
  }
308
486
  ),
309
- entry.alt ? /* @__PURE__ */ jsx10("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
487
+ entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
310
488
  ] });
311
489
  }
312
490
 
313
491
  // src/components/doc/DocVideo.tsx
314
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
492
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
315
493
  function DocVideo({ entry }) {
316
494
  if (isLocalFsPath(entry.path)) {
317
- return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
318
- /* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Video unavailable" }),
319
- /* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
320
- entry.caption ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
495
+ return /* @__PURE__ */ jsxs8("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
496
+ /* @__PURE__ */ jsx12("div", { className: "font-medium", children: "Video unavailable" }),
497
+ /* @__PURE__ */ jsx12("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
498
+ entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
321
499
  ] });
322
500
  }
323
501
  const src = safeUrl(entry.path);
324
502
  const poster = safeUrl(entry.poster);
325
- return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
326
- /* @__PURE__ */ jsx11(
503
+ return /* @__PURE__ */ jsxs8("figure", { className: "my-3", children: [
504
+ /* @__PURE__ */ jsx12(
327
505
  "video",
328
506
  {
329
507
  controls: true,
@@ -333,21 +511,21 @@ function DocVideo({ entry }) {
333
511
  className: "max-w-full rounded-md border border-border"
334
512
  }
335
513
  ),
336
- entry.caption ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
514
+ entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
337
515
  ] });
338
516
  }
339
517
 
340
518
  // src/components/doc/DocHtml.tsx
341
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
519
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
342
520
  function DocHtml({ entry }) {
343
521
  const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
344
522
  const title = entry.title ?? "Embedded HTML";
345
523
  const safeHref = safeUrl(entry.url ?? entry.path);
346
524
  const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
347
- return /* @__PURE__ */ jsxs8("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
348
- /* @__PURE__ */ jsxs8("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: [
349
- /* @__PURE__ */ jsx12("span", { children: entry.title ?? "HTML" }),
350
- safeHref ? /* @__PURE__ */ jsx12(
525
+ return /* @__PURE__ */ jsxs9("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
526
+ /* @__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: [
527
+ /* @__PURE__ */ jsx13("span", { children: entry.title ?? "HTML" }),
528
+ safeHref ? /* @__PURE__ */ jsx13(
351
529
  "a",
352
530
  {
353
531
  href: safeHref,
@@ -360,7 +538,7 @@ function DocHtml({ entry }) {
360
538
  }
361
539
  ) : null
362
540
  ] }),
363
- /* @__PURE__ */ jsx12(
541
+ /* @__PURE__ */ jsx13(
364
542
  "iframe",
365
543
  {
366
544
  ...frameProps,
@@ -375,7 +553,7 @@ function DocHtml({ entry }) {
375
553
  }
376
554
 
377
555
  // src/components/doc/DocState.tsx
378
- import { jsx as jsx13 } from "react/jsx-runtime";
556
+ import { jsx as jsx14 } from "react/jsx-runtime";
379
557
  function DocState({ entry }) {
380
558
  let json;
381
559
  try {
@@ -383,23 +561,23 @@ function DocState({ entry }) {
383
561
  } catch {
384
562
  json = String(entry.value);
385
563
  }
386
- return /* @__PURE__ */ jsx13(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx13("code", { className: "font-mono text-xs language-json", children: json }) });
564
+ return /* @__PURE__ */ jsx14(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx14("code", { className: "font-mono text-xs language-json", children: json }) });
387
565
  }
388
566
 
389
567
  // src/components/doc/DocCustom.tsx
390
- import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
568
+ import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
391
569
  function DocCustom({ entry }) {
392
570
  const renderers = useCustomRenderers();
393
571
  const renderer = renderers[entry.type];
394
572
  if (renderer) {
395
- return /* @__PURE__ */ jsx14(Fragment4, { children: renderer(entry) });
573
+ return /* @__PURE__ */ jsx15(Fragment4, { children: renderer(entry) });
396
574
  }
397
- return /* @__PURE__ */ jsxs9("div", { className: "my-2", "data-type": entry.type, children: [
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) })
575
+ return /* @__PURE__ */ jsxs10("div", { className: "my-2", "data-type": entry.type, children: [
576
+ /* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
577
+ /* @__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) })
400
578
  ] });
401
579
  }
402
- function safeStringify(value) {
580
+ function safeStringify2(value) {
403
581
  try {
404
582
  return JSON.stringify(value, null, 2);
405
583
  } catch {
@@ -408,47 +586,47 @@ function safeStringify(value) {
408
586
  }
409
587
 
410
588
  // src/components/doc/DocEntry.tsx
411
- import { jsx as jsx15 } from "react/jsx-runtime";
589
+ import { jsx as jsx16 } from "react/jsx-runtime";
412
590
  function DocEntry({ entry }) {
413
591
  switch (entry.kind) {
414
592
  case "note":
415
- return /* @__PURE__ */ jsx15(DocNote, { entry });
593
+ return /* @__PURE__ */ jsx16(DocNote, { entry });
416
594
  case "tag":
417
- return /* @__PURE__ */ jsx15(DocTag, { entry });
595
+ return /* @__PURE__ */ jsx16(DocTag, { entry });
418
596
  case "kv":
419
- return /* @__PURE__ */ jsx15(DocKv, { entry });
597
+ return /* @__PURE__ */ jsx16(DocKv, { entry });
420
598
  case "code":
421
- return /* @__PURE__ */ jsx15(DocCode, { entry });
599
+ return /* @__PURE__ */ jsx16(DocCode, { entry });
422
600
  case "table":
423
- return /* @__PURE__ */ jsx15(DocTable, { entry });
601
+ return /* @__PURE__ */ jsx16(DocTable, { entry });
424
602
  case "link":
425
- return /* @__PURE__ */ jsx15(DocLink, { entry });
603
+ return /* @__PURE__ */ jsx16(DocLink, { entry });
426
604
  case "section":
427
- return /* @__PURE__ */ jsx15(DocSection, { entry });
605
+ return /* @__PURE__ */ jsx16(DocSection, { entry });
428
606
  case "mermaid":
429
- return /* @__PURE__ */ jsx15(DocMermaid, { entry });
607
+ return /* @__PURE__ */ jsx16(DocMermaid, { entry });
430
608
  case "screenshot":
431
- return /* @__PURE__ */ jsx15(DocScreenshot, { entry });
609
+ return /* @__PURE__ */ jsx16(DocScreenshot, { entry });
432
610
  case "video":
433
- return /* @__PURE__ */ jsx15(DocVideo, { entry });
611
+ return /* @__PURE__ */ jsx16(DocVideo, { entry });
434
612
  case "html":
435
- return /* @__PURE__ */ jsx15(DocHtml, { entry });
613
+ return /* @__PURE__ */ jsx16(DocHtml, { entry });
436
614
  case "state":
437
- return /* @__PURE__ */ jsx15(DocState, { entry });
615
+ return /* @__PURE__ */ jsx16(DocState, { entry });
438
616
  case "custom":
439
- return /* @__PURE__ */ jsx15(DocCustom, { entry });
617
+ return /* @__PURE__ */ jsx16(DocCustom, { entry });
440
618
  }
441
619
  }
442
620
 
443
621
  // src/components/ReportDocEntries.tsx
444
- import { Fragment as Fragment5, jsx as jsx16 } from "react/jsx-runtime";
622
+ import { Fragment as Fragment5, jsx as jsx17 } from "react/jsx-runtime";
445
623
  function ReportDocEntries({ entries }) {
446
624
  if (entries.length === 0) return null;
447
- return /* @__PURE__ */ jsx16(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx16(DocEntry, { entry }, i)) });
625
+ return /* @__PURE__ */ jsx17(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx17(DocEntry, { entry }, i)) });
448
626
  }
449
627
 
450
628
  // src/lib/step-params.tsx
451
- import { jsx as jsx17 } from "react/jsx-runtime";
629
+ import { jsx as jsx18 } from "react/jsx-runtime";
452
630
  var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
453
631
  function highlightStepParams(text) {
454
632
  const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
@@ -460,7 +638,7 @@ function highlightStepParams(text) {
460
638
  const end = start + match[0].length;
461
639
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
462
640
  nodes.push(
463
- /* @__PURE__ */ jsx17("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
641
+ /* @__PURE__ */ jsx18("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
464
642
  );
465
643
  lastIndex = end;
466
644
  });
@@ -469,7 +647,7 @@ function highlightStepParams(text) {
469
647
  }
470
648
 
471
649
  // src/components/ReportSteps.tsx
472
- import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
650
+ import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
473
651
  var STEP_GLYPH = {
474
652
  passed: "\u2713",
475
653
  failed: "\u2717",
@@ -484,21 +662,21 @@ var STEP_GLYPH_COLOR = {
484
662
  };
485
663
  function ReportSteps({ scenario }) {
486
664
  if (scenario.steps.length === 0) return null;
487
- return /* @__PURE__ */ jsx18("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx18(ReportStepItem, { step }, step.id)) });
665
+ return /* @__PURE__ */ jsx19("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx19(ReportStepItem, { step }, step.id)) });
488
666
  }
489
667
  function ReportStepItem({ step }) {
490
668
  const kw = step.keyword.toLowerCase();
491
669
  const continuation = kw === "and" || kw === "but";
492
- return /* @__PURE__ */ jsxs10(
670
+ return /* @__PURE__ */ jsxs11(
493
671
  "li",
494
672
  {
495
673
  id: step.id,
496
674
  "data-status": step.status,
497
675
  className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
498
676
  children: [
499
- /* @__PURE__ */ jsxs10("div", { className: "flex items-baseline gap-2", children: [
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(
677
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-baseline gap-2", children: [
678
+ /* @__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(
502
680
  "span",
503
681
  {
504
682
  className: cn(
@@ -508,10 +686,10 @@ function ReportStepItem({ step }) {
508
686
  children: step.keyword
509
687
  }
510
688
  ),
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
689
+ /* @__PURE__ */ jsx19("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
690
+ step.durationMs > 0 ? /* @__PURE__ */ jsx19("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
513
691
  ] }),
514
- step.errorMessage ? /* @__PURE__ */ jsx18(
692
+ step.errorMessage ? /* @__PURE__ */ jsx19(
515
693
  "pre",
516
694
  {
517
695
  role: "alert",
@@ -519,7 +697,7 @@ function ReportStepItem({ step }) {
519
697
  children: step.errorMessage
520
698
  }
521
699
  ) : 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
700
+ step.docEntries.length > 0 ? /* @__PURE__ */ jsx19("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx19(ReportDocEntries, { entries: step.docEntries }) }) : null
523
701
  ]
524
702
  }
525
703
  );
@@ -644,7 +822,7 @@ function extractStoryboardFrames(scenario) {
644
822
  }
645
823
 
646
824
  // src/components/ReportStoryboard.tsx
647
- import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
825
+ import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
648
826
  var FRAME_GLYPH = {
649
827
  passed: "\u2713",
650
828
  failed: "\u2717",
@@ -660,32 +838,32 @@ var FRAME_GLYPH_COLOR = {
660
838
  function ReportStoryboard({ scenario }) {
661
839
  const frames = extractStoryboardFrames(scenario);
662
840
  if (frames.length < 2) return null;
663
- return /* @__PURE__ */ jsxs11("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
664
- /* @__PURE__ */ jsx19("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
665
- /* @__PURE__ */ jsx19("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx19(StoryboardFrameItem, { frame }, frame.stepId)) })
841
+ return /* @__PURE__ */ jsxs12("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
842
+ /* @__PURE__ */ jsx20("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
843
+ /* @__PURE__ */ jsx20("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx20(StoryboardFrameItem, { frame }, frame.stepId)) })
666
844
  ] });
667
845
  }
668
846
  function StoryboardFrameItem({ frame }) {
669
847
  const label = `${frame.keyword} ${frame.text}`;
670
848
  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 }),
849
+ const caption = /* @__PURE__ */ jsxs12("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
850
+ /* @__PURE__ */ jsx20("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
851
+ /* @__PURE__ */ jsxs12("span", { className: "min-w-0", children: [
852
+ /* @__PURE__ */ jsx20("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
675
853
  " ",
676
- /* @__PURE__ */ jsx19("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
854
+ /* @__PURE__ */ jsx20("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
677
855
  ] })
678
856
  ] });
679
857
  return (
680
858
  // State cards need room for diff rows; screenshot-only frames keep the
681
859
  // 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,
860
+ /* @__PURE__ */ jsxs12("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
861
+ frame.screenshot ? /* @__PURE__ */ jsx20(FrameScreenshot, { frame, label }) : null,
862
+ hasStates ? /* @__PURE__ */ jsx20("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ jsx20(StateCardView, { card }, card.label ?? i)) }) : null,
685
863
  frame.screenshot ? caption : (
686
864
  // No screenshot means no image anchor, so the caption carries the
687
865
  // jump-to-step link instead.
688
- /* @__PURE__ */ jsx19("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
866
+ /* @__PURE__ */ jsx20("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
689
867
  )
690
868
  ] })
691
869
  );
@@ -693,13 +871,13 @@ function StoryboardFrameItem({ frame }) {
693
871
  function FrameScreenshot({ frame, label }) {
694
872
  const path = frame.screenshot?.path ?? "";
695
873
  const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
696
- return /* @__PURE__ */ jsx19(
874
+ return /* @__PURE__ */ jsx20(
697
875
  "a",
698
876
  {
699
877
  href: `#${frame.stepId}`,
700
878
  "aria-label": `Jump to step: ${label}`,
701
879
  className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
702
- children: src ? /* @__PURE__ */ jsx19(
880
+ children: src ? /* @__PURE__ */ jsx20(
703
881
  "img",
704
882
  {
705
883
  src,
@@ -707,7 +885,7 @@ function FrameScreenshot({ frame, label }) {
707
885
  loading: "lazy",
708
886
  className: "h-24 w-full bg-muted object-cover object-top"
709
887
  }
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" })
888
+ ) : /* @__PURE__ */ jsx20("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
889
  }
712
890
  );
713
891
  }
@@ -726,12 +904,12 @@ function prettyJson(value) {
726
904
  function StateCardView({ card }) {
727
905
  const json = prettyJson(card.value);
728
906
  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
907
+ return /* @__PURE__ */ jsxs12("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
908
+ /* @__PURE__ */ jsxs12("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
909
+ /* @__PURE__ */ jsx20("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" }),
910
+ firstCapture ? /* @__PURE__ */ jsx20("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
733
911
  ] }),
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(
912
+ !firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ jsx20("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ jsx20(
735
913
  "li",
736
914
  {
737
915
  className: cn(
@@ -741,15 +919,15 @@ function StateCardView({ card }) {
741
919
  children: summarizeStateChanges([change])[0]
742
920
  },
743
921
  i
744
- )) }) : /* @__PURE__ */ jsx19("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
745
- /* @__PURE__ */ jsxs11(
922
+ )) }) : /* @__PURE__ */ jsx20("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
923
+ /* @__PURE__ */ jsxs12(
746
924
  "details",
747
925
  {
748
926
  open: firstCapture && json.length <= 240,
749
927
  className: cn(firstCapture ? "mt-1.5" : "mt-1"),
750
928
  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 })
929
+ /* @__PURE__ */ jsx20("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
930
+ /* @__PURE__ */ jsx20("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
931
  ]
754
932
  }
755
933
  )
@@ -757,17 +935,17 @@ function StateCardView({ card }) {
757
935
  }
758
936
 
759
937
  // src/components/ReportAttachments.tsx
760
- import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
938
+ import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
761
939
  function ReportAttachments({ attachments }) {
762
940
  if (attachments.length === 0) return null;
763
941
  return (
764
942
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
765
943
  // blocks don't create duplicate "Attachments" region landmarks.
766
- /* @__PURE__ */ jsx20("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
944
+ /* @__PURE__ */ jsx21("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
767
945
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
768
946
  const isImage = att.mediaType.startsWith("image/");
769
- return /* @__PURE__ */ jsx20("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
770
- /* @__PURE__ */ jsx20(
947
+ return /* @__PURE__ */ jsx21("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
948
+ /* @__PURE__ */ jsx21(
771
949
  "img",
772
950
  {
773
951
  src: dataUri,
@@ -776,8 +954,8 @@ function ReportAttachments({ attachments }) {
776
954
  className: "max-w-full rounded-md border border-border"
777
955
  }
778
956
  ),
779
- /* @__PURE__ */ jsx20("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
780
- ] }) : /* @__PURE__ */ jsxs12(
957
+ /* @__PURE__ */ jsx21("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
958
+ ] }) : /* @__PURE__ */ jsxs13(
781
959
  "a",
782
960
  {
783
961
  href: dataUri,
@@ -786,7 +964,7 @@ function ReportAttachments({ attachments }) {
786
964
  children: [
787
965
  att.name,
788
966
  " ",
789
- /* @__PURE__ */ jsxs12("span", { className: "text-muted-foreground", children: [
967
+ /* @__PURE__ */ jsxs13("span", { className: "text-muted-foreground", children: [
790
968
  "(",
791
969
  att.mediaType,
792
970
  ")"
@@ -874,7 +1052,7 @@ function traceWindow(rows) {
874
1052
  }
875
1053
 
876
1054
  // src/components/ReportTrace.tsx
877
- import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1055
+ import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
878
1056
  var BAR_COLOR = {
879
1057
  ok: "bg-pass",
880
1058
  error: "bg-fail",
@@ -885,8 +1063,8 @@ function ReportTrace({ spans }) {
885
1063
  const rows = toTraceRows(spans);
886
1064
  if (rows.length === 0) return null;
887
1065
  const { minStartMs, totalMs } = traceWindow(rows);
888
- return /* @__PURE__ */ jsxs13("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
889
- /* @__PURE__ */ jsxs13("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
1066
+ return /* @__PURE__ */ jsxs14("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
1067
+ /* @__PURE__ */ jsxs14("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
890
1068
  "Trace (",
891
1069
  rows.length,
892
1070
  " span",
@@ -895,11 +1073,11 @@ function ReportTrace({ spans }) {
895
1073
  formatDuration(totalMs),
896
1074
  ")"
897
1075
  ] }),
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) => {
1076
+ /* @__PURE__ */ jsx22("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
899
1077
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
900
1078
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
901
- return /* @__PURE__ */ jsxs13("li", { className: "flex items-center gap-2", children: [
902
- /* @__PURE__ */ jsx21(
1079
+ return /* @__PURE__ */ jsxs14("li", { className: "flex items-center gap-2", children: [
1080
+ /* @__PURE__ */ jsx22(
903
1081
  "span",
904
1082
  {
905
1083
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -908,14 +1086,14 @@ function ReportTrace({ spans }) {
908
1086
  children: row.name
909
1087
  }
910
1088
  ),
911
- /* @__PURE__ */ jsx21("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx21(
1089
+ /* @__PURE__ */ jsx22("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx22(
912
1090
  "span",
913
1091
  {
914
1092
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
915
1093
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
916
1094
  }
917
1095
  ) }),
918
- /* @__PURE__ */ jsx21("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
1096
+ /* @__PURE__ */ jsx22("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
919
1097
  ] }, `${row.spanId}-${i}`);
920
1098
  }) })
921
1099
  ] });
@@ -966,7 +1144,7 @@ function flakinessOf(entries) {
966
1144
  }
967
1145
 
968
1146
  // src/components/ScenarioRunHistory.tsx
969
- import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1147
+ import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
970
1148
  var MAX_DOTS = 10;
971
1149
  var DOT_COLOR = {
972
1150
  passed: "bg-pass",
@@ -986,16 +1164,16 @@ function ScenarioRunHistory({ scenarioId }) {
986
1164
  const recent = entries.slice(-MAX_DOTS);
987
1165
  const flaky = flakinessOf(recent) === "flaky";
988
1166
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
989
- return /* @__PURE__ */ jsxs14(Fragment7, { children: [
990
- flaky ? /* @__PURE__ */ jsx22(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
991
- /* @__PURE__ */ jsx22(
1167
+ return /* @__PURE__ */ jsxs15(Fragment7, { children: [
1168
+ flaky ? /* @__PURE__ */ jsx23(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
1169
+ /* @__PURE__ */ jsx23(
992
1170
  "span",
993
1171
  {
994
1172
  role: "img",
995
1173
  "aria-label": `Run history: ${summary}`,
996
1174
  title: summary,
997
1175
  className: "flex shrink-0 items-center gap-[3px]",
998
- children: recent.map((e, i) => /* @__PURE__ */ jsx22(
1176
+ children: recent.map((e, i) => /* @__PURE__ */ jsx23(
999
1177
  "span",
1000
1178
  {
1001
1179
  "aria-hidden": true,
@@ -1034,9 +1212,9 @@ function useScenarioActions() {
1034
1212
 
1035
1213
  // src/components/ui/card.tsx
1036
1214
  import "react";
1037
- import { jsx as jsx23 } from "react/jsx-runtime";
1215
+ import { jsx as jsx24 } from "react/jsx-runtime";
1038
1216
  function Card({ className, ...props }) {
1039
- return /* @__PURE__ */ jsx23(
1217
+ return /* @__PURE__ */ jsx24(
1040
1218
  "div",
1041
1219
  {
1042
1220
  "data-slot": "card",
@@ -1049,7 +1227,7 @@ function Card({ className, ...props }) {
1049
1227
  );
1050
1228
  }
1051
1229
  function CardHeader({ className, ...props }) {
1052
- return /* @__PURE__ */ jsx23(
1230
+ return /* @__PURE__ */ jsx24(
1053
1231
  "div",
1054
1232
  {
1055
1233
  "data-slot": "card-header",
@@ -1062,7 +1240,7 @@ function CardHeader({ className, ...props }) {
1062
1240
  );
1063
1241
  }
1064
1242
  function CardContent({ className, ...props }) {
1065
- return /* @__PURE__ */ jsx23(
1243
+ return /* @__PURE__ */ jsx24(
1066
1244
  "div",
1067
1245
  {
1068
1246
  "data-slot": "card-content",
@@ -1076,13 +1254,13 @@ function CardContent({ className, ...props }) {
1076
1254
  import "react";
1077
1255
  import { Menu as MenuPrimitive } from "@base-ui/react/menu";
1078
1256
  import { CheckIcon } from "lucide-react";
1079
- import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
1257
+ import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
1080
1258
  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";
1081
1259
  function DropdownMenu(props) {
1082
- return /* @__PURE__ */ jsx24(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1260
+ return /* @__PURE__ */ jsx25(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1083
1261
  }
1084
1262
  function DropdownMenuTrigger(props) {
1085
- return /* @__PURE__ */ jsx24(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1263
+ return /* @__PURE__ */ jsx25(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1086
1264
  }
1087
1265
  function DropdownMenuContent({
1088
1266
  className,
@@ -1090,14 +1268,14 @@ function DropdownMenuContent({
1090
1268
  sideOffset = 4,
1091
1269
  ...props
1092
1270
  }) {
1093
- return /* @__PURE__ */ jsx24(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx24(
1271
+ return /* @__PURE__ */ jsx25(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx25(
1094
1272
  MenuPrimitive.Positioner,
1095
1273
  {
1096
1274
  "data-slot": "dropdown-menu-positioner",
1097
1275
  className: "z-50",
1098
1276
  align,
1099
1277
  sideOffset,
1100
- children: /* @__PURE__ */ jsx24(
1278
+ children: /* @__PURE__ */ jsx25(
1101
1279
  MenuPrimitive.Popup,
1102
1280
  {
1103
1281
  "data-slot": "dropdown-menu-content",
@@ -1115,7 +1293,7 @@ function DropdownMenuItem({
1115
1293
  className,
1116
1294
  ...props
1117
1295
  }) {
1118
- return /* @__PURE__ */ jsx24(
1296
+ return /* @__PURE__ */ jsx25(
1119
1297
  MenuPrimitive.Item,
1120
1298
  {
1121
1299
  "data-slot": "dropdown-menu-item",
@@ -1127,7 +1305,7 @@ function DropdownMenuItem({
1127
1305
 
1128
1306
  // src/components/ReportScenario.tsx
1129
1307
  import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
1130
- import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
1308
+ import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
1131
1309
  var STATUS_META = {
1132
1310
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
1133
1311
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -1143,7 +1321,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
1143
1321
  const collapsible = collapse !== null && !hideTitle;
1144
1322
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
1145
1323
  const actions = useScenarioActions();
1146
- return /* @__PURE__ */ jsxs16(
1324
+ return /* @__PURE__ */ jsxs17(
1147
1325
  Card,
1148
1326
  {
1149
1327
  id: scenario.id,
@@ -1151,10 +1329,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
1151
1329
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
1152
1330
  className: "gap-0 py-0",
1153
1331
  children: [
1154
- /* @__PURE__ */ jsxs16(CardHeader, { className: "px-4 py-3", children: [
1155
- /* @__PURE__ */ jsxs16("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1156
- hideTitle ? null : /* @__PURE__ */ jsxs16("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1157
- collapsible ? /* @__PURE__ */ jsx25(
1332
+ /* @__PURE__ */ jsxs17(CardHeader, { className: "px-4 py-3", children: [
1333
+ /* @__PURE__ */ jsxs17("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1334
+ hideTitle ? null : /* @__PURE__ */ jsxs17("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1335
+ collapsible ? /* @__PURE__ */ jsx26(
1158
1336
  "button",
1159
1337
  {
1160
1338
  type: "button",
@@ -1163,49 +1341,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
1163
1341
  "aria-controls": bodyId,
1164
1342
  "aria-label": `Toggle ${scenario.title}`,
1165
1343
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1166
- children: /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1344
+ children: /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1167
1345
  }
1168
1346
  ) : null,
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 })
1347
+ /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1348
+ /* @__PURE__ */ jsx26("span", { children: scenario.title })
1171
1349
  ] }),
1172
- /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2", children: [
1173
- /* @__PURE__ */ jsx25(ScenarioRunHistory, { scenarioId: scenario.id }),
1174
- scenario.durationMs > 0 ? /* @__PURE__ */ jsx25("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1175
- meta.showPill ? /* @__PURE__ */ jsx25(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx25("span", { className: "sr-only", children: `Status: ${label}` }),
1176
- actions ? /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
1177
- /* @__PURE__ */ jsx25(
1350
+ /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2", children: [
1351
+ /* @__PURE__ */ jsx26(ScenarioRunHistory, { scenarioId: scenario.id }),
1352
+ scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1353
+ meta.showPill ? /* @__PURE__ */ jsx26(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx26("span", { className: "sr-only", children: `Status: ${label}` }),
1354
+ actions ? /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
1355
+ /* @__PURE__ */ jsx26(
1178
1356
  DropdownMenuTrigger,
1179
1357
  {
1180
1358
  "aria-label": `Actions for ${scenario.title}`,
1181
1359
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1182
- children: /* @__PURE__ */ jsx25(MoreHorizontalIcon, { "aria-hidden": true })
1360
+ children: /* @__PURE__ */ jsx26(MoreHorizontalIcon, { "aria-hidden": true })
1183
1361
  }
1184
1362
  ),
1185
- /* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", children: [
1186
- /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1187
- /* @__PURE__ */ jsx25(LinkIcon, {}),
1363
+ /* @__PURE__ */ jsxs17(DropdownMenuContent, { align: "end", children: [
1364
+ /* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1365
+ /* @__PURE__ */ jsx26(LinkIcon, {}),
1188
1366
  " Copy link"
1189
1367
  ] }),
1190
- /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1191
- /* @__PURE__ */ jsx25(FileTextIcon, {}),
1368
+ /* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1369
+ /* @__PURE__ */ jsx26(FileTextIcon, {}),
1192
1370
  " Copy as Markdown"
1193
1371
  ] }),
1194
- /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1195
- /* @__PURE__ */ jsx25(SparklesIcon, {}),
1372
+ /* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1373
+ /* @__PURE__ */ jsx26(SparklesIcon, {}),
1196
1374
  " Explain with AI"
1197
1375
  ] })
1198
1376
  ] })
1199
1377
  ] }) : null
1200
1378
  ] })
1201
1379
  ] }),
1202
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs16("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1203
- scenario.tags.map((t) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1204
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx25("li", { children: ticket.url ? /* @__PURE__ */ jsx25("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1380
+ 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: [
1381
+ scenario.tags.map((t) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1382
+ (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}`))
1205
1383
  ] }) : null
1206
1384
  ] }),
1207
- /* @__PURE__ */ jsxs16(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1208
- scenario.errorMessage ? /* @__PURE__ */ jsx25(
1385
+ /* @__PURE__ */ jsxs17(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1386
+ scenario.errorMessage ? /* @__PURE__ */ jsx26(
1209
1387
  "pre",
1210
1388
  {
1211
1389
  role: "alert",
@@ -1213,11 +1391,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
1213
1391
  children: scenario.errorMessage
1214
1392
  }
1215
1393
  ) : null,
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 })
1394
+ /* @__PURE__ */ jsx26(ReportStoryboard, { scenario }),
1395
+ /* @__PURE__ */ jsx26(ReportSteps, { scenario }),
1396
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx26("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx26(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1397
+ /* @__PURE__ */ jsx26(ReportAttachments, { attachments: scenario.attachments }),
1398
+ /* @__PURE__ */ jsx26(ReportTrace, { spans: scenario.otelSpans })
1221
1399
  ] })
1222
1400
  ]
1223
1401
  }
@@ -1225,13 +1403,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1225
1403
  }
1226
1404
 
1227
1405
  // src/components/ReportScenarioList.tsx
1228
- import { Fragment as Fragment8, jsx as jsx26 } from "react/jsx-runtime";
1406
+ import { Fragment as Fragment8, jsx as jsx27 } from "react/jsx-runtime";
1229
1407
  function ReportScenarioList({ feature }) {
1230
- return /* @__PURE__ */ jsx26(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx26(ReportScenario, { scenario }, scenario.id)) });
1408
+ return /* @__PURE__ */ jsx27(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx27(ReportScenario, { scenario }, scenario.id)) });
1231
1409
  }
1232
1410
 
1233
1411
  // src/components/ReportFeature.tsx
1234
- import { Fragment as Fragment9, jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
1412
+ import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
1235
1413
  function ReportFeature({ feature }) {
1236
1414
  const titleId = `${feature.id}-title`;
1237
1415
  const bodyId = `${feature.id}-body`;
@@ -1242,7 +1420,7 @@ function ReportFeature({ feature }) {
1242
1420
  return (
1243
1421
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1244
1422
  // layer of nesting so the scenario cards below read as the primary unit.
1245
- /* @__PURE__ */ jsxs17(
1423
+ /* @__PURE__ */ jsxs18(
1246
1424
  "section",
1247
1425
  {
1248
1426
  id: feature.id,
@@ -1250,9 +1428,9 @@ function ReportFeature({ feature }) {
1250
1428
  "aria-labelledby": titleId,
1251
1429
  className: "flex flex-col gap-3",
1252
1430
  children: [
1253
- /* @__PURE__ */ jsxs17("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1254
- /* @__PURE__ */ jsxs17("div", { className: "min-w-0", children: [
1255
- /* @__PURE__ */ jsx27("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
1431
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1432
+ /* @__PURE__ */ jsxs18("div", { className: "min-w-0", children: [
1433
+ /* @__PURE__ */ jsx28("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs18(
1256
1434
  "button",
1257
1435
  {
1258
1436
  type: "button",
@@ -1261,31 +1439,31 @@ function ReportFeature({ feature }) {
1261
1439
  "aria-controls": bodyId,
1262
1440
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1263
1441
  children: [
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 })
1442
+ /* @__PURE__ */ jsx28("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1443
+ /* @__PURE__ */ jsx28("span", { className: "truncate", children: feature.title })
1266
1444
  ]
1267
1445
  }
1268
1446
  ) : feature.title }),
1269
- /* @__PURE__ */ jsx27("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1447
+ /* @__PURE__ */ jsx28("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1270
1448
  ] }),
1271
- /* @__PURE__ */ jsxs17(
1449
+ /* @__PURE__ */ jsxs18(
1272
1450
  "p",
1273
1451
  {
1274
1452
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1275
1453
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1276
1454
  children: [
1277
- /* @__PURE__ */ jsxs17("span", { children: [
1455
+ /* @__PURE__ */ jsxs18("span", { children: [
1278
1456
  s.passed,
1279
1457
  " passed"
1280
1458
  ] }),
1281
- /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1282
- /* @__PURE__ */ jsxs17("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1459
+ /* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
1460
+ /* @__PURE__ */ jsxs18("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1283
1461
  s.failed,
1284
1462
  " failed"
1285
1463
  ] }),
1286
- skipped > 0 ? /* @__PURE__ */ jsxs17(Fragment9, { children: [
1287
- /* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
1288
- /* @__PURE__ */ jsxs17("span", { children: [
1464
+ skipped > 0 ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
1465
+ /* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
1466
+ /* @__PURE__ */ jsxs18("span", { children: [
1289
1467
  skipped,
1290
1468
  " skipped"
1291
1469
  ] })
@@ -1294,7 +1472,7 @@ function ReportFeature({ feature }) {
1294
1472
  }
1295
1473
  )
1296
1474
  ] }),
1297
- /* @__PURE__ */ jsx27("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx27(ReportScenarioList, { feature }) })
1475
+ /* @__PURE__ */ jsx28("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx28(ReportScenarioList, { feature }) })
1298
1476
  ]
1299
1477
  }
1300
1478
  )
@@ -1302,17 +1480,17 @@ function ReportFeature({ feature }) {
1302
1480
  }
1303
1481
 
1304
1482
  // src/components/ReportFeatureList.tsx
1305
- import { jsx as jsx28 } from "react/jsx-runtime";
1483
+ import { jsx as jsx29 } from "react/jsx-runtime";
1306
1484
  function ReportFeatureList() {
1307
1485
  const report = useReport();
1308
- return /* @__PURE__ */ jsx28("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx28(ReportFeature, { feature }, feature.id)) });
1486
+ return /* @__PURE__ */ jsx29("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx29(ReportFeature, { feature }, feature.id)) });
1309
1487
  }
1310
1488
 
1311
1489
  // src/components/ui/empty.tsx
1312
1490
  import { cva as cva2 } from "class-variance-authority";
1313
- import { jsx as jsx29 } from "react/jsx-runtime";
1491
+ import { jsx as jsx30 } from "react/jsx-runtime";
1314
1492
  function Empty({ className, ...props }) {
1315
- return /* @__PURE__ */ jsx29(
1493
+ return /* @__PURE__ */ jsx30(
1316
1494
  "div",
1317
1495
  {
1318
1496
  "data-slot": "empty",
@@ -1325,7 +1503,7 @@ function Empty({ className, ...props }) {
1325
1503
  );
1326
1504
  }
1327
1505
  function EmptyHeader({ className, ...props }) {
1328
- return /* @__PURE__ */ jsx29(
1506
+ return /* @__PURE__ */ jsx30(
1329
1507
  "div",
1330
1508
  {
1331
1509
  "data-slot": "empty-header",
@@ -1352,7 +1530,7 @@ var emptyMediaVariants = cva2(
1352
1530
  }
1353
1531
  );
1354
1532
  function EmptyTitle({ className, ...props }) {
1355
- return /* @__PURE__ */ jsx29(
1533
+ return /* @__PURE__ */ jsx30(
1356
1534
  "div",
1357
1535
  {
1358
1536
  "data-slot": "empty-title",
@@ -1363,16 +1541,16 @@ function EmptyTitle({ className, ...props }) {
1363
1541
  }
1364
1542
 
1365
1543
  // src/components/ReportEmpty.tsx
1366
- import { jsx as jsx30 } from "react/jsx-runtime";
1544
+ import { jsx as jsx31 } from "react/jsx-runtime";
1367
1545
  function ReportEmpty({ message }) {
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." }) }) });
1546
+ return /* @__PURE__ */ jsx31(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx31(EmptyHeader, { children: /* @__PURE__ */ jsx31(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1369
1547
  }
1370
1548
 
1371
1549
  // src/components/ReportSummary.tsx
1372
- import { jsx as jsx31, jsxs as jsxs18 } from "react/jsx-runtime";
1550
+ import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
1373
1551
  function ReportSummary({ className }) {
1374
1552
  const report = useReport();
1375
- return /* @__PURE__ */ jsx31(
1553
+ return /* @__PURE__ */ jsx32(
1376
1554
  ReportSummaryView,
1377
1555
  {
1378
1556
  summary: report.summary,
@@ -1398,7 +1576,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1398
1576
  if (summary.pending > 0) {
1399
1577
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1400
1578
  }
1401
- return /* @__PURE__ */ jsx31(
1579
+ return /* @__PURE__ */ jsx32(
1402
1580
  "dl",
1403
1581
  {
1404
1582
  className: cn(
@@ -1411,17 +1589,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1411
1589
  "aria-label": ariaLabel,
1412
1590
  children: cards.map((c) => {
1413
1591
  const tone = TONE[c.status];
1414
- return /* @__PURE__ */ jsxs18(
1592
+ return /* @__PURE__ */ jsxs19(
1415
1593
  "div",
1416
1594
  {
1417
1595
  "data-status": c.status,
1418
1596
  className: "rounded-lg border bg-card px-4 py-3",
1419
1597
  children: [
1420
- /* @__PURE__ */ jsxs18("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1421
- /* @__PURE__ */ jsx31("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1598
+ /* @__PURE__ */ jsxs19("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1599
+ /* @__PURE__ */ jsx32("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1422
1600
  c.label
1423
1601
  ] }),
1424
- /* @__PURE__ */ jsx31("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1602
+ /* @__PURE__ */ jsx32("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1425
1603
  ]
1426
1604
  },
1427
1605
  c.status
@@ -1481,7 +1659,7 @@ function prUrl(ci) {
1481
1659
  }
1482
1660
 
1483
1661
  // src/components/ReportMeta.tsx
1484
- import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
1662
+ import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
1485
1663
  function ReportMeta() {
1486
1664
  const report = useReport();
1487
1665
  const items = [];
@@ -1504,13 +1682,13 @@ function ReportMeta() {
1504
1682
  const short = sha.slice(0, 8);
1505
1683
  items.push({
1506
1684
  label: "Commit",
1507
- value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1685
+ value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1508
1686
  });
1509
1687
  }
1510
1688
  if (report.ci) {
1511
1689
  items.push({
1512
1690
  label: "CI",
1513
- value: report.ci.url ? /* @__PURE__ */ jsxs19("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1691
+ value: report.ci.url ? /* @__PURE__ */ jsxs20("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1514
1692
  ciDisplayName(report.ci.name),
1515
1693
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1516
1694
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1521,7 +1699,7 @@ function ReportMeta() {
1521
1699
  const label = `#${report.ci.prNumber}`;
1522
1700
  items.push({
1523
1701
  label: "PR",
1524
- value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1702
+ value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1525
1703
  });
1526
1704
  }
1527
1705
  if (items.length === 0) return null;
@@ -1529,48 +1707,48 @@ function ReportMeta() {
1529
1707
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1530
1708
  // collapsed disclosure so it doesn't push the result down. Native <details>
1531
1709
  // so it works with no JS (the SSR/no-hydration report still toggles).
1532
- /* @__PURE__ */ jsxs19("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1533
- /* @__PURE__ */ jsxs19("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1534
- /* @__PURE__ */ jsx32("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1710
+ /* @__PURE__ */ jsxs20("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1711
+ /* @__PURE__ */ jsxs20("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: [
1712
+ /* @__PURE__ */ jsx33("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1535
1713
  "Run details"
1536
1714
  ] }),
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 })
1715
+ /* @__PURE__ */ jsx33("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__ */ jsxs20("div", { className: "flex items-baseline gap-1.5", children: [
1716
+ /* @__PURE__ */ jsx33("dt", { className: "font-medium", children: item.label }),
1717
+ /* @__PURE__ */ jsx33("dd", { className: "font-mono text-foreground", children: item.value })
1540
1718
  ] }, item.label)) })
1541
1719
  ] })
1542
1720
  );
1543
1721
  }
1544
1722
 
1545
1723
  // src/components/ReportSchemaError.tsx
1546
- import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
1724
+ import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
1547
1725
  function ReportSchemaError({ error }) {
1548
- return /* @__PURE__ */ jsxs20("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1549
- /* @__PURE__ */ jsx33("p", { children: /* @__PURE__ */ jsx33("strong", { children: "Report could not be displayed." }) }),
1550
- /* @__PURE__ */ jsx33("p", { children: error.message }),
1551
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs20("p", { children: [
1726
+ return /* @__PURE__ */ jsxs21("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1727
+ /* @__PURE__ */ jsx34("p", { children: /* @__PURE__ */ jsx34("strong", { children: "Report could not be displayed." }) }),
1728
+ /* @__PURE__ */ jsx34("p", { children: error.message }),
1729
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs21("p", { children: [
1552
1730
  "The report bundle is newer than this version of ",
1553
- /* @__PURE__ */ jsx33("code", { children: "executable-stories-react" }),
1731
+ /* @__PURE__ */ jsx34("code", { children: "executable-stories-react" }),
1554
1732
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1555
1733
  ] }) : null,
1556
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs20("details", { children: [
1557
- /* @__PURE__ */ jsxs20("summary", { children: [
1734
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs21("details", { children: [
1735
+ /* @__PURE__ */ jsxs21("summary", { children: [
1558
1736
  error.issues.length,
1559
1737
  " validation issue",
1560
1738
  error.issues.length === 1 ? "" : "s"
1561
1739
  ] }),
1562
- /* @__PURE__ */ jsx33("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1740
+ /* @__PURE__ */ jsx34("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1563
1741
  ] }) : null
1564
1742
  ] });
1565
1743
  }
1566
1744
 
1567
1745
  // src/components/ReportShell.tsx
1568
- import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
1746
+ import { Fragment as Fragment10, jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
1569
1747
  function ReportTitleBlock({ title }) {
1570
- return /* @__PURE__ */ jsxs21(Fragment10, { children: [
1571
- /* @__PURE__ */ jsx34("h1", { children: title ?? "Story Report" }),
1572
- /* @__PURE__ */ jsx34(ReportSummary, {}),
1573
- /* @__PURE__ */ jsx34(ReportMeta, {})
1748
+ return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1749
+ /* @__PURE__ */ jsx35("h1", { children: title ?? "Story Report" }),
1750
+ /* @__PURE__ */ jsx35(ReportSummary, {}),
1751
+ /* @__PURE__ */ jsx35(ReportMeta, {})
1574
1752
  ] });
1575
1753
  }
1576
1754
  function ReportErrorShell({
@@ -1579,28 +1757,28 @@ function ReportErrorShell({
1579
1757
  title,
1580
1758
  dataTheme
1581
1759
  }) {
1582
- return /* @__PURE__ */ jsx34("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx34(ReportSchemaError, { error }) });
1760
+ return /* @__PURE__ */ jsx35("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx35(ReportSchemaError, { error }) });
1583
1761
  }
1584
1762
 
1585
1763
  // src/components/Report.tsx
1586
- import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
1764
+ import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1587
1765
  function Report(props) {
1588
1766
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1589
1767
  const result = unwrapReport(report);
1590
1768
  if (!result.ok) {
1591
- return /* @__PURE__ */ jsx35(ReportErrorShell, { error: result.error, className, title, dataTheme });
1769
+ return /* @__PURE__ */ jsx36(ReportErrorShell, { error: result.error, className, title, dataTheme });
1592
1770
  }
1593
1771
  const data = result.data;
1594
1772
  const hasContent = data.features.length > 0;
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, {})
1773
+ return /* @__PURE__ */ jsx36(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs23("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1774
+ /* @__PURE__ */ jsx36("header", { className: "es-report-header", children: /* @__PURE__ */ jsx36(ReportTitleBlock, { title }) }),
1775
+ hasContent ? /* @__PURE__ */ jsx36(ReportFeatureList, {}) : /* @__PURE__ */ jsx36(ReportEmpty, {})
1598
1776
  ] }) });
1599
1777
  }
1600
1778
 
1601
1779
  // src/components/doc/MermaidView.tsx
1602
1780
  import { useEffect, useRef, useState as useState2 } from "react";
1603
- import { Fragment as Fragment11, jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1781
+ import { Fragment as Fragment11, jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1604
1782
  function prefersDark(el) {
1605
1783
  const themed = el?.closest("[data-theme]");
1606
1784
  if (themed?.dataset.theme === "dark") return true;
@@ -1654,9 +1832,9 @@ function MermaidView({ entry, load }) {
1654
1832
  };
1655
1833
  }, [entry.code, load]);
1656
1834
  if (svg) {
1657
- return /* @__PURE__ */ jsxs23("figure", { ref, className: "my-3", children: [
1658
- entry.title ? /* @__PURE__ */ jsx36("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1659
- /* @__PURE__ */ jsx36(
1835
+ return /* @__PURE__ */ jsxs24("figure", { ref, className: "my-3", children: [
1836
+ entry.title ? /* @__PURE__ */ jsx37("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1837
+ /* @__PURE__ */ jsx37(
1660
1838
  "div",
1661
1839
  {
1662
1840
  role: "img",
@@ -1667,8 +1845,8 @@ function MermaidView({ entry, load }) {
1667
1845
  )
1668
1846
  ] });
1669
1847
  }
1670
- return /* @__PURE__ */ jsxs23(Fragment11, { children: [
1671
- error ? /* @__PURE__ */ jsxs23(
1848
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1849
+ error ? /* @__PURE__ */ jsxs24(
1672
1850
  "p",
1673
1851
  {
1674
1852
  role: "alert",
@@ -1680,19 +1858,19 @@ function MermaidView({ entry, load }) {
1680
1858
  ]
1681
1859
  }
1682
1860
  ) : null,
1683
- /* @__PURE__ */ jsx36(MermaidSource, { entry, ref })
1861
+ /* @__PURE__ */ jsx37(MermaidSource, { entry, ref })
1684
1862
  ] });
1685
1863
  }
1686
1864
 
1687
1865
  // src/components/doc/MermaidDiagram.tsx
1688
- import { jsx as jsx37 } from "react/jsx-runtime";
1866
+ import { jsx as jsx38 } from "react/jsx-runtime";
1689
1867
  var mermaidLoader;
1690
1868
  function loadMermaid() {
1691
1869
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1692
1870
  return mermaidLoader;
1693
1871
  }
1694
1872
  function MermaidDiagram({ entry, load = loadMermaid }) {
1695
- return /* @__PURE__ */ jsx37(MermaidView, { entry, load });
1873
+ return /* @__PURE__ */ jsx38(MermaidView, { entry, load });
1696
1874
  }
1697
1875
 
1698
1876
  // src/components/ScenarioExplorer.tsx
@@ -1702,12 +1880,12 @@ import { useState as useState3 } from "react";
1702
1880
  import "react";
1703
1881
  import { Command as CommandPrimitive } from "cmdk";
1704
1882
  import { SearchIcon } from "lucide-react";
1705
- import { jsx as jsx38, jsxs as jsxs24 } from "react/jsx-runtime";
1883
+ import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
1706
1884
  function Command({
1707
1885
  className,
1708
1886
  ...props
1709
1887
  }) {
1710
- return /* @__PURE__ */ jsx38(
1888
+ return /* @__PURE__ */ jsx39(
1711
1889
  CommandPrimitive,
1712
1890
  {
1713
1891
  "data-slot": "command",
@@ -1723,14 +1901,14 @@ function CommandInput({
1723
1901
  className,
1724
1902
  ...props
1725
1903
  }) {
1726
- return /* @__PURE__ */ jsxs24(
1904
+ return /* @__PURE__ */ jsxs25(
1727
1905
  "div",
1728
1906
  {
1729
1907
  "data-slot": "command-input-wrapper",
1730
1908
  className: "flex h-9 items-center gap-2 border-b px-3",
1731
1909
  children: [
1732
- /* @__PURE__ */ jsx38(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1733
- /* @__PURE__ */ jsx38(
1910
+ /* @__PURE__ */ jsx39(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1911
+ /* @__PURE__ */ jsx39(
1734
1912
  CommandPrimitive.Input,
1735
1913
  {
1736
1914
  "data-slot": "command-input",
@@ -1749,7 +1927,7 @@ function CommandList({
1749
1927
  className,
1750
1928
  ...props
1751
1929
  }) {
1752
- return /* @__PURE__ */ jsx38(
1930
+ return /* @__PURE__ */ jsx39(
1753
1931
  CommandPrimitive.List,
1754
1932
  {
1755
1933
  "data-slot": "command-list",
@@ -1764,7 +1942,7 @@ function CommandList({
1764
1942
  function CommandEmpty({
1765
1943
  ...props
1766
1944
  }) {
1767
- return /* @__PURE__ */ jsx38(
1945
+ return /* @__PURE__ */ jsx39(
1768
1946
  CommandPrimitive.Empty,
1769
1947
  {
1770
1948
  "data-slot": "command-empty",
@@ -1777,7 +1955,7 @@ function CommandGroup({
1777
1955
  className,
1778
1956
  ...props
1779
1957
  }) {
1780
- return /* @__PURE__ */ jsx38(
1958
+ return /* @__PURE__ */ jsx39(
1781
1959
  CommandPrimitive.Group,
1782
1960
  {
1783
1961
  "data-slot": "command-group",
@@ -1793,7 +1971,7 @@ function CommandItem({
1793
1971
  className,
1794
1972
  ...props
1795
1973
  }) {
1796
- return /* @__PURE__ */ jsx38(
1974
+ return /* @__PURE__ */ jsx39(
1797
1975
  CommandPrimitive.Item,
1798
1976
  {
1799
1977
  "data-slot": "command-item",
@@ -1807,7 +1985,7 @@ function CommandItem({
1807
1985
  }
1808
1986
 
1809
1987
  // src/components/ScenarioExplorer.tsx
1810
- import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
1988
+ import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
1811
1989
  var STATUS_FILTERS = [
1812
1990
  { value: "all", label: "All" },
1813
1991
  { value: "passed", label: "Passed" },
@@ -1818,22 +1996,22 @@ var STATUS_FILTERS = [
1818
1996
  function ScenarioExplorer({ scenarios, summary }) {
1819
1997
  const [status, setStatus] = useState3("all");
1820
1998
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1821
- return /* @__PURE__ */ jsxs25("div", { className: "font-sans text-foreground", children: [
1822
- summary ? /* @__PURE__ */ jsxs25("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1999
+ return /* @__PURE__ */ jsxs26("div", { className: "font-sans text-foreground", children: [
2000
+ summary ? /* @__PURE__ */ jsxs26("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1823
2001
  summary.total,
1824
2002
  " scenarios \xB7 ",
1825
- /* @__PURE__ */ jsxs25("span", { className: "text-pass", children: [
2003
+ /* @__PURE__ */ jsxs26("span", { className: "text-pass", children: [
1826
2004
  summary.passed,
1827
2005
  " passed"
1828
2006
  ] }),
1829
2007
  " \xB7",
1830
2008
  " ",
1831
- /* @__PURE__ */ jsxs25("span", { className: "text-fail", children: [
2009
+ /* @__PURE__ */ jsxs26("span", { className: "text-fail", children: [
1832
2010
  summary.failed,
1833
2011
  " failed"
1834
2012
  ] })
1835
2013
  ] }) : null,
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(
2014
+ /* @__PURE__ */ jsx40("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx40(
1837
2015
  "button",
1838
2016
  {
1839
2017
  type: "button",
@@ -1848,26 +2026,26 @@ function ScenarioExplorer({ scenarios, summary }) {
1848
2026
  },
1849
2027
  f.value
1850
2028
  )) }),
1851
- /* @__PURE__ */ jsxs25(
2029
+ /* @__PURE__ */ jsxs26(
1852
2030
  Command,
1853
2031
  {
1854
2032
  className: "rounded-lg border border-border bg-card",
1855
2033
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1856
2034
  children: [
1857
- /* @__PURE__ */ jsx39(CommandInput, { placeholder: "Search scenarios\u2026" }),
1858
- /* @__PURE__ */ jsxs25(CommandList, { className: "max-h-none", children: [
1859
- /* @__PURE__ */ jsx39(CommandEmpty, { children: "No scenarios match your filters." }),
1860
- /* @__PURE__ */ jsx39(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx39(
2035
+ /* @__PURE__ */ jsx40(CommandInput, { placeholder: "Search scenarios\u2026" }),
2036
+ /* @__PURE__ */ jsxs26(CommandList, { className: "max-h-none", children: [
2037
+ /* @__PURE__ */ jsx40(CommandEmpty, { children: "No scenarios match your filters." }),
2038
+ /* @__PURE__ */ jsx40(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx40(
1861
2039
  CommandItem,
1862
2040
  {
1863
2041
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1864
2042
  asChild: true,
1865
2043
  className: "cursor-pointer",
1866
- children: /* @__PURE__ */ jsxs25("a", { href: s.href, className: "flex items-center gap-3", children: [
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 })
2044
+ children: /* @__PURE__ */ jsxs26("a", { href: s.href, className: "flex items-center gap-3", children: [
2045
+ /* @__PURE__ */ jsx40(Badge, { variant: s.status, children: s.status }),
2046
+ /* @__PURE__ */ jsx40("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
2047
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx40(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
2048
+ /* @__PURE__ */ jsx40("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1871
2049
  ] })
1872
2050
  },
1873
2051
  s.id
@@ -2889,6 +3067,8 @@ function parseStoryReport(input) {
2889
3067
  });
2890
3068
  }
2891
3069
  export {
3070
+ DATA_MODEL_TYPE,
3071
+ DataModelBlock,
2892
3072
  DocCode,
2893
3073
  DocCustom,
2894
3074
  DocEntry,
@@ -2902,6 +3082,8 @@ export {
2902
3082
  DocTable,
2903
3083
  DocTag,
2904
3084
  DocVideo,
3085
+ FILE_TREE_TYPE,
3086
+ FileTreeBlock,
2905
3087
  MermaidDiagram,
2906
3088
  MermaidSource,
2907
3089
  Report,
@@ -2931,7 +3113,10 @@ export {
2931
3113
  err,
2932
3114
  formatRelativeAge,
2933
3115
  isReportStale,
3116
+ narrativeBlockRenderers,
2934
3117
  ok,
3118
+ parseDataModel,
3119
+ parseFileTree,
2935
3120
  parseStoryReport,
2936
3121
  prUrl,
2937
3122
  reportLastRunMs,