executable-stories-react 0.8.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.cjs CHANGED
@@ -31,6 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var src_exports = {};
33
33
  __export(src_exports, {
34
+ DATA_MODEL_TYPE: () => DATA_MODEL_TYPE,
35
+ DataModelBlock: () => DataModelBlock,
34
36
  DocCode: () => DocCode,
35
37
  DocCustom: () => DocCustom,
36
38
  DocEntry: () => DocEntry,
@@ -44,6 +46,8 @@ __export(src_exports, {
44
46
  DocTable: () => DocTable,
45
47
  DocTag: () => DocTag,
46
48
  DocVideo: () => DocVideo,
49
+ FILE_TREE_TYPE: () => FILE_TREE_TYPE,
50
+ FileTreeBlock: () => FileTreeBlock,
47
51
  MermaidDiagram: () => MermaidDiagram,
48
52
  MermaidSource: () => MermaidSource,
49
53
  Report: () => Report,
@@ -73,7 +77,10 @@ __export(src_exports, {
73
77
  err: () => err,
74
78
  formatRelativeAge: () => formatRelativeAge,
75
79
  isReportStale: () => isReportStale,
80
+ narrativeBlockRenderers: () => narrativeBlockRenderers,
76
81
  ok: () => ok,
82
+ parseDataModel: () => parseDataModel,
83
+ parseFileTree: () => parseFileTree,
77
84
  parseStoryReport: () => parseStoryReport,
78
85
  prUrl: () => prUrl,
79
86
  reportLastRunMs: () => reportLastRunMs,
@@ -101,63 +108,6 @@ var import_react2 = require("react");
101
108
  var import_react = require("react");
102
109
  var ReportContext = (0, import_react.createContext)(null);
103
110
 
104
- // src/context/ReportRoot.tsx
105
- var import_jsx_runtime = require("react/jsx-runtime");
106
- var EMPTY_CUSTOM = {};
107
- var EMPTY_RENDERERS = {};
108
- function ReportRoot({
109
- report,
110
- customRenderers,
111
- renderers,
112
- children
113
- }) {
114
- const value = (0, import_react2.useMemo)(
115
- () => ({
116
- report,
117
- customRenderers: customRenderers ?? EMPTY_CUSTOM,
118
- renderers: renderers ?? EMPTY_RENDERERS
119
- }),
120
- [report, customRenderers, renderers]
121
- );
122
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReportContext.Provider, { value, children });
123
- }
124
-
125
- // src/hooks/useReport.ts
126
- var import_react3 = require("react");
127
- function useReport() {
128
- const ctx = (0, import_react3.useContext)(ReportContext);
129
- if (!ctx) {
130
- throw new Error(
131
- "useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
132
- );
133
- }
134
- return ctx.report;
135
- }
136
-
137
- // ../executable-stories-core/dist/utils/duration.js
138
- function formatDuration(ms) {
139
- if (ms < 1e3) {
140
- return `${Math.round(ms)} ms`;
141
- }
142
- if (ms < 6e4) {
143
- return `${(ms / 1e3).toFixed(2)} s`;
144
- }
145
- const minutes = Math.floor(ms / 6e4);
146
- const seconds = Math.floor(ms % 6e4 / 1e3);
147
- if (minutes < 60) {
148
- return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
149
- }
150
- const hours = Math.floor(minutes / 60);
151
- const remainingMinutes = minutes % 60;
152
- return `${hours}h ${remainingMinutes}m`;
153
- }
154
-
155
- // src/components/doc/DocNote.tsx
156
- var import_jsx_runtime2 = require("react/jsx-runtime");
157
- function DocNote({ entry }) {
158
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
159
- }
160
-
161
111
  // src/components/ui/badge.tsx
162
112
  var React = require("react");
163
113
  var import_class_variance_authority = require("class-variance-authority");
@@ -216,14 +166,249 @@ function Badge({
216
166
  });
217
167
  }
218
168
 
219
- // src/components/doc/DocTag.tsx
169
+ // src/components/doc/NarrativeBlocks.tsx
170
+ var import_jsx_runtime = require("react/jsx-runtime");
171
+ var FILE_TREE_TYPE = "file-tree";
172
+ var DATA_MODEL_TYPE = "data-model";
173
+ function isChangeKind(value) {
174
+ return value === "added" || value === "modified" || value === "removed" || value === "renamed";
175
+ }
176
+ function isRecord(value) {
177
+ return typeof value === "object" && value !== null && !Array.isArray(value);
178
+ }
179
+ function str(value) {
180
+ return typeof value === "string" && value !== "" ? value : void 0;
181
+ }
182
+ function AuthoredMarker({ authored }) {
183
+ if (authored !== "agent") return null;
184
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
185
+ }
186
+ function BlockFrame({
187
+ title,
188
+ authored,
189
+ children
190
+ }) {
191
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figure", { className: "my-3", children: [
192
+ title || authored === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
193
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
194
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthoredMarker, { authored })
195
+ ] }) : null,
196
+ children
197
+ ] });
198
+ }
199
+ function ChangeBadge({ change }) {
200
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, { variant: "tag", className: "text-[10px]", children: change });
201
+ }
202
+ function parseFileTree(data) {
203
+ if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
204
+ const files = [];
205
+ for (const raw of data.files) {
206
+ if (typeof raw === "string") {
207
+ if (raw) files.push({ path: raw });
208
+ continue;
209
+ }
210
+ if (!isRecord(raw)) continue;
211
+ const path = str(raw.path);
212
+ if (!path) continue;
213
+ files.push({
214
+ path,
215
+ change: isChangeKind(raw.change) ? raw.change : void 0,
216
+ note: str(raw.note)
217
+ });
218
+ }
219
+ if (files.length === 0) return void 0;
220
+ return { title: str(data.title), authored: str(data.authored), files };
221
+ }
222
+ function buildTree(files) {
223
+ const root = { name: "", children: /* @__PURE__ */ new Map() };
224
+ for (const file of files) {
225
+ const segments = file.path.split("/").filter(Boolean);
226
+ let node = root;
227
+ segments.forEach((segment, index) => {
228
+ let child = node.children.get(segment);
229
+ if (!child) {
230
+ child = { name: segment, children: /* @__PURE__ */ new Map() };
231
+ node.children.set(segment, child);
232
+ }
233
+ if (index === segments.length - 1) child.file = file;
234
+ node = child;
235
+ });
236
+ }
237
+ return root;
238
+ }
239
+ function sortedChildren(node) {
240
+ return [...node.children.values()].sort((a, b) => {
241
+ const aDir = a.children.size > 0;
242
+ const bDir = b.children.size > 0;
243
+ if (aDir !== bDir) return aDir ? -1 : 1;
244
+ return a.name.localeCompare(b.name);
245
+ });
246
+ }
247
+ function TreeBranch({ node, depth }) {
248
+ const children = sortedChildren(node);
249
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
250
+ const isDir = child.children.size > 0;
251
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
252
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-baseline gap-2", children: [
253
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
254
+ "span",
255
+ {
256
+ className: cn(
257
+ "font-mono text-xs",
258
+ isDir ? "text-muted-foreground" : "text-foreground"
259
+ ),
260
+ children: isDir ? `${child.name}/` : child.name
261
+ }
262
+ ),
263
+ child.file?.change ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeBadge, { change: child.file.change }) : null,
264
+ child.file?.note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
265
+ ] }),
266
+ isDir ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeBranch, { node: child, depth: depth + 1 }) : null
267
+ ] }, child.name);
268
+ }) });
269
+ }
270
+ function FileTreeBlock({ entry }) {
271
+ const data = parseFileTree(entry.data);
272
+ if (!data) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnreadableBlock, { entry });
273
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
274
+ }
275
+ function parseDataModel(data) {
276
+ if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
277
+ const fields = [];
278
+ for (const raw of data.fields) {
279
+ if (!isRecord(raw)) continue;
280
+ const name = str(raw.name);
281
+ if (!name) continue;
282
+ fields.push({
283
+ name,
284
+ type: str(raw.type),
285
+ note: str(raw.note),
286
+ change: isChangeKind(raw.change) ? raw.change : void 0
287
+ });
288
+ }
289
+ if (fields.length === 0) return void 0;
290
+ return {
291
+ title: str(data.title),
292
+ authored: str(data.authored),
293
+ name: str(data.name),
294
+ fields
295
+ };
296
+ }
297
+ function DataModelBlock({ entry }) {
298
+ const data = parseDataModel(entry.data);
299
+ if (!data) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnreadableBlock, { entry });
300
+ const hasNotes = data.fields.some((f) => f.note);
301
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
302
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { className: "bg-muted/50", children: [
303
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
304
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
305
+ hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
306
+ ] }) }),
307
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: data.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
308
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex flex-wrap items-center gap-2", children: [
309
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono text-xs text-foreground", children: field.name }),
310
+ field.change ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeBadge, { change: field.change }) : null
311
+ ] }) }),
312
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
313
+ hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
314
+ ] }, field.name)) })
315
+ ] }) }) });
316
+ }
317
+ function UnreadableBlock({ entry }) {
318
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
319
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
320
+ entry.type,
321
+ " (unrecognised shape)"
322
+ ] }),
323
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
324
+ "pre",
325
+ {
326
+ tabIndex: 0,
327
+ className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground",
328
+ children: safeStringify(entry.data)
329
+ }
330
+ )
331
+ ] });
332
+ }
333
+ function safeStringify(value) {
334
+ try {
335
+ return JSON.stringify(value, null, 2);
336
+ } catch {
337
+ return String(value);
338
+ }
339
+ }
340
+ var narrativeBlockRenderers = {
341
+ [FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileTreeBlock, { entry }),
342
+ [DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataModelBlock, { entry })
343
+ };
344
+
345
+ // src/context/ReportRoot.tsx
346
+ var import_jsx_runtime2 = require("react/jsx-runtime");
347
+ var EMPTY_RENDERERS = {};
348
+ function ReportRoot({
349
+ report,
350
+ customRenderers,
351
+ renderers,
352
+ children
353
+ }) {
354
+ const value = (0, import_react2.useMemo)(
355
+ () => ({
356
+ report,
357
+ // Narrative blocks render everywhere the report does (static SSR, the
358
+ // island, Astro) without every host wiring them up. A host renderer for
359
+ // the same type still wins.
360
+ customRenderers: { ...narrativeBlockRenderers, ...customRenderers },
361
+ renderers: renderers ?? EMPTY_RENDERERS
362
+ }),
363
+ [report, customRenderers, renderers]
364
+ );
365
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReportContext.Provider, { value, children });
366
+ }
367
+
368
+ // src/hooks/useReport.ts
369
+ var import_react3 = require("react");
370
+ function useReport() {
371
+ const ctx = (0, import_react3.useContext)(ReportContext);
372
+ if (!ctx) {
373
+ throw new Error(
374
+ "useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
375
+ );
376
+ }
377
+ return ctx.report;
378
+ }
379
+
380
+ // ../executable-stories-core/dist/utils/duration.js
381
+ function formatDuration(ms) {
382
+ if (ms < 1e3) {
383
+ return `${Math.round(ms)} ms`;
384
+ }
385
+ if (ms < 6e4) {
386
+ return `${(ms / 1e3).toFixed(2)} s`;
387
+ }
388
+ const minutes = Math.floor(ms / 6e4);
389
+ const seconds = Math.floor(ms % 6e4 / 1e3);
390
+ if (minutes < 60) {
391
+ return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
392
+ }
393
+ const hours = Math.floor(minutes / 60);
394
+ const remainingMinutes = minutes % 60;
395
+ return `${hours}h ${remainingMinutes}m`;
396
+ }
397
+
398
+ // src/components/doc/DocNote.tsx
220
399
  var import_jsx_runtime3 = require("react/jsx-runtime");
400
+ function DocNote({ entry }) {
401
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
402
+ }
403
+
404
+ // src/components/doc/DocTag.tsx
405
+ var import_jsx_runtime4 = require("react/jsx-runtime");
221
406
  function DocTag({ entry }) {
222
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Badge, { variant: "tag", children: n }) }, n)) });
407
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Badge, { variant: "tag", children: n }) }, n)) });
223
408
  }
224
409
 
225
410
  // src/components/doc/DocKv.tsx
226
- var import_jsx_runtime4 = require("react/jsx-runtime");
411
+ var import_jsx_runtime5 = require("react/jsx-runtime");
227
412
  function formatValue(value) {
228
413
  if (value === null) return "null";
229
414
  if (typeof value === "string") return value;
@@ -235,19 +420,19 @@ function formatValue(value) {
235
420
  }
236
421
  }
237
422
  function DocKv({ entry }) {
238
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
239
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
240
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
423
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
424
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
425
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
241
426
  ] });
242
427
  }
243
428
 
244
429
  // src/hooks/useRenderers.ts
245
430
  var import_react4 = require("react");
246
- var EMPTY_CUSTOM2 = {};
431
+ var EMPTY_CUSTOM = {};
247
432
  var EMPTY_RENDERERS2 = {};
248
433
  function useCustomRenderers() {
249
434
  const ctx = (0, import_react4.useContext)(ReportContext);
250
- return ctx?.customRenderers ?? EMPTY_CUSTOM2;
435
+ return ctx?.customRenderers ?? EMPTY_CUSTOM;
251
436
  }
252
437
  function useBuiltinRenderers() {
253
438
  const ctx = (0, import_react4.useContext)(ReportContext);
@@ -255,37 +440,37 @@ function useBuiltinRenderers() {
255
440
  }
256
441
 
257
442
  // src/components/doc/DocCode.tsx
258
- var import_jsx_runtime5 = require("react/jsx-runtime");
443
+ var import_jsx_runtime6 = require("react/jsx-runtime");
259
444
  function CodeFigure({ label, children }) {
260
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("figure", { className: "my-3", children: [
261
- label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
262
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
445
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("figure", { className: "my-3", children: [
446
+ label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
447
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
263
448
  ] });
264
449
  }
265
450
  function DocCode({ entry }) {
266
451
  const renderers = useBuiltinRenderers();
267
452
  if (renderers.code) {
268
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: renderers.code(entry) });
453
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: renderers.code(entry) });
269
454
  }
270
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CodeFigure, { label: entry.label, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
455
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CodeFigure, { label: entry.label, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
271
456
  }
272
457
 
273
458
  // src/components/doc/DocTable.tsx
274
- var import_jsx_runtime6 = require("react/jsx-runtime");
459
+ var import_jsx_runtime7 = require("react/jsx-runtime");
275
460
  function DocTable({ entry }) {
276
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("figure", { className: "my-3", children: [
277
- entry.label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
278
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
279
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
280
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
461
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("figure", { className: "my-3", children: [
462
+ entry.label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
463
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
464
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
465
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
281
466
  ] }) })
282
467
  ] });
283
468
  }
284
469
 
285
470
  // src/components/doc/DocLink.tsx
286
- var import_jsx_runtime7 = require("react/jsx-runtime");
471
+ var import_jsx_runtime8 = require("react/jsx-runtime");
287
472
  function DocLink({ entry }) {
288
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
473
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
289
474
  "a",
290
475
  {
291
476
  className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
@@ -319,7 +504,7 @@ function isLocalFsPath(value) {
319
504
  }
320
505
 
321
506
  // src/components/doc/DocSection.tsx
322
- var import_jsx_runtime8 = require("react/jsx-runtime");
507
+ var import_jsx_runtime9 = require("react/jsx-runtime");
323
508
  function neutralizeUrl(value) {
324
509
  return safeUrl(value) ?? "#";
325
510
  }
@@ -330,12 +515,12 @@ function safeMarkdownHtml(markdown) {
330
515
  function DocSection({ entry }) {
331
516
  const renderers = useBuiltinRenderers();
332
517
  if (renderers.section) {
333
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: renderers.section(entry) });
518
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: renderers.section(entry) });
334
519
  }
335
520
  const html = safeMarkdownHtml(entry.markdown);
336
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
337
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
338
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
521
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
522
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
523
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
339
524
  "div",
340
525
  {
341
526
  className: "es-doc-prose prose prose-sm max-w-none",
@@ -346,11 +531,11 @@ function DocSection({ entry }) {
346
531
  }
347
532
 
348
533
  // src/components/doc/DocMermaid.tsx
349
- var import_jsx_runtime9 = require("react/jsx-runtime");
534
+ var import_jsx_runtime10 = require("react/jsx-runtime");
350
535
  function MermaidSource({ entry, ref }) {
351
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
352
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
353
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
536
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
537
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
538
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
354
539
  "pre",
355
540
  {
356
541
  "data-mermaid": true,
@@ -364,24 +549,24 @@ function MermaidSource({ entry, ref }) {
364
549
  function DocMermaid({ entry }) {
365
550
  const renderers = useBuiltinRenderers();
366
551
  if (renderers.mermaid) {
367
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: renderers.mermaid(entry) });
552
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: renderers.mermaid(entry) });
368
553
  }
369
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MermaidSource, { entry });
554
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MermaidSource, { entry });
370
555
  }
371
556
 
372
557
  // src/components/doc/DocScreenshot.tsx
373
- var import_jsx_runtime10 = require("react/jsx-runtime");
558
+ var import_jsx_runtime11 = require("react/jsx-runtime");
374
559
  function DocScreenshot({ entry }) {
375
560
  const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
376
561
  if (!src) {
377
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
378
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
379
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
380
- entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
562
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
563
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
564
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
565
+ entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
381
566
  ] });
382
567
  }
383
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("figure", { className: "my-3", children: [
384
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
568
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3", children: [
569
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
385
570
  "img",
386
571
  {
387
572
  src,
@@ -390,24 +575,24 @@ function DocScreenshot({ entry }) {
390
575
  className: "max-w-full rounded-md border border-border"
391
576
  }
392
577
  ),
393
- entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
578
+ entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
394
579
  ] });
395
580
  }
396
581
 
397
582
  // src/components/doc/DocVideo.tsx
398
- var import_jsx_runtime11 = require("react/jsx-runtime");
583
+ var import_jsx_runtime12 = require("react/jsx-runtime");
399
584
  function DocVideo({ entry }) {
400
585
  if (isLocalFsPath(entry.path)) {
401
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
402
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
403
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
404
- entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
586
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
587
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
588
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
589
+ entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
405
590
  ] });
406
591
  }
407
592
  const src = safeUrl(entry.path);
408
593
  const poster = safeUrl(entry.poster);
409
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3", children: [
410
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
594
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3", children: [
595
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
411
596
  "video",
412
597
  {
413
598
  controls: true,
@@ -417,21 +602,21 @@ function DocVideo({ entry }) {
417
602
  className: "max-w-full rounded-md border border-border"
418
603
  }
419
604
  ),
420
- entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
605
+ entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
421
606
  ] });
422
607
  }
423
608
 
424
609
  // src/components/doc/DocHtml.tsx
425
- var import_jsx_runtime12 = require("react/jsx-runtime");
610
+ var import_jsx_runtime13 = require("react/jsx-runtime");
426
611
  function DocHtml({ entry }) {
427
612
  const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
428
613
  const title = entry.title ?? "Embedded HTML";
429
614
  const safeHref = safeUrl(entry.url ?? entry.path);
430
615
  const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
431
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
432
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("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: [
433
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: entry.title ?? "HTML" }),
434
- safeHref ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
616
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
617
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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: [
618
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: entry.title ?? "HTML" }),
619
+ safeHref ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
435
620
  "a",
436
621
  {
437
622
  href: safeHref,
@@ -444,7 +629,7 @@ function DocHtml({ entry }) {
444
629
  }
445
630
  ) : null
446
631
  ] }),
447
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
632
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
448
633
  "iframe",
449
634
  {
450
635
  ...frameProps,
@@ -459,7 +644,7 @@ function DocHtml({ entry }) {
459
644
  }
460
645
 
461
646
  // src/components/doc/DocState.tsx
462
- var import_jsx_runtime13 = require("react/jsx-runtime");
647
+ var import_jsx_runtime14 = require("react/jsx-runtime");
463
648
  function DocState({ entry }) {
464
649
  let json;
465
650
  try {
@@ -467,23 +652,23 @@ function DocState({ entry }) {
467
652
  } catch {
468
653
  json = String(entry.value);
469
654
  }
470
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
655
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
471
656
  }
472
657
 
473
658
  // src/components/doc/DocCustom.tsx
474
- var import_jsx_runtime14 = require("react/jsx-runtime");
659
+ var import_jsx_runtime15 = require("react/jsx-runtime");
475
660
  function DocCustom({ entry }) {
476
661
  const renderers = useCustomRenderers();
477
662
  const renderer = renderers[entry.type];
478
663
  if (renderer) {
479
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: renderer(entry) });
664
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: renderer(entry) });
480
665
  }
481
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
482
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
483
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
666
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
667
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
668
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify2(entry.data) })
484
669
  ] });
485
670
  }
486
- function safeStringify(value) {
671
+ function safeStringify2(value) {
487
672
  try {
488
673
  return JSON.stringify(value, null, 2);
489
674
  } catch {
@@ -492,47 +677,47 @@ function safeStringify(value) {
492
677
  }
493
678
 
494
679
  // src/components/doc/DocEntry.tsx
495
- var import_jsx_runtime15 = require("react/jsx-runtime");
680
+ var import_jsx_runtime16 = require("react/jsx-runtime");
496
681
  function DocEntry({ entry }) {
497
682
  switch (entry.kind) {
498
683
  case "note":
499
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocNote, { entry });
684
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocNote, { entry });
500
685
  case "tag":
501
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTag, { entry });
686
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocTag, { entry });
502
687
  case "kv":
503
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocKv, { entry });
688
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocKv, { entry });
504
689
  case "code":
505
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCode, { entry });
690
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocCode, { entry });
506
691
  case "table":
507
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTable, { entry });
692
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocTable, { entry });
508
693
  case "link":
509
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocLink, { entry });
694
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocLink, { entry });
510
695
  case "section":
511
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocSection, { entry });
696
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocSection, { entry });
512
697
  case "mermaid":
513
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocMermaid, { entry });
698
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocMermaid, { entry });
514
699
  case "screenshot":
515
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocScreenshot, { entry });
700
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocScreenshot, { entry });
516
701
  case "video":
517
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocVideo, { entry });
702
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocVideo, { entry });
518
703
  case "html":
519
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocHtml, { entry });
704
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocHtml, { entry });
520
705
  case "state":
521
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocState, { entry });
706
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocState, { entry });
522
707
  case "custom":
523
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCustom, { entry });
708
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocCustom, { entry });
524
709
  }
525
710
  }
526
711
 
527
712
  // src/components/ReportDocEntries.tsx
528
- var import_jsx_runtime16 = require("react/jsx-runtime");
713
+ var import_jsx_runtime17 = require("react/jsx-runtime");
529
714
  function ReportDocEntries({ entries }) {
530
715
  if (entries.length === 0) return null;
531
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocEntry, { entry }, i)) });
716
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocEntry, { entry }, i)) });
532
717
  }
533
718
 
534
719
  // src/lib/step-params.tsx
535
- var import_jsx_runtime17 = require("react/jsx-runtime");
720
+ var import_jsx_runtime18 = require("react/jsx-runtime");
536
721
  var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
537
722
  function highlightStepParams(text) {
538
723
  const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
@@ -544,7 +729,7 @@ function highlightStepParams(text) {
544
729
  const end = start + match[0].length;
545
730
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
546
731
  nodes.push(
547
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
732
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
548
733
  );
549
734
  lastIndex = end;
550
735
  });
@@ -553,7 +738,7 @@ function highlightStepParams(text) {
553
738
  }
554
739
 
555
740
  // src/components/ReportSteps.tsx
556
- var import_jsx_runtime18 = require("react/jsx-runtime");
741
+ var import_jsx_runtime19 = require("react/jsx-runtime");
557
742
  var STEP_GLYPH = {
558
743
  passed: "\u2713",
559
744
  failed: "\u2717",
@@ -568,21 +753,21 @@ var STEP_GLYPH_COLOR = {
568
753
  };
569
754
  function ReportSteps({ scenario }) {
570
755
  if (scenario.steps.length === 0) return null;
571
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportStepItem, { step }, step.id)) });
756
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ReportStepItem, { step }, step.id)) });
572
757
  }
573
758
  function ReportStepItem({ step }) {
574
759
  const kw = step.keyword.toLowerCase();
575
760
  const continuation = kw === "and" || kw === "but";
576
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
761
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
577
762
  "li",
578
763
  {
579
764
  id: step.id,
580
765
  "data-status": step.status,
581
766
  className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
582
767
  children: [
583
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-baseline gap-2", children: [
584
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
585
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
768
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-baseline gap-2", children: [
769
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
770
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
586
771
  "span",
587
772
  {
588
773
  className: cn(
@@ -592,10 +777,10 @@ function ReportStepItem({ step }) {
592
777
  children: step.keyword
593
778
  }
594
779
  ),
595
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
596
- step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
780
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
781
+ step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
597
782
  ] }),
598
- step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
783
+ step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
599
784
  "pre",
600
785
  {
601
786
  role: "alert",
@@ -603,7 +788,7 @@ function ReportStepItem({ step }) {
603
788
  children: step.errorMessage
604
789
  }
605
790
  ) : null,
606
- step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
791
+ step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
607
792
  ]
608
793
  }
609
794
  );
@@ -728,7 +913,7 @@ function extractStoryboardFrames(scenario) {
728
913
  }
729
914
 
730
915
  // src/components/ReportStoryboard.tsx
731
- var import_jsx_runtime19 = require("react/jsx-runtime");
916
+ var import_jsx_runtime20 = require("react/jsx-runtime");
732
917
  var FRAME_GLYPH = {
733
918
  passed: "\u2713",
734
919
  failed: "\u2717",
@@ -744,32 +929,32 @@ var FRAME_GLYPH_COLOR = {
744
929
  function ReportStoryboard({ scenario }) {
745
930
  const frames = extractStoryboardFrames(scenario);
746
931
  if (frames.length < 2) return null;
747
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
748
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
749
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
932
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
933
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
934
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
750
935
  ] });
751
936
  }
752
937
  function StoryboardFrameItem({ frame }) {
753
938
  const label = `${frame.keyword} ${frame.text}`;
754
939
  const hasStates = frame.states.length > 0;
755
- const caption = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
756
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
757
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0", children: [
758
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
940
+ const caption = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
941
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
942
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "min-w-0", children: [
943
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
759
944
  " ",
760
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
945
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
761
946
  ] })
762
947
  ] });
763
948
  return (
764
949
  // State cards need room for diff rows; screenshot-only frames keep the
765
950
  // original narrow film-cell width (and DOM) unchanged.
766
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
767
- frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FrameScreenshot, { frame, label }) : null,
768
- hasStates ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StateCardView, { card }, card.label ?? i)) }) : null,
951
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
952
+ frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FrameScreenshot, { frame, label }) : null,
953
+ hasStates ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StateCardView, { card }, card.label ?? i)) }) : null,
769
954
  frame.screenshot ? caption : (
770
955
  // No screenshot means no image anchor, so the caption carries the
771
956
  // jump-to-step link instead.
772
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
957
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
773
958
  )
774
959
  ] })
775
960
  );
@@ -777,13 +962,13 @@ function StoryboardFrameItem({ frame }) {
777
962
  function FrameScreenshot({ frame, label }) {
778
963
  const path = frame.screenshot?.path ?? "";
779
964
  const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
780
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
965
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
781
966
  "a",
782
967
  {
783
968
  href: `#${frame.stepId}`,
784
969
  "aria-label": `Jump to step: ${label}`,
785
970
  className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
786
- children: src ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
971
+ children: src ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
787
972
  "img",
788
973
  {
789
974
  src,
@@ -791,7 +976,7 @@ function FrameScreenshot({ frame, label }) {
791
976
  loading: "lazy",
792
977
  className: "h-24 w-full bg-muted object-cover object-top"
793
978
  }
794
- ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
979
+ ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
795
980
  }
796
981
  );
797
982
  }
@@ -810,12 +995,12 @@ function prettyJson(value) {
810
995
  function StateCardView({ card }) {
811
996
  const json = prettyJson(card.value);
812
997
  const firstCapture = card.changes === void 0;
813
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
814
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
815
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground", children: card.label ?? "State" }),
816
- firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
998
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
999
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
1000
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground", children: card.label ?? "State" }),
1001
+ firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
817
1002
  ] }),
818
- !firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1003
+ !firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
819
1004
  "li",
820
1005
  {
821
1006
  className: cn(
@@ -825,15 +1010,15 @@ function StateCardView({ card }) {
825
1010
  children: summarizeStateChanges([change])[0]
826
1011
  },
827
1012
  i
828
- )) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
829
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1013
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
1014
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
830
1015
  "details",
831
1016
  {
832
1017
  open: firstCapture && json.length <= 240,
833
1018
  className: cn(firstCapture ? "mt-1.5" : "mt-1"),
834
1019
  children: [
835
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
836
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("pre", { tabIndex: 0, className: "mt-1 max-h-48 overflow-auto rounded-sm bg-muted p-1.5 font-mono text-[0.625rem] leading-snug", children: json })
1020
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
1021
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("pre", { tabIndex: 0, className: "mt-1 max-h-48 overflow-auto rounded-sm bg-muted p-1.5 font-mono text-[0.625rem] leading-snug", children: json })
837
1022
  ]
838
1023
  }
839
1024
  )
@@ -841,17 +1026,17 @@ function StateCardView({ card }) {
841
1026
  }
842
1027
 
843
1028
  // src/components/ReportAttachments.tsx
844
- var import_jsx_runtime20 = require("react/jsx-runtime");
1029
+ var import_jsx_runtime21 = require("react/jsx-runtime");
845
1030
  function ReportAttachments({ attachments }) {
846
1031
  if (attachments.length === 0) return null;
847
1032
  return (
848
1033
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
849
1034
  // blocks don't create duplicate "Attachments" region landmarks.
850
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
1035
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
851
1036
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
852
1037
  const isImage = att.mediaType.startsWith("image/");
853
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
854
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1038
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1039
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
855
1040
  "img",
856
1041
  {
857
1042
  src: dataUri,
@@ -860,8 +1045,8 @@ function ReportAttachments({ attachments }) {
860
1045
  className: "max-w-full rounded-md border border-border"
861
1046
  }
862
1047
  ),
863
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
864
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1048
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
1049
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
865
1050
  "a",
866
1051
  {
867
1052
  href: dataUri,
@@ -870,7 +1055,7 @@ function ReportAttachments({ attachments }) {
870
1055
  children: [
871
1056
  att.name,
872
1057
  " ",
873
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "text-muted-foreground", children: [
1058
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-muted-foreground", children: [
874
1059
  "(",
875
1060
  att.mediaType,
876
1061
  ")"
@@ -958,7 +1143,7 @@ function traceWindow(rows) {
958
1143
  }
959
1144
 
960
1145
  // src/components/ReportTrace.tsx
961
- var import_jsx_runtime21 = require("react/jsx-runtime");
1146
+ var import_jsx_runtime22 = require("react/jsx-runtime");
962
1147
  var BAR_COLOR = {
963
1148
  ok: "bg-pass",
964
1149
  error: "bg-fail",
@@ -969,8 +1154,8 @@ function ReportTrace({ spans }) {
969
1154
  const rows = toTraceRows(spans);
970
1155
  if (rows.length === 0) return null;
971
1156
  const { minStartMs, totalMs } = traceWindow(rows);
972
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
973
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
1157
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
1158
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
974
1159
  "Trace (",
975
1160
  rows.length,
976
1161
  " span",
@@ -979,11 +1164,11 @@ function ReportTrace({ spans }) {
979
1164
  formatDuration(totalMs),
980
1165
  ")"
981
1166
  ] }),
982
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
1167
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
983
1168
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
984
1169
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
985
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex items-center gap-2", children: [
986
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1170
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("li", { className: "flex items-center gap-2", children: [
1171
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
987
1172
  "span",
988
1173
  {
989
1174
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -992,14 +1177,14 @@ function ReportTrace({ spans }) {
992
1177
  children: row.name
993
1178
  }
994
1179
  ),
995
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1180
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
996
1181
  "span",
997
1182
  {
998
1183
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
999
1184
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
1000
1185
  }
1001
1186
  ) }),
1002
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
1187
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
1003
1188
  ] }, `${row.spanId}-${i}`);
1004
1189
  }) })
1005
1190
  ] });
@@ -1050,7 +1235,7 @@ function flakinessOf(entries) {
1050
1235
  }
1051
1236
 
1052
1237
  // src/components/ScenarioRunHistory.tsx
1053
- var import_jsx_runtime22 = require("react/jsx-runtime");
1238
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1054
1239
  var MAX_DOTS = 10;
1055
1240
  var DOT_COLOR = {
1056
1241
  passed: "bg-pass",
@@ -1070,16 +1255,16 @@ function ScenarioRunHistory({ scenarioId }) {
1070
1255
  const recent = entries.slice(-MAX_DOTS);
1071
1256
  const flaky = flakinessOf(recent) === "flaky";
1072
1257
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
1073
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
1074
- flaky ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
1075
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1258
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
1259
+ flaky ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
1260
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1076
1261
  "span",
1077
1262
  {
1078
1263
  role: "img",
1079
1264
  "aria-label": `Run history: ${summary}`,
1080
1265
  title: summary,
1081
1266
  className: "flex shrink-0 items-center gap-[3px]",
1082
- children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1267
+ children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1083
1268
  "span",
1084
1269
  {
1085
1270
  "aria-hidden": true,
@@ -1118,9 +1303,9 @@ function useScenarioActions() {
1118
1303
 
1119
1304
  // src/components/ui/card.tsx
1120
1305
  var React2 = require("react");
1121
- var import_jsx_runtime23 = require("react/jsx-runtime");
1306
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1122
1307
  function Card({ className, ...props }) {
1123
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1308
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1124
1309
  "div",
1125
1310
  {
1126
1311
  "data-slot": "card",
@@ -1133,7 +1318,7 @@ function Card({ className, ...props }) {
1133
1318
  );
1134
1319
  }
1135
1320
  function CardHeader({ className, ...props }) {
1136
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1321
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1137
1322
  "div",
1138
1323
  {
1139
1324
  "data-slot": "card-header",
@@ -1146,7 +1331,7 @@ function CardHeader({ className, ...props }) {
1146
1331
  );
1147
1332
  }
1148
1333
  function CardContent({ className, ...props }) {
1149
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1334
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1150
1335
  "div",
1151
1336
  {
1152
1337
  "data-slot": "card-content",
@@ -1160,13 +1345,13 @@ function CardContent({ className, ...props }) {
1160
1345
  var React3 = require("react");
1161
1346
  var import_menu = require("@base-ui/react/menu");
1162
1347
  var import_lucide_react = require("lucide-react");
1163
- var import_jsx_runtime24 = require("react/jsx-runtime");
1348
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1164
1349
  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";
1165
1350
  function DropdownMenu(props) {
1166
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
1351
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
1167
1352
  }
1168
1353
  function DropdownMenuTrigger(props) {
1169
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1170
1355
  }
1171
1356
  function DropdownMenuContent({
1172
1357
  className,
@@ -1174,14 +1359,14 @@ function DropdownMenuContent({
1174
1359
  sideOffset = 4,
1175
1360
  ...props
1176
1361
  }) {
1177
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1362
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1178
1363
  import_menu.Menu.Positioner,
1179
1364
  {
1180
1365
  "data-slot": "dropdown-menu-positioner",
1181
1366
  className: "z-50",
1182
1367
  align,
1183
1368
  sideOffset,
1184
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1369
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1185
1370
  import_menu.Menu.Popup,
1186
1371
  {
1187
1372
  "data-slot": "dropdown-menu-content",
@@ -1199,7 +1384,7 @@ function DropdownMenuItem({
1199
1384
  className,
1200
1385
  ...props
1201
1386
  }) {
1202
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1387
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1203
1388
  import_menu.Menu.Item,
1204
1389
  {
1205
1390
  "data-slot": "dropdown-menu-item",
@@ -1211,7 +1396,7 @@ function DropdownMenuItem({
1211
1396
 
1212
1397
  // src/components/ReportScenario.tsx
1213
1398
  var import_lucide_react2 = require("lucide-react");
1214
- var import_jsx_runtime25 = require("react/jsx-runtime");
1399
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1215
1400
  var STATUS_META = {
1216
1401
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
1217
1402
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -1227,7 +1412,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
1227
1412
  const collapsible = collapse !== null && !hideTitle;
1228
1413
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
1229
1414
  const actions = useScenarioActions();
1230
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1415
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1231
1416
  Card,
1232
1417
  {
1233
1418
  id: scenario.id,
@@ -1235,10 +1420,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
1235
1420
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
1236
1421
  className: "gap-0 py-0",
1237
1422
  children: [
1238
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardHeader, { className: "px-4 py-3", children: [
1239
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1240
- hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1241
- collapsible ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1423
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(CardHeader, { className: "px-4 py-3", children: [
1424
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1425
+ hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1426
+ collapsible ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1242
1427
  "button",
1243
1428
  {
1244
1429
  type: "button",
@@ -1247,49 +1432,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
1247
1432
  "aria-controls": bodyId,
1248
1433
  "aria-label": `Toggle ${scenario.title}`,
1249
1434
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1250
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1435
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1251
1436
  }
1252
1437
  ) : null,
1253
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1254
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: scenario.title })
1438
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: scenario.title })
1255
1440
  ] }),
1256
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1257
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1258
- scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1259
- meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1260
- actions ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenu, { children: [
1261
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1441
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1442
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1443
+ scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1444
+ meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1445
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenu, { children: [
1446
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1262
1447
  DropdownMenuTrigger,
1263
1448
  {
1264
1449
  "aria-label": `Actions for ${scenario.title}`,
1265
1450
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1266
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1451
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1267
1452
  }
1268
1453
  ),
1269
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuContent, { align: "end", children: [
1270
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1271
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.LinkIcon, {}),
1454
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuContent, { align: "end", children: [
1455
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1456
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.LinkIcon, {}),
1272
1457
  " Copy link"
1273
1458
  ] }),
1274
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1275
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.FileTextIcon, {}),
1459
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1460
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.FileTextIcon, {}),
1276
1461
  " Copy as Markdown"
1277
1462
  ] }),
1278
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1279
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.SparklesIcon, {}),
1463
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1464
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.SparklesIcon, {}),
1280
1465
  " Explain with AI"
1281
1466
  ] })
1282
1467
  ] })
1283
1468
  ] }) : null
1284
1469
  ] })
1285
1470
  ] }),
1286
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1287
- scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1288
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1471
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1472
+ scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1473
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1289
1474
  ] }) : null
1290
1475
  ] }),
1291
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1292
- scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1476
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1477
+ scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1293
1478
  "pre",
1294
1479
  {
1295
1480
  role: "alert",
@@ -1297,11 +1482,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
1297
1482
  children: scenario.errorMessage
1298
1483
  }
1299
1484
  ) : null,
1300
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportStoryboard, { scenario }),
1301
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportSteps, { scenario }),
1302
- scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1303
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1304
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportTrace, { spans: scenario.otelSpans })
1485
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportStoryboard, { scenario }),
1486
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportSteps, { scenario }),
1487
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1488
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1489
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportTrace, { spans: scenario.otelSpans })
1305
1490
  ] })
1306
1491
  ]
1307
1492
  }
@@ -1309,13 +1494,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1309
1494
  }
1310
1495
 
1311
1496
  // src/components/ReportScenarioList.tsx
1312
- var import_jsx_runtime26 = require("react/jsx-runtime");
1497
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1313
1498
  function ReportScenarioList({ feature }) {
1314
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenario, { scenario }, scenario.id)) });
1499
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_jsx_runtime27.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenario, { scenario }, scenario.id)) });
1315
1500
  }
1316
1501
 
1317
1502
  // src/components/ReportFeature.tsx
1318
- var import_jsx_runtime27 = require("react/jsx-runtime");
1503
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1319
1504
  function ReportFeature({ feature }) {
1320
1505
  const titleId = `${feature.id}-title`;
1321
1506
  const bodyId = `${feature.id}-body`;
@@ -1326,7 +1511,7 @@ function ReportFeature({ feature }) {
1326
1511
  return (
1327
1512
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1328
1513
  // layer of nesting so the scenario cards below read as the primary unit.
1329
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1514
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1330
1515
  "section",
1331
1516
  {
1332
1517
  id: feature.id,
@@ -1334,9 +1519,9 @@ function ReportFeature({ feature }) {
1334
1519
  "aria-labelledby": titleId,
1335
1520
  className: "flex flex-col gap-3",
1336
1521
  children: [
1337
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1338
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "min-w-0", children: [
1339
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1522
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1523
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "min-w-0", children: [
1524
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1340
1525
  "button",
1341
1526
  {
1342
1527
  type: "button",
@@ -1345,31 +1530,31 @@ function ReportFeature({ feature }) {
1345
1530
  "aria-controls": bodyId,
1346
1531
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1347
1532
  children: [
1348
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1349
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: feature.title })
1533
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1534
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate", children: feature.title })
1350
1535
  ]
1351
1536
  }
1352
1537
  ) : feature.title }),
1353
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1538
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1354
1539
  ] }),
1355
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1540
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1356
1541
  "p",
1357
1542
  {
1358
1543
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1359
1544
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1360
1545
  children: [
1361
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
1546
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
1362
1547
  s.passed,
1363
1548
  " passed"
1364
1549
  ] }),
1365
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1366
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1550
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1551
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1367
1552
  s.failed,
1368
1553
  " failed"
1369
1554
  ] }),
1370
- skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
1371
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1372
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
1555
+ skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
1556
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1557
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
1373
1558
  skipped,
1374
1559
  " skipped"
1375
1560
  ] })
@@ -1378,7 +1563,7 @@ function ReportFeature({ feature }) {
1378
1563
  }
1379
1564
  )
1380
1565
  ] }),
1381
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenarioList, { feature }) })
1566
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportScenarioList, { feature }) })
1382
1567
  ]
1383
1568
  }
1384
1569
  )
@@ -1386,17 +1571,17 @@ function ReportFeature({ feature }) {
1386
1571
  }
1387
1572
 
1388
1573
  // src/components/ReportFeatureList.tsx
1389
- var import_jsx_runtime28 = require("react/jsx-runtime");
1574
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1390
1575
  function ReportFeatureList() {
1391
1576
  const report = useReport();
1392
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportFeature, { feature }, feature.id)) });
1577
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ReportFeature, { feature }, feature.id)) });
1393
1578
  }
1394
1579
 
1395
1580
  // src/components/ui/empty.tsx
1396
1581
  var import_class_variance_authority2 = require("class-variance-authority");
1397
- var import_jsx_runtime29 = require("react/jsx-runtime");
1582
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1398
1583
  function Empty({ className, ...props }) {
1399
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1584
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1400
1585
  "div",
1401
1586
  {
1402
1587
  "data-slot": "empty",
@@ -1409,7 +1594,7 @@ function Empty({ className, ...props }) {
1409
1594
  );
1410
1595
  }
1411
1596
  function EmptyHeader({ className, ...props }) {
1412
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1597
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1413
1598
  "div",
1414
1599
  {
1415
1600
  "data-slot": "empty-header",
@@ -1436,7 +1621,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
1436
1621
  }
1437
1622
  );
1438
1623
  function EmptyTitle({ className, ...props }) {
1439
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1624
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1440
1625
  "div",
1441
1626
  {
1442
1627
  "data-slot": "empty-title",
@@ -1447,16 +1632,16 @@ function EmptyTitle({ className, ...props }) {
1447
1632
  }
1448
1633
 
1449
1634
  // src/components/ReportEmpty.tsx
1450
- var import_jsx_runtime30 = require("react/jsx-runtime");
1635
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1451
1636
  function ReportEmpty({ message }) {
1452
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1637
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1453
1638
  }
1454
1639
 
1455
1640
  // src/components/ReportSummary.tsx
1456
- var import_jsx_runtime31 = require("react/jsx-runtime");
1641
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1457
1642
  function ReportSummary({ className }) {
1458
1643
  const report = useReport();
1459
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1644
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1460
1645
  ReportSummaryView,
1461
1646
  {
1462
1647
  summary: report.summary,
@@ -1482,7 +1667,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1482
1667
  if (summary.pending > 0) {
1483
1668
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1484
1669
  }
1485
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1670
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1486
1671
  "dl",
1487
1672
  {
1488
1673
  className: cn(
@@ -1495,17 +1680,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1495
1680
  "aria-label": ariaLabel,
1496
1681
  children: cards.map((c) => {
1497
1682
  const tone = TONE[c.status];
1498
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1683
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
1499
1684
  "div",
1500
1685
  {
1501
1686
  "data-status": c.status,
1502
1687
  className: "rounded-lg border bg-card px-4 py-3",
1503
1688
  children: [
1504
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1505
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1689
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1690
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1506
1691
  c.label
1507
1692
  ] }),
1508
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1693
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1509
1694
  ]
1510
1695
  },
1511
1696
  c.status
@@ -1565,7 +1750,7 @@ function prUrl(ci) {
1565
1750
  }
1566
1751
 
1567
1752
  // src/components/ReportMeta.tsx
1568
- var import_jsx_runtime32 = require("react/jsx-runtime");
1753
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1569
1754
  function ReportMeta() {
1570
1755
  const report = useReport();
1571
1756
  const items = [];
@@ -1588,13 +1773,13 @@ function ReportMeta() {
1588
1773
  const short = sha.slice(0, 8);
1589
1774
  items.push({
1590
1775
  label: "Commit",
1591
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1776
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1592
1777
  });
1593
1778
  }
1594
1779
  if (report.ci) {
1595
1780
  items.push({
1596
1781
  label: "CI",
1597
- value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1782
+ value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1598
1783
  ciDisplayName(report.ci.name),
1599
1784
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1600
1785
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1605,7 +1790,7 @@ function ReportMeta() {
1605
1790
  const label = `#${report.ci.prNumber}`;
1606
1791
  items.push({
1607
1792
  label: "PR",
1608
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1793
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1609
1794
  });
1610
1795
  }
1611
1796
  if (items.length === 0) return null;
@@ -1613,48 +1798,48 @@ function ReportMeta() {
1613
1798
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1614
1799
  // collapsed disclosure so it doesn't push the result down. Native <details>
1615
1800
  // so it works with no JS (the SSR/no-hydration report still toggles).
1616
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1617
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1618
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1801
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1802
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1803
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1619
1804
  "Run details"
1620
1805
  ] }),
1621
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1622
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dt", { className: "font-medium", children: item.label }),
1623
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1806
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1807
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dt", { className: "font-medium", children: item.label }),
1808
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1624
1809
  ] }, item.label)) })
1625
1810
  ] })
1626
1811
  );
1627
1812
  }
1628
1813
 
1629
1814
  // src/components/ReportSchemaError.tsx
1630
- var import_jsx_runtime33 = require("react/jsx-runtime");
1815
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1631
1816
  function ReportSchemaError({ error }) {
1632
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1633
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "Report could not be displayed." }) }),
1634
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: error.message }),
1635
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { children: [
1817
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1818
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("strong", { children: "Report could not be displayed." }) }),
1819
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: error.message }),
1820
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { children: [
1636
1821
  "The report bundle is newer than this version of ",
1637
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("code", { children: "executable-stories-react" }),
1822
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("code", { children: "executable-stories-react" }),
1638
1823
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1639
1824
  ] }) : null,
1640
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { children: [
1641
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("summary", { children: [
1825
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("details", { children: [
1826
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("summary", { children: [
1642
1827
  error.issues.length,
1643
1828
  " validation issue",
1644
1829
  error.issues.length === 1 ? "" : "s"
1645
1830
  ] }),
1646
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1831
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1647
1832
  ] }) : null
1648
1833
  ] });
1649
1834
  }
1650
1835
 
1651
1836
  // src/components/ReportShell.tsx
1652
- var import_jsx_runtime34 = require("react/jsx-runtime");
1837
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1653
1838
  function ReportTitleBlock({ title }) {
1654
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
1655
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { children: title ?? "Story Report" }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSummary, {}),
1657
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportMeta, {})
1839
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
1840
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { children: title ?? "Story Report" }),
1841
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportSummary, {}),
1842
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportMeta, {})
1658
1843
  ] });
1659
1844
  }
1660
1845
  function ReportErrorShell({
@@ -1663,28 +1848,28 @@ function ReportErrorShell({
1663
1848
  title,
1664
1849
  dataTheme
1665
1850
  }) {
1666
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSchemaError, { error }) });
1851
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportSchemaError, { error }) });
1667
1852
  }
1668
1853
 
1669
1854
  // src/components/Report.tsx
1670
- var import_jsx_runtime35 = require("react/jsx-runtime");
1855
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1671
1856
  function Report(props) {
1672
1857
  const { report, customRenderers, renderers, className, title, dataTheme } = props;
1673
1858
  const result = unwrapReport(report);
1674
1859
  if (!result.ok) {
1675
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1860
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
1676
1861
  }
1677
1862
  const data = result.data;
1678
1863
  const hasContent = data.features.length > 0;
1679
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1680
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportTitleBlock, { title }) }),
1681
- hasContent ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportEmpty, {})
1864
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
1865
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportTitleBlock, { title }) }),
1866
+ hasContent ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportEmpty, {})
1682
1867
  ] }) });
1683
1868
  }
1684
1869
 
1685
1870
  // src/components/doc/MermaidView.tsx
1686
1871
  var import_react8 = require("react");
1687
- var import_jsx_runtime36 = require("react/jsx-runtime");
1872
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1688
1873
  function prefersDark(el) {
1689
1874
  const themed = el?.closest("[data-theme]");
1690
1875
  if (themed?.dataset.theme === "dark") return true;
@@ -1694,21 +1879,38 @@ function prefersDark(el) {
1694
1879
  function MermaidView({ entry, load }) {
1695
1880
  const ref = (0, import_react8.useRef)(null);
1696
1881
  const [svg, setSvg] = (0, import_react8.useState)(null);
1882
+ const [error, setError] = (0, import_react8.useState)(null);
1697
1883
  (0, import_react8.useEffect)(() => {
1698
1884
  let cancelled = false;
1699
1885
  const draw = async () => {
1886
+ let mermaid;
1887
+ try {
1888
+ mermaid = await load();
1889
+ } catch {
1890
+ if (!cancelled) {
1891
+ setSvg(null);
1892
+ setError(null);
1893
+ }
1894
+ return;
1895
+ }
1700
1896
  try {
1701
- const mermaid = await load();
1702
1897
  mermaid.initialize({
1703
1898
  startOnLoad: false,
1704
1899
  securityLevel: "strict",
1705
1900
  theme: prefersDark(ref.current) ? "dark" : "default"
1706
1901
  });
1902
+ await mermaid.parse(entry.code);
1707
1903
  const id = `es-mermaid-${Math.random().toString(36).slice(2)}`;
1708
1904
  const { svg: rendered } = await mermaid.render(id, entry.code);
1709
- if (!cancelled) setSvg(rendered);
1710
- } catch {
1711
- if (!cancelled) setSvg(null);
1905
+ if (!cancelled) {
1906
+ setSvg(rendered);
1907
+ setError(null);
1908
+ }
1909
+ } catch (err2) {
1910
+ if (!cancelled) {
1911
+ setSvg(null);
1912
+ setError(err2 instanceof Error ? err2.message : String(err2));
1913
+ }
1712
1914
  }
1713
1915
  };
1714
1916
  void draw();
@@ -1721,9 +1923,9 @@ function MermaidView({ entry, load }) {
1721
1923
  };
1722
1924
  }, [entry.code, load]);
1723
1925
  if (svg) {
1724
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("figure", { ref, className: "my-3", children: [
1725
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1726
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1926
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("figure", { ref, className: "my-3", children: [
1927
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
1928
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1727
1929
  "div",
1728
1930
  {
1729
1931
  role: "img",
@@ -1734,18 +1936,32 @@ function MermaidView({ entry, load }) {
1734
1936
  )
1735
1937
  ] });
1736
1938
  }
1737
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MermaidSource, { entry, ref });
1939
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
1940
+ error ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1941
+ "p",
1942
+ {
1943
+ role: "alert",
1944
+ "data-es-mermaid-error": true,
1945
+ className: "mt-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
1946
+ children: [
1947
+ "Diagram failed to render: ",
1948
+ error
1949
+ ]
1950
+ }
1951
+ ) : null,
1952
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MermaidSource, { entry, ref })
1953
+ ] });
1738
1954
  }
1739
1955
 
1740
1956
  // src/components/doc/MermaidDiagram.tsx
1741
- var import_jsx_runtime37 = require("react/jsx-runtime");
1957
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1742
1958
  var mermaidLoader;
1743
1959
  function loadMermaid() {
1744
1960
  mermaidLoader ??= import("mermaid").then((m) => m.default);
1745
1961
  return mermaidLoader;
1746
1962
  }
1747
1963
  function MermaidDiagram({ entry, load = loadMermaid }) {
1748
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MermaidView, { entry, load });
1964
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MermaidView, { entry, load });
1749
1965
  }
1750
1966
 
1751
1967
  // src/components/ScenarioExplorer.tsx
@@ -1755,12 +1971,12 @@ var import_react9 = require("react");
1755
1971
  var React4 = require("react");
1756
1972
  var import_cmdk = require("cmdk");
1757
1973
  var import_lucide_react3 = require("lucide-react");
1758
- var import_jsx_runtime38 = require("react/jsx-runtime");
1974
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1759
1975
  function Command({
1760
1976
  className,
1761
1977
  ...props
1762
1978
  }) {
1763
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1979
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1764
1980
  import_cmdk.Command,
1765
1981
  {
1766
1982
  "data-slot": "command",
@@ -1776,14 +1992,14 @@ function CommandInput({
1776
1992
  className,
1777
1993
  ...props
1778
1994
  }) {
1779
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
1995
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
1780
1996
  "div",
1781
1997
  {
1782
1998
  "data-slot": "command-input-wrapper",
1783
1999
  className: "flex h-9 items-center gap-2 border-b px-3",
1784
2000
  children: [
1785
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1786
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2001
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
2002
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1787
2003
  import_cmdk.Command.Input,
1788
2004
  {
1789
2005
  "data-slot": "command-input",
@@ -1802,7 +2018,7 @@ function CommandList({
1802
2018
  className,
1803
2019
  ...props
1804
2020
  }) {
1805
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2021
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1806
2022
  import_cmdk.Command.List,
1807
2023
  {
1808
2024
  "data-slot": "command-list",
@@ -1817,7 +2033,7 @@ function CommandList({
1817
2033
  function CommandEmpty({
1818
2034
  ...props
1819
2035
  }) {
1820
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2036
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1821
2037
  import_cmdk.Command.Empty,
1822
2038
  {
1823
2039
  "data-slot": "command-empty",
@@ -1830,7 +2046,7 @@ function CommandGroup({
1830
2046
  className,
1831
2047
  ...props
1832
2048
  }) {
1833
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2049
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1834
2050
  import_cmdk.Command.Group,
1835
2051
  {
1836
2052
  "data-slot": "command-group",
@@ -1846,7 +2062,7 @@ function CommandItem({
1846
2062
  className,
1847
2063
  ...props
1848
2064
  }) {
1849
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2065
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1850
2066
  import_cmdk.Command.Item,
1851
2067
  {
1852
2068
  "data-slot": "command-item",
@@ -1860,7 +2076,7 @@ function CommandItem({
1860
2076
  }
1861
2077
 
1862
2078
  // src/components/ScenarioExplorer.tsx
1863
- var import_jsx_runtime39 = require("react/jsx-runtime");
2079
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1864
2080
  var STATUS_FILTERS = [
1865
2081
  { value: "all", label: "All" },
1866
2082
  { value: "passed", label: "Passed" },
@@ -1871,22 +2087,22 @@ var STATUS_FILTERS = [
1871
2087
  function ScenarioExplorer({ scenarios, summary }) {
1872
2088
  const [status, setStatus] = (0, import_react9.useState)("all");
1873
2089
  const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
1874
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "font-sans text-foreground", children: [
1875
- summary ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
2090
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "font-sans text-foreground", children: [
2091
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
1876
2092
  summary.total,
1877
2093
  " scenarios \xB7 ",
1878
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-pass", children: [
2094
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "text-pass", children: [
1879
2095
  summary.passed,
1880
2096
  " passed"
1881
2097
  ] }),
1882
2098
  " \xB7",
1883
2099
  " ",
1884
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-fail", children: [
2100
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "text-fail", children: [
1885
2101
  summary.failed,
1886
2102
  " failed"
1887
2103
  ] })
1888
2104
  ] }) : null,
1889
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2105
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
1890
2106
  "button",
1891
2107
  {
1892
2108
  type: "button",
@@ -1901,26 +2117,26 @@ function ScenarioExplorer({ scenarios, summary }) {
1901
2117
  },
1902
2118
  f.value
1903
2119
  )) }),
1904
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
2120
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
1905
2121
  Command,
1906
2122
  {
1907
2123
  className: "rounded-lg border border-border bg-card",
1908
2124
  filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
1909
2125
  children: [
1910
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
1911
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(CommandList, { className: "max-h-none", children: [
1912
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
1913
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2126
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
2127
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(CommandList, { className: "max-h-none", children: [
2128
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
2129
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
1914
2130
  CommandItem,
1915
2131
  {
1916
2132
  value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
1917
2133
  asChild: true,
1918
2134
  className: "cursor-pointer",
1919
- children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
1920
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: s.status, children: s.status }),
1921
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
1922
- s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
1923
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
2135
+ children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
2136
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { variant: s.status, children: s.status }),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
2138
+ s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
2139
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
1924
2140
  ] })
1925
2141
  },
1926
2142
  s.id
@@ -2943,6 +3159,8 @@ function parseStoryReport(input) {
2943
3159
  }
2944
3160
  // Annotate the CommonJS export names for ESM import in node:
2945
3161
  0 && (module.exports = {
3162
+ DATA_MODEL_TYPE,
3163
+ DataModelBlock,
2946
3164
  DocCode,
2947
3165
  DocCustom,
2948
3166
  DocEntry,
@@ -2956,6 +3174,8 @@ function parseStoryReport(input) {
2956
3174
  DocTable,
2957
3175
  DocTag,
2958
3176
  DocVideo,
3177
+ FILE_TREE_TYPE,
3178
+ FileTreeBlock,
2959
3179
  MermaidDiagram,
2960
3180
  MermaidSource,
2961
3181
  Report,
@@ -2985,7 +3205,10 @@ function parseStoryReport(input) {
2985
3205
  err,
2986
3206
  formatRelativeAge,
2987
3207
  isReportStale,
3208
+ narrativeBlockRenderers,
2988
3209
  ok,
3210
+ parseDataModel,
3211
+ parseFileTree,
2989
3212
  parseStoryReport,
2990
3213
  prUrl,
2991
3214
  reportLastRunMs,