executable-stories-react 0.2.1 → 0.3.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 +344 -151
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +295 -9
- package/dist/index.d.ts +295 -9
- package/dist/index.js +328 -144
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +532 -238
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +269 -2
- package/dist/interactive.d.ts +269 -2
- package/dist/interactive.js +493 -200
- package/dist/interactive.js.map +1 -1
- package/dist/parse.cjs +4 -0
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +225 -3
- package/dist/parse.d.ts +225 -3
- package/dist/parse.js +4 -0
- package/dist/parse.js.map +1 -1
- package/dist/report-island.global.js +32 -32
- package/dist/ssr.cjs +274 -117
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +250 -2
- package/dist/ssr.d.ts +250 -2
- package/dist/ssr.js +271 -114
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +26 -0
- package/dist/tailwind.css +1 -1
- package/package.json +4 -4
package/dist/ssr.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ssr-entry.ts","../src/result.ts","../src/context/ReportRoot.tsx","../src/context/ReportContext.ts","../src/hooks/useReport.ts","../src/components/ReportScenario.tsx","../src/components/ReportSteps.tsx","../src/components/doc/DocNote.tsx","../src/components/ui/badge.tsx","../src/lib/utils.ts","../src/components/doc/DocTag.tsx","../src/components/doc/DocKv.tsx","../src/hooks/useRenderers.ts","../src/components/doc/DocCode.tsx","../src/components/doc/DocTable.tsx","../src/components/doc/DocLink.tsx","../src/components/doc/DocSection.tsx","../src/lib/url.ts","../src/components/doc/DocMermaid.tsx","../src/components/doc/DocScreenshot.tsx","../src/components/doc/DocVideo.tsx","../src/components/doc/DocHtml.tsx","../src/components/doc/DocCustom.tsx","../src/components/doc/DocEntry.tsx","../src/components/ReportDocEntries.tsx","../src/lib/step-params.tsx","../src/components/ReportAttachments.tsx","../src/components/ReportTrace.tsx","../src/lib/trace.ts","../src/interactive/collapse-context.ts","../src/interactive/scenario-actions.tsx","../src/components/ui/card.tsx","../src/components/ReportScenarioList.tsx","../src/components/ReportFeature.tsx","../src/components/ReportFeatureList.tsx","../src/components/ui/empty.tsx","../src/components/ReportEmpty.tsx","../src/components/ReportSummary.tsx","../src/components/ReportMeta.tsx","../src/components/ReportSchemaError.tsx","../src/components/ReportShell.tsx","../src/components/Report.tsx"],"sourcesContent":["/**\n * Server-only entry: render a StoryReport to a standalone HTML document string.\n *\n * This is the single rendering path shared by the CLI's standalone `.html`\n * output and (later) the Astro docs site — both render the same <Report/>\n * component tree, so there is no second renderer to drift from.\n *\n * No fs, no client code. The caller supplies the stylesheet text (read once\n * from `executable-stories-react/tailwind.css`) so this module stays pure and\n * bundler-agnostic. The interactive hydration island is injected via\n * `bodyExtra` in a later phase; this entry renders static markup only.\n */\n\nimport { createElement } from \"react\";\nimport { renderToStaticMarkup } from \"react-dom/server\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"./result\";\nimport { unwrapReport } from \"./result\";\nimport { Report } from \"./components/Report\";\n\nexport interface RenderReportToHtmlOptions {\n /** Document <title> and the report's <h1>. */\n title?: string;\n /** Stylesheet text inlined into <head> (e.g. executable-stories-react/tailwind.css). */\n css?: string;\n /** Force a theme; defaults to \"light\" (CSS still honours prefers-color-scheme). */\n theme?: \"light\" | \"dark\";\n /** Raw HTML injected at the end of <head> (font links, CDN module scripts). */\n headExtra?: string;\n /** Raw HTML injected before </body> (the hydration island <script>, later phases). */\n bodyExtra?: string;\n /** Document language attribute. */\n lang?: string;\n /** Load highlight.js to colour code blocks (default true). */\n syntaxHighlighting?: boolean;\n /** Load mermaid to render `pre[data-mermaid]` diagrams (default true). */\n mermaid?: boolean;\n /**\n * When set, embed the report JSON + this inlined IIFE bundle text\n * (executable-stories-react/report-island.js) so the static markup is\n * upgraded to the interactive tree on load. The static render stays as the\n * no-JS fallback.\n */\n islandScript?: string;\n}\n\nconst ROOT_ID = \"es-report-root\";\nconst DATA_ID = \"es-report-data\";\n\n/** Escape a JSON string for safe embedding inside a <script> element. */\nfunction escapeJsonForScript(json: string): string {\n return json.replace(/[<\\u2028\\u2029]/g, (c) => \"\\\\u\" + c.charCodeAt(0).toString(16).padStart(4, \"0\"));\n}\n\nconst HLJS_URL = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js\";\nconst HLJS_CSS_LIGHT = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css\";\nconst HLJS_CSS_DARK = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\";\nconst MERMAID_URL = \"https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs\";\n\n/** Build the CDN <head> styles + the bottom-of-body init module script. */\nfunction cdnAssets(syntaxHighlighting: boolean, mermaid: boolean): { head: string; body: string } {\n const headParts: string[] = [];\n const imports: string[] = [];\n const init: string[] = [];\n\n if (syntaxHighlighting) {\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_LIGHT}\">`);\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_DARK}\" media=\"(prefers-color-scheme: dark)\">`);\n imports.push(`import hljs from \"${HLJS_URL}\";`);\n init.push(\"document.querySelectorAll('pre code').forEach((el) => hljs.highlightElement(el));\");\n }\n if (mermaid) {\n imports.push(`import mermaid from \"${MERMAID_URL}\";`);\n init.push(\"mermaid.initialize({ startOnLoad: false, theme: 'neutral' });\");\n init.push('await mermaid.run({ querySelector: \"pre[data-mermaid]\" });');\n }\n\n const body = imports.length\n ? `<script type=\"module\">\\n${imports.join(\"\\n\")}\\n${init.join(\"\\n\")}\\n</script>`\n : \"\";\n return { head: headParts.join(\"\\n\"), body };\n}\n\nconst HTML_ESCAPES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n};\n\nfunction escapeHtml(value: string): string {\n return value.replace(/[&<>\"']/g, (ch) => HTML_ESCAPES[ch] ?? ch);\n}\n\n/**\n * Render a StoryReport (or a parse Result) to a complete, self-contained HTML\n * document. The report markup is wrapped in `.es-report-island` so the scoped\n * Tailwind/shadcn resets and utilities apply without leaking onto a host page.\n */\nexport function renderReportToHtml(\n report: StoryReport | Result<StoryReport>,\n options: RenderReportToHtmlOptions = {},\n): string {\n const {\n title = \"Story Report\",\n css = \"\",\n theme = \"light\",\n headExtra = \"\",\n bodyExtra = \"\",\n lang = \"en\",\n syntaxHighlighting = true,\n mermaid = true,\n islandScript = \"\",\n } = options;\n\n const markup = renderToStaticMarkup(\n createElement(Report, { report, title }),\n );\n\n const cdn = cdnAssets(syntaxHighlighting, mermaid);\n\n // Interactive island: embed the report JSON + the inlined IIFE so the static\n // markup is upgraded to <ReportInteractive> on load (static = no-JS fallback).\n // <Report> already normalizes the same input internally; we re-normalize here\n // only to recover the bare report for the JSON payload.\n const parsed = unwrapReport(report);\n const rawReport: StoryReport | undefined = parsed.ok ? parsed.data : undefined;\n const interactive = islandScript.length > 0 && rawReport !== undefined;\n const dataScript = interactive\n ? `<script type=\"application/json\" id=\"${DATA_ID}\">${escapeJsonForScript(JSON.stringify(rawReport))}</script>`\n : \"\";\n const islandTag = interactive ? `<script>${islandScript}</script>` : \"\";\n // When interactive, the React island OWNS the doc-entry DOM via createRoot.\n // Highlighting + mermaid therefore render inside the React tree (the island\n // reads these flags and wires the matching renderers); the CDN post-processor\n // module (cdn.body) would race the client takeover and is dropped. The hljs\n // stylesheet (cdn.head) is still required to colour the React-owned tokens.\n const cdnBody = interactive ? \"\" : cdn.body;\n const islandConfigAttrs = interactive\n ? ` data-es-syntax=\"${syntaxHighlighting ? \"true\" : \"false\"}\" data-es-mermaid=\"${mermaid ? \"true\" : \"false\"}\"`\n : \"\";\n const rootAttrs = interactive\n ? ` id=\"${ROOT_ID}\" data-title=\"${escapeHtml(title)}\"${islandConfigAttrs}`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"${escapeHtml(lang)}\" data-theme=\"${theme === \"dark\" ? \"dark\" : \"light\"}\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"color-scheme\" content=\"light dark\">\n<title>${escapeHtml(title)}</title>\n${cdn.head}\n${headExtra}\n<style>${css}</style>\n</head>\n<body>\n<div${rootAttrs} class=\"es-report-island font-sans text-foreground\">${markup}</div>\n${dataScript}\n${bodyExtra}\n${cdnBody}\n${islandTag}\n</body>\n</html>`;\n}\n","/**\n * Result<T> — explicit success/error type matching the cookbook convention.\n *\n * Used at the boundary where a StoryReport is parsed: the consumer hands us\n * an unknown value (file contents, fetch body, prop) and we return a Result.\n */\nimport type { StoryReport } from \"executable-stories-core\";\n\nexport type Result<T, E = ReportParseError> =\n | { ok: true; data: T }\n | { ok: false; error: E };\n\nexport interface ReportParseError {\n message: string;\n code: ReportParseErrorCode;\n issues?: readonly { path: string; message: string }[];\n}\n\nexport type ReportParseErrorCode =\n | \"INVALID_INPUT\"\n | \"SCHEMA_VERSION_MISMATCH\"\n | \"VALIDATION_FAILED\";\n\nexport const ok = <T>(data: T): Result<T> => ({ ok: true, data });\nexport const err = (error: ReportParseError): Result<never> => ({ ok: false, error });\n\n/**\n * Normalize the `StoryReport | Result<StoryReport>` prop accepted across the\n * render entrypoints (`Report`, `ReportInteractive`, `renderReportToHtml`) into\n * a single `Result`. A bare report becomes `ok(report)`; an already-wrapped\n * value passes through. One place owns the \"is this a Result?\" discrimination.\n */\nexport function unwrapReport(value: StoryReport | Result<StoryReport>): Result<StoryReport> {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"ok\" in value &&\n typeof (value as { ok: unknown }).ok === \"boolean\"\n ) {\n return value as Result<StoryReport>;\n }\n return ok(value as StoryReport);\n}\n","import { useMemo, type ReactNode } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportContext, type ReportContextValue } from \"./ReportContext\";\n\nexport interface ReportRootProps {\n report: StoryReport;\n customRenderers?: CustomRenderers;\n renderers?: BuiltinRenderers;\n children: ReactNode;\n}\n\nconst EMPTY_CUSTOM: CustomRenderers = {};\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function ReportRoot({\n report,\n customRenderers,\n renderers,\n children,\n}: ReportRootProps) {\n const value = useMemo<ReportContextValue>(\n () => ({\n report,\n customRenderers: customRenderers ?? EMPTY_CUSTOM,\n renderers: renderers ?? EMPTY_RENDERERS,\n }),\n [report, customRenderers, renderers],\n );\n return <ReportContext.Provider value={value}>{children}</ReportContext.Provider>;\n}\n","import { createContext } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nexport interface ReportContextValue {\n report: StoryReport;\n customRenderers: CustomRenderers;\n renderers: BuiltinRenderers;\n}\n\nexport const ReportContext = createContext<ReportContextValue | null>(null);\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\n\nexport function useReport() {\n const ctx = useContext(ReportContext);\n if (!ctx) {\n throw new Error(\n \"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those.\",\n );\n }\n return ctx.report;\n}\n","import type { ReportScenario as ReportScenarioT } from \"executable-stories-core\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { ReportSteps } from \"./ReportSteps\";\nimport { ReportDocEntries } from \"./ReportDocEntries\";\nimport { ReportAttachments } from \"./ReportAttachments\";\nimport { ReportTrace } from \"./ReportTrace\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { useScenarioActions } from \"../interactive/scenario-actions\";\nimport { Card, CardContent, CardHeader } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportScenarioProps {\n scenario: ReportScenarioT;\n /**\n * Omit the card's own title row (status badge + tags still render). Use when\n * the surrounding page already shows the scenario title as its heading — e.g.\n * the Astro detail page, where Starlight renders the title as the page `h1`.\n */\n hideTitle?: boolean;\n}\n\ntype Status = ReportScenarioT[\"status\"];\n\nconst STATUS_LABEL: Record<Status, string> = {\n passed: \"Passed\",\n failed: \"Failed\",\n skipped: \"Skipped\",\n pending: \"Pending\",\n};\n\nconst STATUS_GLYPH: Record<Status, string> = {\n passed: \"✓\",\n failed: \"✗\",\n skipped: \"○\",\n pending: \"○\",\n};\n\nconst STATUS_GLYPH_COLOR: Record<Status, string> = {\n passed: \"text-pass\",\n failed: \"text-fail\",\n skipped: \"text-skip\",\n pending: \"text-pend\",\n};\n\nconst STATUS_BADGE: Record<Status, \"passed\" | \"failed\" | \"skipped\" | \"pending\"> = {\n passed: \"passed\",\n failed: \"failed\",\n skipped: \"skipped\",\n pending: \"pending\",\n};\n\nexport function ReportScenario({ scenario, hideTitle = false }: ReportScenarioProps) {\n const titleId = `${scenario.id}-title`;\n const bodyId = `${scenario.id}-body`;\n const label = STATUS_LABEL[scenario.status];\n const collapse = useCollapse();\n const collapsible = collapse !== null && !hideTitle;\n const collapsed = collapsible ? collapse!.isCollapsed(scenario.id) : false;\n const actions = useScenarioActions();\n return (\n <Card\n id={scenario.id}\n data-status={scenario.status}\n {...(hideTitle\n ? { \"aria-label\": `${scenario.title} — ${label}` }\n : { \"aria-labelledby\": titleId })}\n className=\"gap-0 py-0\"\n >\n <CardHeader className=\"px-4 py-3\">\n <div className={cn(\"flex items-start gap-4\", hideTitle ? \"justify-end\" : \"justify-between\")}>\n {hideTitle ? null : (\n <h3 id={titleId} className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n {collapsible ? (\n <button\n type=\"button\"\n onClick={() => collapse!.toggle(scenario.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n aria-label={`Toggle ${scenario.title}`}\n className=\"shrink-0 cursor-pointer text-muted-foreground hover:text-foreground\"\n >\n <span aria-hidden className={cn(\"inline-block text-xs transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n </button>\n ) : null}\n <span aria-hidden className={cn(\"text-sm leading-none\", STATUS_GLYPH_COLOR[scenario.status])}>\n {STATUS_GLYPH[scenario.status]}\n </span>\n <span>{scenario.title}</span>\n </h3>\n )}\n <div className=\"flex shrink-0 items-center gap-2\">\n {scenario.durationMs > 0 ? (\n <span className=\"whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(scenario.durationMs)}\n </span>\n ) : null}\n <Badge variant={STATUS_BADGE[scenario.status]} aria-label={`Status: ${label}`}>\n {label}\n </Badge>\n {actions ? (\n <div className=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n onClick={() => actions.copyLink(scenario)}\n aria-label={`Copy link to ${scenario.title}`}\n title=\"Copy permalink\"\n className=\"cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n link\n </button>\n <button\n type=\"button\"\n onClick={() => actions.copyMarkdown(scenario)}\n aria-label={`Copy ${scenario.title} as Markdown`}\n title=\"Copy as Markdown\"\n className=\"cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n md\n </button>\n <button\n type=\"button\"\n onClick={() => actions.copyPrompt(scenario)}\n aria-label={`Copy ${scenario.title} as an AI investigation prompt`}\n title=\"Copy as AI prompt\"\n className=\"cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n ai\n </button>\n </div>\n ) : null}\n </div>\n </div>\n {scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? (\n <ul aria-label=\"Tags and tickets\" className=\"flex flex-wrap gap-1.5\">\n {scenario.tags.map((t) => (\n <li key={`tag-${t}`}>\n <Badge variant=\"tag\">{t}</Badge>\n </li>\n ))}\n {(scenario.tickets ?? []).map((ticket) => (\n <li key={`ticket-${ticket.id}`}>\n {ticket.url ? (\n <a href={ticket.url} target=\"_blank\" rel=\"noreferrer noopener\">\n <Badge variant=\"outline\">{ticket.id}</Badge>\n </a>\n ) : (\n <Badge variant=\"outline\">{ticket.id}</Badge>\n )}\n </li>\n ))}\n </ul>\n ) : null}\n </CardHeader>\n <CardContent id={bodyId} hidden={collapsed} className=\"px-4 pt-0 pb-4\">\n {scenario.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mb-1 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {scenario.errorMessage}\n </pre>\n ) : null}\n <ReportSteps scenario={scenario} />\n {scenario.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-3\">\n <ReportDocEntries entries={scenario.docEntries} />\n </div>\n ) : null}\n <ReportAttachments attachments={scenario.attachments} />\n <ReportTrace spans={scenario.otelSpans} />\n </CardContent>\n </Card>\n );\n}\n","import type { ReportStep, ReportScenario } from \"executable-stories-core\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { ReportDocEntries } from \"./ReportDocEntries\";\nimport { highlightStepParams } from \"@/lib/step-params\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportStepsProps {\n scenario: ReportScenario;\n}\n\nconst STEP_GLYPH: Record<string, string> = {\n passed: \"✓\",\n failed: \"✗\",\n skipped: \"○\",\n pending: \"○\",\n};\n\nconst STEP_GLYPH_COLOR: Record<string, string> = {\n passed: \"text-pass\",\n failed: \"text-fail\",\n skipped: \"text-skip\",\n pending: \"text-pend\",\n};\n\nexport function ReportSteps({ scenario }: ReportStepsProps) {\n if (scenario.steps.length === 0) return null;\n return (\n <ol data-slot=\"steps\" className=\"flex flex-col\">\n {scenario.steps.map((step) => (\n <ReportStepItem key={step.id} step={step} />\n ))}\n </ol>\n );\n}\n\nexport function ReportStepItem({ step }: { step: ReportStep }) {\n // And/But (incl. auto-And repeats) read as continuations of the prior step —\n // indented with a muted keyword, matching the report's `.step.continuation`.\n const kw = step.keyword.toLowerCase();\n const continuation = kw === \"and\" || kw === \"but\";\n return (\n <li\n id={step.id}\n data-status={step.status}\n className={cn(\"py-1.5 text-[0.8125rem] leading-normal\", continuation && \"pl-5\")}\n >\n <div className=\"flex items-baseline gap-2\">\n <span aria-hidden className={cn(\"w-4 shrink-0 text-center text-xs\", STEP_GLYPH_COLOR[step.status])}>\n {STEP_GLYPH[step.status] ?? \"○\"}\n </span>\n <span\n className={cn(\n \"min-w-[52px] shrink-0 font-mono text-xs font-semibold capitalize\",\n continuation ? \"font-medium text-muted-foreground\" : \"text-keyword\",\n )}\n >\n {step.keyword}\n </span>\n <span className=\"flex-1 text-foreground\">{highlightStepParams(step.text)}</span>\n {step.durationMs > 0 ? (\n <span className=\"shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(step.durationMs)}\n </span>\n ) : null}\n </div>\n {step.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mt-2.5 ml-6 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {step.errorMessage}\n </pre>\n ) : null}\n {step.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-2 ml-6\">\n <ReportDocEntries entries={step.docEntries} />\n </div>\n ) : null}\n </li>\n );\n}\n","import type { ReportDocNote } from \"executable-stories-core\";\n\nexport function DocNote({ entry }: { entry: ReportDocNote }) {\n return <p className=\"my-2 text-sm text-muted-foreground\">{entry.text}</p>;\n}\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { useRender } from \"@base-ui/react/use-render\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst badgeVariants = cva(\n \"inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90\",\n outline:\n \"border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n ghost: \"[a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 [a&]:hover:underline\",\n passed: \"border-pass-border bg-pass-bg text-pass font-mono uppercase\",\n failed: \"border-fail-border bg-fail-bg text-fail font-mono uppercase\",\n skipped: \"border-skip-border bg-skip-bg text-skip font-mono uppercase\",\n pending: \"border-pend-border bg-pend-bg text-pend font-mono uppercase\",\n tag: \"border-pass-border bg-pass-bg text-pass font-mono font-medium\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n render,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & {\n // Base UI composition: pass `render={<a … />}` to swap the underlying tag —\n // replaces Radix's `asChild`. See rules/base-vs-radix.md.\n render?: useRender.RenderProp\n }) {\n return useRender({\n defaultTagName: \"span\",\n render,\n props: {\n \"data-slot\": \"badge\",\n \"data-variant\": variant,\n className: cn(badgeVariants({ variant }), className),\n ...props,\n },\n })\n}\n\nexport { Badge, badgeVariants }\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merge class names with Tailwind-aware conflict resolution (shadcn `cn`). */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import type { ReportDocTag } from \"executable-stories-core\";\nimport { Badge } from \"@/components/ui/badge\";\n\nexport function DocTag({ entry }: { entry: ReportDocTag }) {\n return (\n <ul className=\"my-2 flex flex-wrap gap-1.5\" aria-label=\"Tags\">\n {entry.names.map((n) => (\n <li key={n}>\n <Badge variant=\"tag\">{n}</Badge>\n </li>\n ))}\n </ul>\n );\n}\n","import type { ReportDocKv } from \"executable-stories-core\";\n\nfunction formatValue(value: unknown): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport function DocKv({ entry }: { entry: ReportDocKv }) {\n return (\n <dl className=\"my-2 flex flex-wrap items-baseline gap-x-2 text-sm\">\n <dt className=\"font-semibold text-muted-foreground\">{entry.label}</dt>\n <dd className=\"font-mono text-foreground\">{formatValue(entry.value)}</dd>\n </dl>\n );\n}\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nconst EMPTY_CUSTOM: CustomRenderers = {};\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function useCustomRenderers(): CustomRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.customRenderers ?? EMPTY_CUSTOM;\n}\n\nexport function useBuiltinRenderers(): BuiltinRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.renderers ?? EMPTY_RENDERERS;\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportDocCode } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Shared shell for code blocks: optional label + the scrollable `<pre>`. Both\n * the static `DocCode` and the island's CDN-highlighted variant render their\n * `<code>` into this so the two can never drift in spacing or chrome.\n */\nexport function CodeFigure({ label, children }: { label?: string; children: ReactNode }) {\n return (\n <figure className=\"my-3\">\n {label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{label}</figcaption>\n ) : null}\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3\">\n {children}\n </pre>\n </figure>\n );\n}\n\nexport function DocCode({ entry }: { entry: ReportDocCode }) {\n const renderers = useBuiltinRenderers();\n if (renderers.code) {\n return <>{renderers.code(entry)}</>;\n }\n return (\n <CodeFigure label={entry.label}>\n <code className={cn(\"font-mono text-xs\", entry.lang && `language-${entry.lang}`)}>\n {entry.content}\n </code>\n </CodeFigure>\n );\n}\n","import type { ReportDocTable } from \"executable-stories-core\";\n\nexport function DocTable({ entry }: { entry: ReportDocTable }) {\n return (\n <figure className=\"my-3\">\n {entry.label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">\n {entry.label}\n </figcaption>\n ) : null}\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-muted/50\">\n {entry.columns.map((c) => (\n <th key={c} scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n {c}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {entry.rows.map((row, i) => (\n <tr key={i}>\n {row.map((cell, j) => (\n <td key={j} className=\"border-b border-border px-3 py-2 text-foreground\">\n {cell}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </figure>\n );\n}\n","import type { ReportDocLink } from \"executable-stories-core\";\n\nexport function DocLink({ entry }: { entry: ReportDocLink }) {\n return (\n <a\n className=\"text-sm font-medium text-primary underline underline-offset-2 hover:no-underline\"\n href={entry.url}\n rel=\"noreferrer noopener\"\n target=\"_blank\"\n >\n {entry.label}\n </a>\n );\n}\n","import { marked } from \"marked\";\nimport type { ReportDocSection } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { safeUrl } from \"../../lib/url\";\n\n/**\n * Best-effort sanitizer for marked-generated HTML. `section` markdown is\n * authored in the test source (developer-trusted), so this is defense-in-depth,\n * not a hard boundary against hostile input. It:\n * - drops <script>/<style> and other active elements (iframe/object/embed/form)\n * - strips on* event-handler attributes\n * - neutralizes any non-http(s) scheme on href/src via the shared `safeUrl`\n * allow-list (covers javascript:/data:/vbscript:/file:, not just javascript:)\n *\n * It is NOT a substitute for a full HTML sanitizer (it won't catch entity-\n * obfuscated schemes). For untrusted markdown, supply `renderers.section` with\n * your own sanitizer.\n */\nfunction neutralizeUrl(value: string): string {\n return safeUrl(value) ?? \"#\";\n}\n\nfunction safeMarkdownHtml(markdown: string): string {\n const raw = marked.parse(markdown, { async: false }) as string;\n return raw\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, \"\")\n .replace(/<\\/?(?:iframe|object|embed|form|base)\\b[^>]*>/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*\"[^\"]*\"/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*'[^']*'/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*[^\\s>]+/gi, \"\")\n .replace(/(href|src)\\s*=\\s*\"([^\"]*)\"/gi, (_m, attr, val) => `${attr}=\"${neutralizeUrl(val)}\"`)\n .replace(/(href|src)\\s*=\\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);\n}\n\nexport function DocSection({ entry }: { entry: ReportDocSection }) {\n const renderers = useBuiltinRenderers();\n if (renderers.section) {\n return <>{renderers.section(entry)}</>;\n }\n const html = safeMarkdownHtml(entry.markdown);\n return (\n <section className=\"my-3 text-sm\" aria-label={entry.title}>\n {entry.title ? <h4 className=\"mb-1 font-semibold text-foreground\">{entry.title}</h4> : null}\n <div\n className=\"es-doc-prose text-muted-foreground\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n </section>\n );\n}\n","/**\n * A URL is safe to put in the DOM (href/src/poster) only if it's relative (no\n * scheme) or uses http/https. Anything with another scheme — notably\n * `javascript:` (which runs in the page context), plus `data:` / `vbscript:` /\n * `file:` — is rejected. Report JSON carries adapter-supplied URLs, so every\n * report-sourced URL that reaches the DOM is treated as untrusted and passed\n * through here (DocHtml iframe src, DocVideo src/poster, …).\n */\nexport function safeUrl(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);\n if (scheme && !/^https?$/i.test(scheme[1] ?? \"\")) return undefined;\n return trimmed;\n}\n\n/**\n * Same trust boundary as safeUrl(), but for `<img src>`: also allows\n * `data:image/*` URIs, since that's how executable-stories-playwright's\n * story.screenshot() inlines a captured screenshot (see\n * inlineScreenshotIfPossible in that package). Browsers sandbox SVG rendered\n * via `<img>` — no script execution, no external resource loads — so\n * `data:image/svg+xml` is safe here even though data: URIs are rejected for\n * iframe/video src.\n */\nexport function safeImageUrl(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (/^data:image\\//i.test(trimmed)) return trimmed;\n return safeUrl(trimmed);\n}\n\n/**\n * True for POSIX absolute paths (`/foo`, `\\foo`) and Windows drive-letter\n * paths (`C:\\foo`) — i.e. a local filesystem path rather than a URL. Report\n * assets are bundled (copied + rewritten to a relative `assets/...` path) at\n * format time when the source file can be found; a path that's still\n * absolute by the time it reaches the DOM means that bundling step couldn't\n * find the file — rendering it as `<img src>`/`<video src>` would 404 (or\n * silently resolve nothing) since it points at a path on the machine that\n * generated the report, not at the browser's origin.\n */\nexport function isLocalFsPath(value: string): boolean {\n return /^(?:[/\\\\]|[A-Za-z]:[/\\\\])/.test(value);\n}\n","import type { Ref } from \"react\";\nimport type { ReportDocMermaid } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\n\n/**\n * The raw mermaid source as a semantic `<pre data-mermaid>`. This is the\n * default render and the universal fallback: AI agents, screen readers, and\n * no-JS views all get the readable source. `<MermaidDiagram>` upgrades this to\n * a drawn diagram on the client.\n */\nexport function MermaidSource({ entry, ref }: { entry: ReportDocMermaid; ref?: Ref<HTMLElement> }) {\n return (\n <figure ref={ref} className=\"my-3\" aria-label={entry.title ?? \"Diagram\"}>\n {entry.title ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{entry.title}</figcaption>\n ) : null}\n <pre\n data-mermaid\n tabIndex={0}\n className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\"\n >\n {entry.code}\n </pre>\n </figure>\n );\n}\n\n/**\n * Renders mermaid source as a semantic `<pre data-mermaid>` by default.\n *\n * To draw the diagram, supply a `renderers.mermaid` prop — e.g. the shipped\n * `MermaidDiagram` (`renderers={{ mermaid: (e) => <MermaidDiagram entry={e} /> }}`).\n */\nexport function DocMermaid({ entry }: { entry: ReportDocMermaid }) {\n const renderers = useBuiltinRenderers();\n if (renderers.mermaid) {\n return <>{renderers.mermaid(entry)}</>;\n }\n return <MermaidSource entry={entry} />;\n}\n","import type { ReportDocScreenshot } from \"executable-stories-core\";\nimport { isLocalFsPath, safeImageUrl } from \"../../lib/url\";\n\n/**\n * A screenshot that's still an absolute local filesystem path by the time it\n * reaches this component means the report's asset bundler couldn't find the\n * file to inline/copy it (deleted, moved, or never captured — see\n * inlineScreenshotIfPossible in executable-stories-playwright). `<img src>`\n * would 404 against a path from the machine that generated the report, so\n * show a placeholder instead of a broken image.\n */\nexport function DocScreenshot({ entry }: { entry: ReportDocScreenshot }) {\n const src = isLocalFsPath(entry.path) ? undefined : safeImageUrl(entry.path);\n\n if (!src) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Screenshot unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs\">{entry.alt}</figcaption> : null}\n </figure>\n );\n }\n\n return (\n <figure className=\"my-3\">\n <img\n src={src}\n alt={entry.alt ?? \"\"}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs text-muted-foreground\">{entry.alt}</figcaption> : null}\n </figure>\n );\n}\n","import type { ReportDocVideo } from \"executable-stories-core\";\nimport { isLocalFsPath, safeUrl } from \"../../lib/url\";\n\n/**\n * Renders a video doc entry. Video bytes are large and never inlined; `path` is\n * a URL or a path that resolves alongside the report. Both `path` and `poster`\n * are adapter-supplied, so they go through the same scheme allow-list as the\n * DocHtml iframe src (no `javascript:`/`data:` URLs reach the DOM).\n *\n * An absolute local filesystem path means the report's asset bundler\n * couldn't find/copy the file — a `<video src>` pointed at a runner-local\n * path would just fail to load, so show a placeholder instead.\n */\nexport function DocVideo({ entry }: { entry: ReportDocVideo }) {\n if (isLocalFsPath(entry.path)) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Video unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.caption ? <figcaption className=\"mt-1.5 text-xs\">{entry.caption}</figcaption> : null}\n </figure>\n );\n }\n\n const src = safeUrl(entry.path);\n const poster = safeUrl(entry.poster);\n return (\n <figure className=\"my-3\">\n <video\n controls\n preload=\"metadata\"\n {...(src ? { src } : {})}\n {...(poster ? { poster } : {})}\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.caption ? (\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{entry.caption}</figcaption>\n ) : null}\n </figure>\n );\n}\n","import type { ReportDocHtml } from \"executable-stories-core\";\nimport { safeUrl } from \"../../lib/url\";\n\n/**\n * Renders an embedded-HTML doc entry inside a SANDBOXED iframe. All embedded\n * HTML is untrusted, so the frame is `sandbox=\"allow-scripts\"` only (no\n * allow-same-origin) — embedded scripts run (charts work) but can't touch the\n * report DOM, cookies, or storage. Inline `content` → srcdoc (keeps the report\n * self-contained); `url`/`path` → src (scheme-validated).\n */\nexport function DocHtml({ entry }: { entry: ReportDocHtml }) {\n const height = typeof entry.height === \"number\" ? `${entry.height}px` : (entry.height ?? \"400px\");\n const title = entry.title ?? \"Embedded HTML\";\n const safeHref = safeUrl(entry.url ?? entry.path);\n\n // Exactly one of content / url / path is set. A url/path with an unsafe\n // scheme yields no src (the figure still renders, just empty).\n const frameProps = entry.content !== undefined ? { srcDoc: entry.content } : { src: safeHref ?? \"\" };\n\n return (\n <figure className=\"my-3 overflow-hidden rounded-md border border-border\">\n <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\">\n <span>{entry.title ?? \"HTML\"}</span>\n {safeHref ? (\n <a\n href={safeHref}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n aria-label=\"Open in new tab\"\n title=\"Open in new tab\"\n className=\"text-primary\"\n >\n ↗\n </a>\n ) : null}\n </figcaption>\n <iframe\n {...frameProps}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n title={title}\n className=\"block w-full border-0\"\n style={{ height }}\n />\n </figure>\n );\n}\n","import type { ReportDocCustom } from \"executable-stories-core\";\nimport { useCustomRenderers } from \"../../hooks/useRenderers\";\n\nexport function DocCustom({ entry }: { entry: ReportDocCustom }) {\n const renderers = useCustomRenderers();\n const renderer = renderers[entry.type];\n if (renderer) {\n return <>{renderer(entry)}</>;\n }\n return (\n <div className=\"my-2\" data-type={entry.type}>\n <p className=\"mb-1 text-xs font-medium text-muted-foreground\">{entry.type}</p>\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\">\n {safeStringify(entry.data)}\n </pre>\n </div>\n );\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocNote } from \"./DocNote\";\nimport { DocTag } from \"./DocTag\";\nimport { DocKv } from \"./DocKv\";\nimport { DocCode } from \"./DocCode\";\nimport { DocTable } from \"./DocTable\";\nimport { DocLink } from \"./DocLink\";\nimport { DocSection } from \"./DocSection\";\nimport { DocMermaid } from \"./DocMermaid\";\nimport { DocScreenshot } from \"./DocScreenshot\";\nimport { DocVideo } from \"./DocVideo\";\nimport { DocHtml } from \"./DocHtml\";\nimport { DocCustom } from \"./DocCustom\";\n\nexport function DocEntry({ entry }: { entry: ReportDocEntry }) {\n switch (entry.kind) {\n case \"note\":\n return <DocNote entry={entry} />;\n case \"tag\":\n return <DocTag entry={entry} />;\n case \"kv\":\n return <DocKv entry={entry} />;\n case \"code\":\n return <DocCode entry={entry} />;\n case \"table\":\n return <DocTable entry={entry} />;\n case \"link\":\n return <DocLink entry={entry} />;\n case \"section\":\n return <DocSection entry={entry} />;\n case \"mermaid\":\n return <DocMermaid entry={entry} />;\n case \"screenshot\":\n return <DocScreenshot entry={entry} />;\n case \"video\":\n return <DocVideo entry={entry} />;\n case \"html\":\n return <DocHtml entry={entry} />;\n case \"custom\":\n return <DocCustom entry={entry} />;\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocEntry } from \"./doc/DocEntry\";\n\nexport interface ReportDocEntriesProps {\n entries: readonly ReportDocEntry[];\n}\n\nexport function ReportDocEntries({ entries }: ReportDocEntriesProps) {\n if (entries.length === 0) return null;\n return (\n <>\n {entries.map((entry, i) => (\n <DocEntry key={i} entry={entry} />\n ))}\n </>\n );\n}\n","import type { ReactNode } from \"react\";\n\n/**\n * Highlight step parameters (double-quoted strings, standalone numbers) in step\n * text — the React equivalent of the report's highlightStepParams. Returns a\n * node array so the matched params can be wrapped in a styled <span> without\n * dangerouslySetInnerHTML.\n *\n * Regex mirrors the string renderer exactly:\n * - `\"[^\"]*\"` double-quoted strings (numbers inside quotes stay part of the string)\n * - `(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])` standalone numbers, dot/word-boundary aware\n */\nconst STEP_PARAM_PATTERN = /\"[^\"]*\"|(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])/g;\n\nexport function highlightStepParams(text: string): ReactNode {\n const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));\n if (matches.length === 0) return text;\n\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n matches.forEach((match, i) => {\n const start = match.index;\n const end = start + match[0].length;\n if (start > lastIndex) nodes.push(text.slice(lastIndex, start));\n nodes.push(\n <span key={i} className=\"font-medium text-step-param italic\">\n {match[0]}\n </span>,\n );\n lastIndex = end;\n });\n if (lastIndex < text.length) nodes.push(text.slice(lastIndex));\n return nodes;\n}\n","import type { ReportAttachment } from \"executable-stories-core\";\n\n/**\n * Renders scenario attachments. Base64 images embed inline; everything else\n * becomes a labelled data-URI download link. Mirrors the report's attachments\n * block (which also inlines images and links other media).\n */\nexport function ReportAttachments({ attachments }: { attachments: ReportAttachment[] }) {\n if (attachments.length === 0) return null;\n return (\n // role=\"group\" (not a labelled <section>) so multiple scenarios' attachment\n // blocks don't create duplicate \"Attachments\" region landmarks.\n <div role=\"group\" aria-label=\"Attachments\" className=\"mt-3 flex flex-col gap-2\">\n {attachments.map((att, i) => {\n const dataUri =\n att.contentEncoding === \"BASE64\"\n ? `data:${att.mediaType};base64,${att.body}`\n : `data:${att.mediaType},${encodeURIComponent(att.body)}`;\n const isImage = att.mediaType.startsWith(\"image/\");\n return (\n <figure key={`${att.name}-${i}`} className=\"m-0\">\n {isImage ? (\n <>\n <img\n src={dataUri}\n alt={att.name}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{att.name}</figcaption>\n </>\n ) : (\n <a\n href={dataUri}\n download={att.name}\n className=\"text-xs text-link underline underline-offset-2\"\n >\n {att.name} <span className=\"text-muted-foreground\">({att.mediaType})</span>\n </a>\n )}\n </figure>\n );\n })}\n </div>\n );\n}\n","import type { OtelSpan } from \"executable-stories-core/types/otel\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { toTraceRows, traceWindow } from \"@/lib/trace\";\nimport { cn } from \"@/lib/utils\";\n\nconst BAR_COLOR: Record<string, string> = {\n ok: \"bg-pass\",\n error: \"bg-fail\",\n unset: \"bg-skip\",\n};\n\n/**\n * OTel trace waterfall. Collapsed by default (native <details>, no JS) so it\n * renders in both the static and interactive reports. Each span is a row with a\n * depth-indented name and a bar positioned/sized by its time window.\n */\nexport function ReportTrace({ spans }: { spans: readonly OtelSpan[] | undefined }) {\n if (!spans || spans.length === 0) return null;\n const rows = toTraceRows(spans);\n if (rows.length === 0) return null;\n const { minStartMs, totalMs } = traceWindow(rows);\n\n return (\n <details className=\"mt-3 rounded-md border border-border bg-muted/30\">\n <summary className=\"cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground\">\n Trace ({rows.length} span{rows.length === 1 ? \"\" : \"s\"}, {formatDuration(totalMs)})\n </summary>\n <ul className=\"flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]\">\n {rows.map((row, i) => {\n const leftPct = ((row.startTimeMs - minStartMs) / totalMs) * 100;\n const widthPct = Math.max((row.durationMs / totalMs) * 100, 0.5);\n return (\n <li key={`${row.spanId}-${i}`} className=\"flex items-center gap-2\">\n <span\n className=\"min-w-0 flex-1 truncate text-foreground\"\n style={{ paddingLeft: `${row.depth * 12}px` }}\n title={row.statusMessage ? `${row.name} — ${row.statusMessage}` : row.name}\n >\n {row.name}\n </span>\n <span className=\"relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40\">\n <span\n className={cn(\"absolute top-0 h-full rounded-sm\", BAR_COLOR[row.status])}\n style={{ left: `${leftPct}%`, width: `${widthPct}%` }}\n />\n </span>\n <span className=\"w-16 shrink-0 text-right text-muted-foreground\">\n {formatDuration(row.durationMs)}\n </span>\n </li>\n );\n })}\n </ul>\n </details>\n );\n}\n","/**\n * Pure span normalization + tree building for the OTel trace waterfall.\n * Ported from the formatters trace-view renderer so the React waterfall shows\n * the same structure. Side-effect-free for unit testing.\n */\n\nimport type { OtelSpan } from \"executable-stories-core/types/otel\";\n\nexport interface NormalizedSpan {\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeMs: number;\n durationMs: number;\n status: \"ok\" | \"error\" | \"unset\";\n statusMessage?: string;\n}\n\nexport interface TraceRow extends NormalizedSpan {\n depth: number;\n}\n\nconst VALID = new Set([\"ok\", \"error\", \"unset\"]);\nconst safeStatus = (s: string): NormalizedSpan[\"status\"] => (VALID.has(s) ? (s as NormalizedSpan[\"status\"]) : \"unset\");\n\nexport function normalizeSpans(spans: readonly OtelSpan[]): NormalizedSpan[] {\n const out: NormalizedSpan[] = [];\n for (const span of spans) {\n if (!span || typeof span.spanId !== \"string\" || typeof span.name !== \"string\") continue;\n let startTimeMs: number;\n let durationMs: number;\n if (span.startTimeMs != null && span.durationMs != null) {\n startTimeMs = span.startTimeMs;\n durationMs = span.durationMs;\n } else if (span.startTimeUnixNano != null && span.endTimeUnixNano != null) {\n startTimeMs = span.startTimeUnixNano / 1e6;\n durationMs = (span.endTimeUnixNano - span.startTimeUnixNano) / 1e6;\n } else {\n continue;\n }\n durationMs = Math.max(0, durationMs);\n if (!isFinite(startTimeMs) || !isFinite(durationMs)) continue;\n out.push({\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n startTimeMs,\n durationMs,\n status: safeStatus(span.status),\n statusMessage: span.statusMessage,\n });\n }\n return out;\n}\n\n/** Flatten spans into rows in tree order with a depth, parent before children. */\nexport function toTraceRows(spans: readonly OtelSpan[]): TraceRow[] {\n const normalized = normalizeSpans(spans);\n if (normalized.length === 0) return [];\n\n interface Node {\n span: NormalizedSpan;\n children: Node[];\n depth: number;\n }\n const byId = new Map<string, Node>();\n for (const span of normalized) {\n let key = span.spanId;\n let suffix = 2;\n while (byId.has(key)) key = `${span.spanId}__dup${suffix++}`;\n byId.set(key, { span: { ...span, spanId: key }, children: [], depth: 0 });\n }\n\n const roots: Node[] = [];\n for (const node of byId.values()) {\n const parent = node.span.parentSpanId ? byId.get(node.span.parentSpanId) : undefined;\n if (parent && parent !== node) parent.children.push(node);\n else roots.push(node);\n }\n for (const node of byId.values()) node.children.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n\n const rows: TraceRow[] = [];\n const seen = new Set<string>();\n const walk = (node: Node, depth: number): void => {\n if (seen.has(node.span.spanId)) return;\n seen.add(node.span.spanId);\n rows.push({ ...node.span, depth });\n for (const child of node.children) walk(child, depth + 1);\n };\n for (const root of roots) walk(root, 0);\n // Orphans from cycles: promote to depth 0.\n for (const node of byId.values()) {\n if (!seen.has(node.span.spanId)) walk(node, 0);\n }\n return rows;\n}\n\nexport interface TraceWindow {\n minStartMs: number;\n totalMs: number;\n}\n\nexport function traceWindow(rows: readonly TraceRow[]): TraceWindow {\n let min = Infinity;\n let max = -Infinity;\n for (const r of rows) {\n min = Math.min(min, r.startTimeMs);\n max = Math.max(max, r.startTimeMs + r.durationMs);\n }\n const total = max - min;\n return { minStartMs: isFinite(min) ? min : 0, totalMs: total > 0 ? total : 1 };\n}\n","\"use client\";\n\nimport { createContext, useCallback, useContext, useState } from \"react\";\n\nexport interface CollapseApi {\n isCollapsed: (id: string) => boolean;\n toggle: (id: string) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (the static <Report/>\n * render, Storybook, Astro), components render fully expanded with no toggle\n * affordance — so the static path and component-tier tests are unaffected.\n */\nconst CollapseContext = createContext<CollapseApi | null>(null);\n\nexport const CollapseProvider = CollapseContext.Provider;\n\nexport function useCollapse(): CollapseApi | null {\n return useContext(CollapseContext);\n}\n\nconst STORAGE_KEY = \"es-collapsed-ids\";\n\nfunction readPersisted(): Set<string> {\n if (typeof localStorage === \"undefined\") return new Set();\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n return raw ? new Set(JSON.parse(raw) as string[]) : new Set();\n } catch {\n return new Set();\n }\n}\n\nfunction persist(ids: Set<string>): void {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify([...ids]));\n } catch {\n /* quota / disabled — collapse still works for the session */\n }\n}\n\n/**\n * Collapse state for the interactive report: a persisted set of collapsed\n * feature/scenario ids, plus expand-all / collapse-all.\n */\nexport function useCollapseState() {\n const [collapsed, setCollapsed] = useState<Set<string>>(readPersisted);\n\n const isCollapsed = useCallback((id: string) => collapsed.has(id), [collapsed]);\n\n const toggle = useCallback((id: string) => {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n persist(next);\n return next;\n });\n }, []);\n\n const collapseAll = useCallback((ids: string[]) => {\n setCollapsed(() => {\n const next = new Set(ids);\n persist(next);\n return next;\n });\n }, []);\n\n const expandAll = useCallback(() => {\n setCollapsed(() => {\n const next = new Set<string>();\n persist(next);\n return next;\n });\n }, []);\n\n return { api: { isCollapsed, toggle } as CollapseApi, collapseAll, expandAll };\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { ReportScenario } from \"executable-stories-core\";\n\nexport interface ScenarioActions {\n copyLink: (scenario: ReportScenario) => void;\n copyMarkdown: (scenario: ReportScenario) => void;\n copyPrompt: (scenario: ReportScenario) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (static render), scenarios\n * show no per-scenario action buttons.\n */\nconst ScenarioActionsContext = createContext<ScenarioActions | null>(null);\nexport const ScenarioActionsProvider = ScenarioActionsContext.Provider;\nexport function useScenarioActions(): ScenarioActions | null {\n return useContext(ScenarioActionsContext);\n}\n\n/** A scenario rendered as Markdown — for pasting into PRs / issues / docs. */\nexport function scenarioToMarkdown(scenario: ReportScenario): string {\n const lines: string[] = [`## ${scenario.title} _(${scenario.status})_`, \"\"];\n for (const step of scenario.steps) {\n lines.push(`- **${step.keyword}** ${step.text}`);\n }\n if (scenario.errorMessage) {\n lines.push(\"\", \"```\", scenario.errorMessage.trim(), \"```\");\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * A failed scenario rendered as an investigation prompt for an AI agent — the\n * \"cheap to verify\" loop: hand the agent the failing behaviour + error verbatim.\n */\nexport function scenarioToPrompt(scenario: ReportScenario): string {\n const lines: string[] = [\n `A test scenario is ${scenario.status}. Investigate the likely cause and propose a fix.`,\n \"\",\n `Scenario: ${scenario.title}`,\n \"Steps:\",\n ];\n for (const step of scenario.steps) {\n const mark = step.status === \"failed\" ? \" ⟵ failed here\" : \"\";\n lines.push(` ${step.keyword} ${step.text}${mark}`);\n }\n if (scenario.errorMessage) {\n lines.push(\"\", \"Error:\", scenario.errorMessage.trim());\n }\n if (scenario.errorStack) {\n lines.push(\"\", \"Stack:\", scenario.errorStack.trim());\n }\n return lines.join(\"\\n\");\n}\n\n/** Absolute permalink to a scenario in the current document. */\nexport function scenarioPermalink(scenario: ReportScenario): string {\n if (typeof location === \"undefined\") return `#${scenario.id}`;\n return `${location.href.split(\"#\")[0]}#${scenario.id}`;\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card\"\n className={cn(\n \"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-6\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","import type { ReportFeature } from \"executable-stories-core\";\nimport { ReportScenario } from \"./ReportScenario\";\n\nexport interface ReportScenarioListProps {\n feature: ReportFeature;\n}\n\nexport function ReportScenarioList({ feature }: ReportScenarioListProps) {\n return (\n <>\n {feature.scenarios.map((scenario) => (\n <ReportScenario key={scenario.id} scenario={scenario} />\n ))}\n </>\n );\n}\n","import type { ReportFeature as ReportFeatureT } from \"executable-stories-core\";\nimport { ReportScenarioList } from \"./ReportScenarioList\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportFeatureProps {\n feature: ReportFeatureT;\n}\n\n/**\n * Feature group — the report's `.feature` card: a header bar with the feature\n * title + mono source path and ✓/✗/○ status counts on the right, over a stack\n * of scenario cards. Kept a semantic <section> (a region), not a shadcn Card\n * div, so it stays a landmark and doesn't collide with the scenario cards'\n * `[data-slot=\"card\"]`.\n */\nexport function ReportFeature({ feature }: ReportFeatureProps) {\n const titleId = `${feature.id}-title`;\n const bodyId = `${feature.id}-body`;\n const s = feature.summary;\n const skipped = s.skipped + s.pending;\n const collapse = useCollapse();\n const collapsed = collapse?.isCollapsed(feature.id) ?? false;\n return (\n <section\n id={feature.id}\n data-slot=\"feature\"\n aria-labelledby={titleId}\n className=\"overflow-hidden rounded-xl border border-border bg-card shadow-sm\"\n >\n <div className=\"flex items-center justify-between gap-4 border-b border-border bg-muted/40 px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n {collapse ? (\n <button\n type=\"button\"\n onClick={() => collapse.toggle(feature.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n aria-label={`Toggle ${feature.title}`}\n className=\"shrink-0 cursor-pointer text-muted-foreground hover:text-foreground\"\n >\n <span aria-hidden className={cn(\"inline-block text-xs transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n </button>\n ) : null}\n <div className=\"min-w-0\">\n <h2 id={titleId} className=\"text-sm font-semibold tracking-tight text-foreground\">\n {feature.title}\n </h2>\n <p className=\"mt-0.5 truncate font-mono text-xs text-muted-foreground\">{feature.sourceFile}</p>\n </div>\n </div>\n <div\n role=\"img\"\n className=\"flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium\"\n aria-label={`${s.passed} passed, ${s.failed} failed, ${skipped} skipped`}\n >\n <span aria-hidden className=\"text-pass\">✓{s.passed}</span>\n <span aria-hidden className=\"text-fail\">✗{s.failed}</span>\n <span aria-hidden className=\"text-skip\">○{skipped}</span>\n </div>\n </div>\n <div id={bodyId} hidden={collapsed} className=\"flex flex-col gap-2 p-3\">\n <ReportScenarioList feature={feature} />\n </div>\n </section>\n );\n}\n","import { useReport } from \"../hooks/useReport\";\nimport { ReportFeature } from \"./ReportFeature\";\n\nexport function ReportFeatureList() {\n const report = useReport();\n return (\n <>\n {report.features.map((feature) => (\n <ReportFeature key={feature.id} feature={feature} />\n ))}\n </>\n );\n}\n","import { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Empty({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty\"\n className={cn(\n \"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-header\"\n className={cn(\n \"flex max-w-sm flex-col items-center gap-2 text-center\",\n className\n )}\n {...props}\n />\n )\n}\n\nconst emptyMediaVariants = cva(\n \"mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction EmptyMedia({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof emptyMediaVariants>) {\n return (\n <div\n data-slot=\"empty-icon\"\n data-variant={variant}\n className={cn(emptyMediaVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\nfunction EmptyTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-title\"\n className={cn(\"text-lg font-medium tracking-tight\", className)}\n {...props}\n />\n )\n}\n\nfunction EmptyDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <div\n data-slot=\"empty-description\"\n className={cn(\n \"text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-content\"\n className={cn(\n \"flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Empty,\n EmptyHeader,\n EmptyTitle,\n EmptyDescription,\n EmptyContent,\n EmptyMedia,\n}\n","import { Empty, EmptyHeader, EmptyTitle } from \"@/components/ui/empty\";\n\nexport interface ReportEmptyProps {\n message?: string;\n}\n\nexport function ReportEmpty({ message }: ReportEmptyProps) {\n return (\n <Empty aria-live=\"polite\" className=\"border\">\n <EmptyHeader>\n <EmptyTitle>{message ?? \"No scenarios in this report.\"}</EmptyTitle>\n </EmptyHeader>\n </Empty>\n );\n}\n","import type { ReportSummary as ReportSummaryT } from \"executable-stories-core\";\nimport { useReport } from \"../hooks/useReport\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportSummaryProps {\n className?: string;\n}\n\nexport function ReportSummary({ className }: ReportSummaryProps) {\n const report = useReport();\n return (\n <ReportSummaryView\n summary={report.summary}\n {...(className !== undefined && { className })}\n ariaLabel=\"Run summary\"\n />\n );\n}\n\nexport interface ReportSummaryViewProps {\n summary: ReportSummaryT;\n className?: string;\n ariaLabel?: string;\n}\n\nexport function ReportSummaryView({ summary, className, ariaLabel }: ReportSummaryViewProps) {\n return (\n <p className={cn(\"text-sm text-muted-foreground\", className)} aria-label={ariaLabel}>\n <span>\n <strong className=\"font-semibold text-foreground\">{summary.total}</strong> scenario\n {summary.total === 1 ? \"\" : \"s\"}\n </span>\n {\" · \"}\n <span data-status=\"passed\" className=\"text-pass\">{summary.passed} passed</span>\n {\" · \"}\n <span data-status=\"failed\" className=\"text-fail\">{summary.failed} failed</span>\n {summary.skipped > 0 ? (\n <>\n {\" · \"}\n <span data-status=\"skipped\" className=\"text-skip\">{summary.skipped} skipped</span>\n </>\n ) : null}\n {summary.pending > 0 ? (\n <>\n {\" · \"}\n <span data-status=\"pending\" className=\"text-pend\">{summary.pending} pending</span>\n </>\n ) : null}\n </p>\n );\n}\n","import { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { useReport } from \"../hooks/useReport\";\n\n/**\n * Run metadata line (started, duration, version, git SHA, CI) — the React\n * equivalent of the report's `.meta-info` block. Reads the top-level StoryReport\n * fields from context.\n */\nexport function ReportMeta() {\n const report = useReport();\n\n const items: Array<{ label: string; value: React.ReactNode }> = [];\n\n if (report.startedAtMs) {\n items.push({ label: \"Started\", value: new Date(report.startedAtMs).toLocaleString() });\n }\n if (report.durationMs) {\n items.push({ label: \"Duration\", value: formatDuration(report.durationMs) });\n }\n if (report.packageVersion) {\n items.push({ label: \"Version\", value: report.packageVersion });\n }\n if (report.gitSha) {\n items.push({ label: \"Commit\", value: report.gitSha.slice(0, 8) });\n }\n if (report.ci) {\n items.push({\n label: \"CI\",\n value: report.ci.url ? (\n <a href={report.ci.url} target=\"_blank\" rel=\"noreferrer noopener\" className=\"text-primary underline underline-offset-2\">\n {report.ci.name}\n {report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}\n </a>\n ) : (\n `${report.ci.name}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}`\n ),\n });\n }\n\n if (items.length === 0) return null;\n\n return (\n <dl aria-label=\"Run metadata\" className=\"flex flex-wrap gap-x-6 gap-y-1 text-xs text-muted-foreground\">\n {items.map((item) => (\n <div key={item.label} className=\"flex gap-1.5\">\n <dt className=\"font-medium\">{item.label}</dt>\n <dd className=\"font-mono text-foreground\">{item.value}</dd>\n </div>\n ))}\n </dl>\n );\n}\n","import type { ReportParseError } from \"../result\";\n\nexport interface ReportSchemaErrorProps {\n error: ReportParseError;\n}\n\nexport function ReportSchemaError({ error }: ReportSchemaErrorProps) {\n return (\n <section className=\"es-schema-error\" role=\"alert\" aria-live=\"assertive\">\n <p>\n <strong>Report could not be displayed.</strong>\n </p>\n <p>{error.message}</p>\n {error.code === \"SCHEMA_VERSION_MISMATCH\" ? (\n <p>\n The report bundle is newer than this version of <code>executable-stories-react</code>.\n Upgrade the package, or regenerate the report with an older formatters CLI.\n </p>\n ) : null}\n {error.issues && error.issues.length > 0 ? (\n <details>\n <summary>{error.issues.length} validation issue{error.issues.length === 1 ? \"\" : \"s\"}</summary>\n <pre>\n {error.issues\n .slice(0, 20)\n .map((i) => `${i.path}: ${i.message}`)\n .join(\"\\n\")}\n </pre>\n </details>\n ) : null}\n </section>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportParseError } from \"../result\";\nimport { cn } from \"../lib/utils\";\nimport { ReportSummary } from \"./ReportSummary\";\nimport { ReportMeta } from \"./ReportMeta\";\nimport { ReportSchemaError } from \"./ReportSchemaError\";\n\n/**\n * The report's title block — `<h1>` + summary + meta. Shared by the static\n * `Report` header and the interactive `ReportInteractive` header so the two\n * views can't drift on the no-JS fallback.\n */\nexport function ReportTitleBlock({ title }: { title?: string }) {\n return (\n <>\n <h1>{title ?? \"Story Report\"}</h1>\n <ReportSummary />\n <ReportMeta />\n </>\n );\n}\n\n/**\n * The `<main>` landmark shown when the report failed to parse. Both entrypoints\n * render the identical shell on a `Result` error, so it lives here once.\n */\nexport function ReportErrorShell({\n error,\n className,\n title,\n dataTheme,\n}: {\n error: ReportParseError;\n className?: string;\n title?: string;\n dataTheme?: \"light\" | \"dark\";\n}): ReactNode {\n return (\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <ReportSchemaError error={error} />\n </main>\n );\n}\n","import type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"../result\";\nimport { unwrapReport } from \"../result\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportRoot } from \"../context/ReportRoot\";\nimport { ReportFeatureList } from \"./ReportFeatureList\";\nimport { ReportEmpty } from \"./ReportEmpty\";\nimport { ReportTitleBlock, ReportErrorShell } from \"./ReportShell\";\nimport { cn } from \"../lib/utils\";\n\nexport interface ReportProps {\n /** A StoryReport, or a Result-wrapped one (e.g., from parseStoryReport). */\n report: StoryReport | Result<StoryReport>;\n /** Renderers keyed by `story.custom({ type })` strings. */\n customRenderers?: CustomRenderers;\n /** Optional overrides for the heavy built-ins (mermaid, code, section). */\n renderers?: BuiltinRenderers;\n /** Optional class on the <main> landmark for layout positioning. */\n className?: string;\n /** Optional override title. */\n title?: string;\n /** Optional theme attribute scope. Use to force \"light\" or \"dark\". */\n dataTheme?: \"light\" | \"dark\";\n}\n\nexport function Report(props: ReportProps) {\n const { report, customRenderers, renderers, className, title, dataTheme } = props;\n const result = unwrapReport(report);\n if (!result.ok) {\n return <ReportErrorShell error={result.error} className={className} title={title} dataTheme={dataTheme} />;\n }\n const data = result.data;\n const hasContent = data.features.length > 0;\n return (\n <ReportRoot report={data} customRenderers={customRenderers} renderers={renderers}>\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <header className=\"es-report-header\">\n <ReportTitleBlock title={title} />\n </header>\n {hasContent ? <ReportFeatureList /> : <ReportEmpty />}\n </main>\n </ReportRoot>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_duration","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","EMPTY_CUSTOM","EMPTY_RENDERERS","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_duration","import_jsx_runtime","import_react","import_react","React","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_class_variance_authority","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_duration","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/ssr-entry.ts","../src/result.ts","../src/context/ReportRoot.tsx","../src/context/ReportContext.ts","../src/hooks/useReport.ts","../../executable-stories-core/src/utils/duration.ts","../src/components/doc/DocNote.tsx","../src/components/ui/badge.tsx","../src/lib/utils.ts","../src/components/doc/DocTag.tsx","../src/components/doc/DocKv.tsx","../src/hooks/useRenderers.ts","../src/components/doc/DocCode.tsx","../src/components/doc/DocTable.tsx","../src/components/doc/DocLink.tsx","../src/components/doc/DocSection.tsx","../src/lib/url.ts","../src/components/doc/DocMermaid.tsx","../src/components/doc/DocScreenshot.tsx","../src/components/doc/DocVideo.tsx","../src/components/doc/DocHtml.tsx","../src/components/doc/DocCustom.tsx","../src/components/doc/DocEntry.tsx","../src/components/ReportDocEntries.tsx","../src/lib/step-params.tsx","../src/components/ReportSteps.tsx","../src/components/ReportAttachments.tsx","../src/lib/trace.ts","../src/components/ReportTrace.tsx","../src/interactive/scenario-history-context.ts","../src/lib/run-history.ts","../src/components/ScenarioRunHistory.tsx","../src/interactive/collapse-context.ts","../src/interactive/scenario-actions.tsx","../src/components/ui/card.tsx","../src/components/ReportScenario.tsx","../src/components/ReportScenarioList.tsx","../src/components/ReportFeature.tsx","../src/components/ReportFeatureList.tsx","../src/components/ui/empty.tsx","../src/components/ReportEmpty.tsx","../src/components/ReportSummary.tsx","../src/lib/provenance.ts","../src/components/ReportMeta.tsx","../src/components/ReportSchemaError.tsx","../src/components/ReportShell.tsx","../src/components/Report.tsx"],"sourcesContent":["/**\n * Server-only entry: render a StoryReport to a standalone HTML document string.\n *\n * This is the single rendering path shared by the CLI's standalone `.html`\n * output and (later) the Astro docs site — both render the same <Report/>\n * component tree, so there is no second renderer to drift from.\n *\n * No fs, no client code. The caller supplies the stylesheet text (read once\n * from `executable-stories-react/tailwind.css`) so this module stays pure and\n * bundler-agnostic. The interactive hydration island is injected via\n * `bodyExtra` in a later phase; this entry renders static markup only.\n */\n\nimport { createElement } from \"react\";\nimport { renderToStaticMarkup } from \"react-dom/server\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"./result\";\nimport { unwrapReport } from \"./result\";\nimport { Report } from \"./components/Report\";\nimport type { ScenarioHistoryMap, ScenarioRunEvent } from \"./lib/run-history\";\n\nexport type { ScenarioHistoryMap, ScenarioRunEvent };\n\nexport interface RenderReportToHtmlOptions {\n /** Document <title> and the report's <h1>. */\n title?: string;\n /** Stylesheet text inlined into <head> (e.g. executable-stories-react/tailwind.css). */\n css?: string;\n /** Force a theme; defaults to \"light\" (CSS still honours prefers-color-scheme). */\n theme?: \"light\" | \"dark\";\n /** Raw HTML injected at the end of <head> (font links, CDN module scripts). */\n headExtra?: string;\n /** Raw HTML injected before </body> (the hydration island <script>, later phases). */\n bodyExtra?: string;\n /** Document language attribute. */\n lang?: string;\n /** Load highlight.js to colour code blocks (default true). */\n syntaxHighlighting?: boolean;\n /** Load mermaid to render `pre[data-mermaid]` diagrams (default true). */\n mermaid?: boolean;\n /**\n * When set, embed the report JSON + this inlined IIFE bundle text\n * (executable-stories-react/report-island.js) so the static markup is\n * upgraded to the interactive tree on load. The static render stays as the\n * no-JS fallback.\n */\n islandScript?: string;\n /**\n * Days before the interactive report flags itself as stale (\"Last verified\n * N days ago\" warning banner). 0 disables the warning. Default 7.\n */\n staleAfterDays?: number;\n /**\n * Recent run events per scenario id (joined from the CLI's --history-file\n * store). Embedded as JSON next to the report data; the interactive island\n * renders a run-over-run timeline strip on each scenario card. Ignored for\n * static (non-island) output.\n */\n scenarioHistory?: ScenarioHistoryMap;\n}\n\nconst ROOT_ID = \"es-report-root\";\nconst DATA_ID = \"es-report-data\";\nconst HISTORY_ID = \"es-report-history\";\n\n/** Escape a JSON string for safe embedding inside a <script> element. */\nfunction escapeJsonForScript(json: string): string {\n return json.replace(/[<\\u2028\\u2029]/g, (c) => \"\\\\u\" + c.charCodeAt(0).toString(16).padStart(4, \"0\"));\n}\n\nconst HLJS_URL = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js\";\nconst HLJS_CSS_LIGHT = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css\";\nconst HLJS_CSS_DARK = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\";\nconst MERMAID_URL = \"https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs\";\n\n/** Build the CDN <head> styles + the bottom-of-body init module script. */\nfunction cdnAssets(syntaxHighlighting: boolean, mermaid: boolean): { head: string; body: string } {\n const headParts: string[] = [];\n const imports: string[] = [];\n const init: string[] = [];\n\n if (syntaxHighlighting) {\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_LIGHT}\">`);\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_DARK}\" media=\"(prefers-color-scheme: dark)\">`);\n imports.push(`import hljs from \"${HLJS_URL}\";`);\n init.push(\"document.querySelectorAll('pre code').forEach((el) => hljs.highlightElement(el));\");\n }\n if (mermaid) {\n imports.push(`import mermaid from \"${MERMAID_URL}\";`);\n init.push(\"mermaid.initialize({ startOnLoad: false, theme: 'neutral' });\");\n init.push('await mermaid.run({ querySelector: \"pre[data-mermaid]\" });');\n }\n\n const body = imports.length\n ? `<script type=\"module\">\\n${imports.join(\"\\n\")}\\n${init.join(\"\\n\")}\\n</script>`\n : \"\";\n return { head: headParts.join(\"\\n\"), body };\n}\n\nconst HTML_ESCAPES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n};\n\nfunction escapeHtml(value: string): string {\n return value.replace(/[&<>\"']/g, (ch) => HTML_ESCAPES[ch] ?? ch);\n}\n\n/**\n * Render a StoryReport (or a parse Result) to a complete, self-contained HTML\n * document. The report markup is wrapped in `.es-report-island` so the scoped\n * Tailwind/shadcn resets and utilities apply without leaking onto a host page.\n */\nexport function renderReportToHtml(\n report: StoryReport | Result<StoryReport>,\n options: RenderReportToHtmlOptions = {},\n): string {\n const {\n title = \"Story Report\",\n css = \"\",\n theme = \"light\",\n headExtra = \"\",\n bodyExtra = \"\",\n lang = \"en\",\n syntaxHighlighting = true,\n mermaid = true,\n islandScript = \"\",\n staleAfterDays = 7,\n scenarioHistory,\n } = options;\n\n const markup = renderToStaticMarkup(\n createElement(Report, { report, title }),\n );\n\n const cdn = cdnAssets(syntaxHighlighting, mermaid);\n\n // Interactive island: embed the report JSON + the inlined IIFE so the static\n // markup is upgraded to <ReportInteractive> on load (static = no-JS fallback).\n // <Report> already normalizes the same input internally; we re-normalize here\n // only to recover the bare report for the JSON payload.\n const parsed = unwrapReport(report);\n const rawReport: StoryReport | undefined = parsed.ok ? parsed.data : undefined;\n const interactive = islandScript.length > 0 && rawReport !== undefined;\n const dataScript = interactive\n ? `<script type=\"application/json\" id=\"${DATA_ID}\">${escapeJsonForScript(JSON.stringify(rawReport))}</script>`\n : \"\";\n const historyScript =\n interactive && scenarioHistory && Object.keys(scenarioHistory).length > 0\n ? `<script type=\"application/json\" id=\"${HISTORY_ID}\">${escapeJsonForScript(JSON.stringify(scenarioHistory))}</script>`\n : \"\";\n const islandTag = interactive ? `<script>${islandScript}</script>` : \"\";\n // When interactive, the React island OWNS the doc-entry DOM via createRoot.\n // Highlighting + mermaid therefore render inside the React tree (the island\n // reads these flags and wires the matching renderers); the CDN post-processor\n // module (cdn.body) would race the client takeover and is dropped. The hljs\n // stylesheet (cdn.head) is still required to colour the React-owned tokens.\n const cdnBody = interactive ? \"\" : cdn.body;\n const islandConfigAttrs = interactive\n ? ` data-es-syntax=\"${syntaxHighlighting ? \"true\" : \"false\"}\" data-es-mermaid=\"${mermaid ? \"true\" : \"false\"}\" data-es-stale-days=\"${Number.isFinite(staleAfterDays) && staleAfterDays >= 0 ? staleAfterDays : 7}\"`\n : \"\";\n const rootAttrs = interactive\n ? ` id=\"${ROOT_ID}\" data-title=\"${escapeHtml(title)}\"${islandConfigAttrs}`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"${escapeHtml(lang)}\" data-theme=\"${theme === \"dark\" ? \"dark\" : \"light\"}\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"color-scheme\" content=\"light dark\">\n<title>${escapeHtml(title)}</title>\n${cdn.head}\n${headExtra}\n<style>${css}</style>\n</head>\n<body>\n<div${rootAttrs} class=\"es-report-island font-sans text-foreground\">${markup}</div>\n${dataScript}\n${historyScript}\n${bodyExtra}\n${cdnBody}\n${islandTag}\n</body>\n</html>`;\n}\n","/**\n * Result<T> — explicit success/error type matching the cookbook convention.\n *\n * Used at the boundary where a StoryReport is parsed: the consumer hands us\n * an unknown value (file contents, fetch body, prop) and we return a Result.\n */\nimport type { StoryReport } from \"executable-stories-core\";\n\nexport type Result<T, E = ReportParseError> =\n | { ok: true; data: T }\n | { ok: false; error: E };\n\nexport interface ReportParseError {\n message: string;\n code: ReportParseErrorCode;\n issues?: readonly { path: string; message: string }[];\n}\n\nexport type ReportParseErrorCode =\n | \"INVALID_INPUT\"\n | \"SCHEMA_VERSION_MISMATCH\"\n | \"VALIDATION_FAILED\";\n\nexport const ok = <T>(data: T): Result<T> => ({ ok: true, data });\nexport const err = (error: ReportParseError): Result<never> => ({ ok: false, error });\n\n/**\n * Normalize the `StoryReport | Result<StoryReport>` prop accepted across the\n * render entrypoints (`Report`, `ReportInteractive`, `renderReportToHtml`) into\n * a single `Result`. A bare report becomes `ok(report)`; an already-wrapped\n * value passes through. One place owns the \"is this a Result?\" discrimination.\n */\nexport function unwrapReport(value: StoryReport | Result<StoryReport>): Result<StoryReport> {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"ok\" in value &&\n typeof (value as { ok: unknown }).ok === \"boolean\"\n ) {\n return value as Result<StoryReport>;\n }\n return ok(value as StoryReport);\n}\n","import { useMemo, type ReactNode } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportContext, type ReportContextValue } from \"./ReportContext\";\n\nexport interface ReportRootProps {\n report: StoryReport;\n customRenderers?: CustomRenderers;\n renderers?: BuiltinRenderers;\n children: ReactNode;\n}\n\nconst EMPTY_CUSTOM: CustomRenderers = {};\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function ReportRoot({\n report,\n customRenderers,\n renderers,\n children,\n}: ReportRootProps) {\n const value = useMemo<ReportContextValue>(\n () => ({\n report,\n customRenderers: customRenderers ?? EMPTY_CUSTOM,\n renderers: renderers ?? EMPTY_RENDERERS,\n }),\n [report, customRenderers, renderers],\n );\n return <ReportContext.Provider value={value}>{children}</ReportContext.Provider>;\n}\n","import { createContext } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nexport interface ReportContextValue {\n report: StoryReport;\n customRenderers: CustomRenderers;\n renderers: BuiltinRenderers;\n}\n\nexport const ReportContext = createContext<ReportContextValue | null>(null);\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\n\nexport function useReport() {\n const ctx = useContext(ReportContext);\n if (!ctx) {\n throw new Error(\n \"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those.\",\n );\n }\n return ctx.report;\n}\n","/**\n * Duration formatting utilities.\n */\n\n/**\n * Format milliseconds as human-readable duration.\n *\n * @param ms - Duration in milliseconds\n * @returns Formatted string (e.g., \"123 ms\", \"1.5 s\", \"2m 30s\")\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)} ms`;\n }\n\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(2)} s`;\n }\n\n const minutes = Math.floor(ms / 60000);\n const seconds = Math.floor((ms % 60000) / 1000);\n\n if (minutes < 60) {\n return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;\n }\n\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n return `${hours}h ${remainingMinutes}m`;\n}\n\n/**\n * Convert milliseconds to nanoseconds.\n *\n * Used for Cucumber JSON format which expects nanoseconds.\n *\n * @param ms - Duration in milliseconds\n * @returns Duration in nanoseconds\n */\nexport function msToNanoseconds(ms: number): number {\n return Math.round(ms * 1_000_000);\n}\n\n/**\n * Convert nanoseconds to milliseconds.\n *\n * @param ns - Duration in nanoseconds\n * @returns Duration in milliseconds\n */\nexport function nanosecondsToMs(ns: number): number {\n return ns / 1_000_000;\n}\n","import type { ReportDocNote } from \"executable-stories-core\";\n\nexport function DocNote({ entry }: { entry: ReportDocNote }) {\n return <p className=\"my-2 text-sm text-muted-foreground\">{entry.text}</p>;\n}\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { useRender } from \"@base-ui/react/use-render\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst badgeVariants = cva(\n \"inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90\",\n outline:\n \"border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n ghost: \"[a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 [a&]:hover:underline\",\n passed: \"border-pass-border bg-pass-bg text-pass font-mono uppercase\",\n failed: \"border-fail-border bg-fail-bg text-fail font-mono uppercase\",\n skipped: \"border-skip-border bg-skip-bg text-skip font-mono uppercase\",\n pending: \"border-pend-border bg-pend-bg text-pend font-mono uppercase\",\n tag: \"border-pass-border bg-pass-bg text-pass font-mono font-medium\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n render,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & {\n // Base UI composition: pass `render={<a … />}` to swap the underlying tag —\n // replaces Radix's `asChild`. See rules/base-vs-radix.md.\n render?: useRender.RenderProp\n }) {\n return useRender({\n defaultTagName: \"span\",\n render,\n props: {\n \"data-slot\": \"badge\",\n \"data-variant\": variant,\n className: cn(badgeVariants({ variant }), className),\n ...props,\n },\n })\n}\n\nexport { Badge, badgeVariants }\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merge class names with Tailwind-aware conflict resolution (shadcn `cn`). */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import type { ReportDocTag } from \"executable-stories-core\";\nimport { Badge } from \"@/components/ui/badge\";\n\nexport function DocTag({ entry }: { entry: ReportDocTag }) {\n return (\n <ul className=\"my-2 flex flex-wrap gap-1.5\" aria-label=\"Tags\">\n {entry.names.map((n) => (\n <li key={n}>\n <Badge variant=\"tag\">{n}</Badge>\n </li>\n ))}\n </ul>\n );\n}\n","import type { ReportDocKv } from \"executable-stories-core\";\n\nfunction formatValue(value: unknown): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport function DocKv({ entry }: { entry: ReportDocKv }) {\n return (\n <dl className=\"my-2 flex flex-wrap items-baseline gap-x-2 text-sm\">\n <dt className=\"font-semibold text-muted-foreground\">{entry.label}</dt>\n <dd className=\"font-mono text-foreground\">{formatValue(entry.value)}</dd>\n </dl>\n );\n}\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nconst EMPTY_CUSTOM: CustomRenderers = {};\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function useCustomRenderers(): CustomRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.customRenderers ?? EMPTY_CUSTOM;\n}\n\nexport function useBuiltinRenderers(): BuiltinRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.renderers ?? EMPTY_RENDERERS;\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportDocCode } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Shared shell for code blocks: optional label + the scrollable `<pre>`. Both\n * the static `DocCode` and the island's CDN-highlighted variant render their\n * `<code>` into this so the two can never drift in spacing or chrome.\n */\nexport function CodeFigure({ label, children }: { label?: string; children: ReactNode }) {\n return (\n <figure className=\"my-3\">\n {label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{label}</figcaption>\n ) : null}\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3\">\n {children}\n </pre>\n </figure>\n );\n}\n\nexport function DocCode({ entry }: { entry: ReportDocCode }) {\n const renderers = useBuiltinRenderers();\n if (renderers.code) {\n return <>{renderers.code(entry)}</>;\n }\n return (\n <CodeFigure label={entry.label}>\n <code className={cn(\"font-mono text-xs\", entry.lang && `language-${entry.lang}`)}>\n {entry.content}\n </code>\n </CodeFigure>\n );\n}\n","import type { ReportDocTable } from \"executable-stories-core\";\n\nexport function DocTable({ entry }: { entry: ReportDocTable }) {\n return (\n <figure className=\"my-3\">\n {entry.label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">\n {entry.label}\n </figcaption>\n ) : null}\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-muted/50\">\n {entry.columns.map((c) => (\n <th key={c} scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n {c}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {entry.rows.map((row, i) => (\n <tr key={i}>\n {row.map((cell, j) => (\n <td key={j} className=\"border-b border-border px-3 py-2 text-foreground\">\n {cell}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </figure>\n );\n}\n","import type { ReportDocLink } from \"executable-stories-core\";\n\nexport function DocLink({ entry }: { entry: ReportDocLink }) {\n return (\n <a\n className=\"text-sm font-medium text-primary underline underline-offset-2 hover:no-underline\"\n href={entry.url}\n rel=\"noreferrer noopener\"\n target=\"_blank\"\n >\n {entry.label}\n </a>\n );\n}\n","import { marked } from \"marked\";\nimport type { ReportDocSection } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { safeUrl } from \"../../lib/url\";\n\n/**\n * Best-effort sanitizer for marked-generated HTML. `section` markdown is\n * authored in the test source (developer-trusted), so this is defense-in-depth,\n * not a hard boundary against hostile input. It:\n * - drops <script>/<style> and other active elements (iframe/object/embed/form)\n * - strips on* event-handler attributes\n * - neutralizes any non-http(s) scheme on href/src via the shared `safeUrl`\n * allow-list (covers javascript:/data:/vbscript:/file:, not just javascript:)\n *\n * It is NOT a substitute for a full HTML sanitizer (it won't catch entity-\n * obfuscated schemes). For untrusted markdown, supply `renderers.section` with\n * your own sanitizer.\n */\nfunction neutralizeUrl(value: string): string {\n return safeUrl(value) ?? \"#\";\n}\n\nfunction safeMarkdownHtml(markdown: string): string {\n const raw = marked.parse(markdown, { async: false }) as string;\n return raw\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, \"\")\n .replace(/<\\/?(?:iframe|object|embed|form|base)\\b[^>]*>/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*\"[^\"]*\"/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*'[^']*'/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*[^\\s>]+/gi, \"\")\n .replace(/(href|src)\\s*=\\s*\"([^\"]*)\"/gi, (_m, attr, val) => `${attr}=\"${neutralizeUrl(val)}\"`)\n .replace(/(href|src)\\s*=\\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);\n}\n\nexport function DocSection({ entry }: { entry: ReportDocSection }) {\n const renderers = useBuiltinRenderers();\n if (renderers.section) {\n return <>{renderers.section(entry)}</>;\n }\n const html = safeMarkdownHtml(entry.markdown);\n return (\n <section className=\"my-3 text-sm\" aria-label={entry.title}>\n {entry.title ? <h4 className=\"mb-1 font-semibold text-foreground\">{entry.title}</h4> : null}\n <div\n className=\"es-doc-prose text-muted-foreground\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n </section>\n );\n}\n","/**\n * A URL is safe to put in the DOM (href/src/poster) only if it's relative (no\n * scheme) or uses http/https. Anything with another scheme — notably\n * `javascript:` (which runs in the page context), plus `data:` / `vbscript:` /\n * `file:` — is rejected. Report JSON carries adapter-supplied URLs, so every\n * report-sourced URL that reaches the DOM is treated as untrusted and passed\n * through here (DocHtml iframe src, DocVideo src/poster, …).\n */\nexport function safeUrl(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);\n if (scheme && !/^https?$/i.test(scheme[1] ?? \"\")) return undefined;\n return trimmed;\n}\n\n/**\n * Same trust boundary as safeUrl(), but for `<img src>`: also allows\n * `data:image/*` URIs, since that's how executable-stories-playwright's\n * story.screenshot() inlines a captured screenshot (see\n * inlineScreenshotIfPossible in that package). Browsers sandbox SVG rendered\n * via `<img>` — no script execution, no external resource loads — so\n * `data:image/svg+xml` is safe here even though data: URIs are rejected for\n * iframe/video src.\n */\nexport function safeImageUrl(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (/^data:image\\//i.test(trimmed)) return trimmed;\n return safeUrl(trimmed);\n}\n\n/**\n * True for POSIX absolute paths (`/foo`, `\\foo`) and Windows drive-letter\n * paths (`C:\\foo`) — i.e. a local filesystem path rather than a URL. Report\n * assets are bundled (copied + rewritten to a relative `assets/...` path) at\n * format time when the source file can be found; a path that's still\n * absolute by the time it reaches the DOM means that bundling step couldn't\n * find the file — rendering it as `<img src>`/`<video src>` would 404 (or\n * silently resolve nothing) since it points at a path on the machine that\n * generated the report, not at the browser's origin.\n */\nexport function isLocalFsPath(value: string): boolean {\n return /^(?:[/\\\\]|[A-Za-z]:[/\\\\])/.test(value);\n}\n","import type { Ref } from \"react\";\nimport type { ReportDocMermaid } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\n\n/**\n * The raw mermaid source as a semantic `<pre data-mermaid>`. This is the\n * default render and the universal fallback: AI agents, screen readers, and\n * no-JS views all get the readable source. `<MermaidDiagram>` upgrades this to\n * a drawn diagram on the client.\n */\nexport function MermaidSource({ entry, ref }: { entry: ReportDocMermaid; ref?: Ref<HTMLElement> }) {\n return (\n <figure ref={ref} className=\"my-3\" aria-label={entry.title ?? \"Diagram\"}>\n {entry.title ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{entry.title}</figcaption>\n ) : null}\n <pre\n data-mermaid\n tabIndex={0}\n className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\"\n >\n {entry.code}\n </pre>\n </figure>\n );\n}\n\n/**\n * Renders mermaid source as a semantic `<pre data-mermaid>` by default.\n *\n * To draw the diagram, supply a `renderers.mermaid` prop — e.g. the shipped\n * `MermaidDiagram` (`renderers={{ mermaid: (e) => <MermaidDiagram entry={e} /> }}`).\n */\nexport function DocMermaid({ entry }: { entry: ReportDocMermaid }) {\n const renderers = useBuiltinRenderers();\n if (renderers.mermaid) {\n return <>{renderers.mermaid(entry)}</>;\n }\n return <MermaidSource entry={entry} />;\n}\n","import type { ReportDocScreenshot } from \"executable-stories-core\";\nimport { isLocalFsPath, safeImageUrl } from \"../../lib/url\";\n\n/**\n * A screenshot that's still an absolute local filesystem path by the time it\n * reaches this component means the report's asset bundler couldn't find the\n * file to inline/copy it (deleted, moved, or never captured — see\n * inlineScreenshotIfPossible in executable-stories-playwright). `<img src>`\n * would 404 against a path from the machine that generated the report, so\n * show a placeholder instead of a broken image.\n */\nexport function DocScreenshot({ entry }: { entry: ReportDocScreenshot }) {\n const src = isLocalFsPath(entry.path) ? undefined : safeImageUrl(entry.path);\n\n if (!src) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Screenshot unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs\">{entry.alt}</figcaption> : null}\n </figure>\n );\n }\n\n return (\n <figure className=\"my-3\">\n <img\n src={src}\n alt={entry.alt ?? \"\"}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs text-muted-foreground\">{entry.alt}</figcaption> : null}\n </figure>\n );\n}\n","import type { ReportDocVideo } from \"executable-stories-core\";\nimport { isLocalFsPath, safeUrl } from \"../../lib/url\";\n\n/**\n * Renders a video doc entry. Video bytes are large and never inlined; `path` is\n * a URL or a path that resolves alongside the report. Both `path` and `poster`\n * are adapter-supplied, so they go through the same scheme allow-list as the\n * DocHtml iframe src (no `javascript:`/`data:` URLs reach the DOM).\n *\n * An absolute local filesystem path means the report's asset bundler\n * couldn't find/copy the file — a `<video src>` pointed at a runner-local\n * path would just fail to load, so show a placeholder instead.\n */\nexport function DocVideo({ entry }: { entry: ReportDocVideo }) {\n if (isLocalFsPath(entry.path)) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Video unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.caption ? <figcaption className=\"mt-1.5 text-xs\">{entry.caption}</figcaption> : null}\n </figure>\n );\n }\n\n const src = safeUrl(entry.path);\n const poster = safeUrl(entry.poster);\n return (\n <figure className=\"my-3\">\n <video\n controls\n preload=\"metadata\"\n {...(src ? { src } : {})}\n {...(poster ? { poster } : {})}\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.caption ? (\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{entry.caption}</figcaption>\n ) : null}\n </figure>\n );\n}\n","import type { ReportDocHtml } from \"executable-stories-core\";\nimport { safeUrl } from \"../../lib/url\";\n\n/**\n * Renders an embedded-HTML doc entry inside a SANDBOXED iframe. All embedded\n * HTML is untrusted, so the frame is `sandbox=\"allow-scripts\"` only (no\n * allow-same-origin) — embedded scripts run (charts work) but can't touch the\n * report DOM, cookies, or storage. Inline `content` → srcdoc (keeps the report\n * self-contained); `url`/`path` → src (scheme-validated).\n */\nexport function DocHtml({ entry }: { entry: ReportDocHtml }) {\n const height = typeof entry.height === \"number\" ? `${entry.height}px` : (entry.height ?? \"400px\");\n const title = entry.title ?? \"Embedded HTML\";\n const safeHref = safeUrl(entry.url ?? entry.path);\n\n // Exactly one of content / url / path is set. A url/path with an unsafe\n // scheme yields no src (the figure still renders, just empty).\n const frameProps = entry.content !== undefined ? { srcDoc: entry.content } : { src: safeHref ?? \"\" };\n\n return (\n <figure className=\"my-3 overflow-hidden rounded-md border border-border\">\n <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\">\n <span>{entry.title ?? \"HTML\"}</span>\n {safeHref ? (\n <a\n href={safeHref}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n aria-label=\"Open in new tab\"\n title=\"Open in new tab\"\n className=\"text-primary\"\n >\n ↗\n </a>\n ) : null}\n </figcaption>\n <iframe\n {...frameProps}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n title={title}\n className=\"block w-full border-0\"\n style={{ height }}\n />\n </figure>\n );\n}\n","import type { ReportDocCustom } from \"executable-stories-core\";\nimport { useCustomRenderers } from \"../../hooks/useRenderers\";\n\nexport function DocCustom({ entry }: { entry: ReportDocCustom }) {\n const renderers = useCustomRenderers();\n const renderer = renderers[entry.type];\n if (renderer) {\n return <>{renderer(entry)}</>;\n }\n return (\n <div className=\"my-2\" data-type={entry.type}>\n <p className=\"mb-1 text-xs font-medium text-muted-foreground\">{entry.type}</p>\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\">\n {safeStringify(entry.data)}\n </pre>\n </div>\n );\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocNote } from \"./DocNote\";\nimport { DocTag } from \"./DocTag\";\nimport { DocKv } from \"./DocKv\";\nimport { DocCode } from \"./DocCode\";\nimport { DocTable } from \"./DocTable\";\nimport { DocLink } from \"./DocLink\";\nimport { DocSection } from \"./DocSection\";\nimport { DocMermaid } from \"./DocMermaid\";\nimport { DocScreenshot } from \"./DocScreenshot\";\nimport { DocVideo } from \"./DocVideo\";\nimport { DocHtml } from \"./DocHtml\";\nimport { DocCustom } from \"./DocCustom\";\n\nexport function DocEntry({ entry }: { entry: ReportDocEntry }) {\n switch (entry.kind) {\n case \"note\":\n return <DocNote entry={entry} />;\n case \"tag\":\n return <DocTag entry={entry} />;\n case \"kv\":\n return <DocKv entry={entry} />;\n case \"code\":\n return <DocCode entry={entry} />;\n case \"table\":\n return <DocTable entry={entry} />;\n case \"link\":\n return <DocLink entry={entry} />;\n case \"section\":\n return <DocSection entry={entry} />;\n case \"mermaid\":\n return <DocMermaid entry={entry} />;\n case \"screenshot\":\n return <DocScreenshot entry={entry} />;\n case \"video\":\n return <DocVideo entry={entry} />;\n case \"html\":\n return <DocHtml entry={entry} />;\n case \"custom\":\n return <DocCustom entry={entry} />;\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocEntry } from \"./doc/DocEntry\";\n\nexport interface ReportDocEntriesProps {\n entries: readonly ReportDocEntry[];\n}\n\nexport function ReportDocEntries({ entries }: ReportDocEntriesProps) {\n if (entries.length === 0) return null;\n return (\n <>\n {entries.map((entry, i) => (\n <DocEntry key={i} entry={entry} />\n ))}\n </>\n );\n}\n","import type { ReactNode } from \"react\";\n\n/**\n * Highlight step parameters (double-quoted strings, standalone numbers) in step\n * text — the React equivalent of the report's highlightStepParams. Returns a\n * node array so the matched params can be wrapped in a styled <span> without\n * dangerouslySetInnerHTML.\n *\n * Regex mirrors the string renderer exactly:\n * - `\"[^\"]*\"` double-quoted strings (numbers inside quotes stay part of the string)\n * - `(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])` standalone numbers, dot/word-boundary aware\n */\nconst STEP_PARAM_PATTERN = /\"[^\"]*\"|(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])/g;\n\nexport function highlightStepParams(text: string): ReactNode {\n const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));\n if (matches.length === 0) return text;\n\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n matches.forEach((match, i) => {\n const start = match.index;\n const end = start + match[0].length;\n if (start > lastIndex) nodes.push(text.slice(lastIndex, start));\n nodes.push(\n <span key={i} className=\"font-medium text-step-param italic\">\n {match[0]}\n </span>,\n );\n lastIndex = end;\n });\n if (lastIndex < text.length) nodes.push(text.slice(lastIndex));\n return nodes;\n}\n","import type { ReportStep, ReportScenario } from \"executable-stories-core\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { ReportDocEntries } from \"./ReportDocEntries\";\nimport { highlightStepParams } from \"@/lib/step-params\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportStepsProps {\n scenario: ReportScenario;\n}\n\nconst STEP_GLYPH: Record<string, string> = {\n passed: \"✓\",\n failed: \"✗\",\n skipped: \"○\",\n pending: \"○\",\n};\n\nconst STEP_GLYPH_COLOR: Record<string, string> = {\n passed: \"text-pass\",\n failed: \"text-fail\",\n skipped: \"text-skip\",\n pending: \"text-pend\",\n};\n\nexport function ReportSteps({ scenario }: ReportStepsProps) {\n if (scenario.steps.length === 0) return null;\n return (\n <ol data-slot=\"steps\" className=\"flex flex-col\">\n {scenario.steps.map((step) => (\n <ReportStepItem key={step.id} step={step} />\n ))}\n </ol>\n );\n}\n\nexport function ReportStepItem({ step }: { step: ReportStep }) {\n // And/But (incl. auto-And repeats) read as continuations of the prior step —\n // indented with a muted keyword, matching the report's `.step.continuation`.\n const kw = step.keyword.toLowerCase();\n const continuation = kw === \"and\" || kw === \"but\";\n return (\n <li\n id={step.id}\n data-status={step.status}\n className={cn(\"py-1.5 text-[0.8125rem] leading-normal\", continuation && \"pl-5\")}\n >\n <div className=\"flex items-baseline gap-2\">\n <span aria-hidden className={cn(\"w-4 shrink-0 text-center text-xs\", STEP_GLYPH_COLOR[step.status])}>\n {STEP_GLYPH[step.status] ?? \"○\"}\n </span>\n <span\n className={cn(\n \"min-w-[52px] shrink-0 font-mono text-xs font-semibold capitalize\",\n continuation ? \"font-medium text-muted-foreground\" : \"text-keyword\",\n )}\n >\n {step.keyword}\n </span>\n <span className=\"flex-1 text-foreground\">{highlightStepParams(step.text)}</span>\n {step.durationMs > 0 ? (\n <span className=\"shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(step.durationMs)}\n </span>\n ) : null}\n </div>\n {step.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mt-2.5 ml-6 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {step.errorMessage}\n </pre>\n ) : null}\n {step.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-2 ml-6\">\n <ReportDocEntries entries={step.docEntries} />\n </div>\n ) : null}\n </li>\n );\n}\n","import type { ReportAttachment } from \"executable-stories-core\";\n\n/**\n * Renders scenario attachments. Base64 images embed inline; everything else\n * becomes a labelled data-URI download link. Mirrors the report's attachments\n * block (which also inlines images and links other media).\n */\nexport function ReportAttachments({ attachments }: { attachments: ReportAttachment[] }) {\n if (attachments.length === 0) return null;\n return (\n // role=\"group\" (not a labelled <section>) so multiple scenarios' attachment\n // blocks don't create duplicate \"Attachments\" region landmarks.\n <div role=\"group\" aria-label=\"Attachments\" className=\"mt-3 flex flex-col gap-2\">\n {attachments.map((att, i) => {\n const dataUri =\n att.contentEncoding === \"BASE64\"\n ? `data:${att.mediaType};base64,${att.body}`\n : `data:${att.mediaType},${encodeURIComponent(att.body)}`;\n const isImage = att.mediaType.startsWith(\"image/\");\n return (\n <figure key={`${att.name}-${i}`} className=\"m-0\">\n {isImage ? (\n <>\n <img\n src={dataUri}\n alt={att.name}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{att.name}</figcaption>\n </>\n ) : (\n <a\n href={dataUri}\n download={att.name}\n className=\"text-xs text-link underline underline-offset-2\"\n >\n {att.name} <span className=\"text-muted-foreground\">({att.mediaType})</span>\n </a>\n )}\n </figure>\n );\n })}\n </div>\n );\n}\n","/**\n * Pure span normalization + tree building for the OTel trace waterfall.\n * Ported from the formatters trace-view renderer so the React waterfall shows\n * the same structure. Side-effect-free for unit testing.\n */\n\nimport type { OtelSpan } from \"executable-stories-core/types/otel\";\n\nexport interface NormalizedSpan {\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeMs: number;\n durationMs: number;\n status: \"ok\" | \"error\" | \"unset\";\n statusMessage?: string;\n}\n\nexport interface TraceRow extends NormalizedSpan {\n depth: number;\n}\n\nconst VALID = new Set([\"ok\", \"error\", \"unset\"]);\nconst safeStatus = (s: string): NormalizedSpan[\"status\"] => (VALID.has(s) ? (s as NormalizedSpan[\"status\"]) : \"unset\");\n\nexport function normalizeSpans(spans: readonly OtelSpan[]): NormalizedSpan[] {\n const out: NormalizedSpan[] = [];\n for (const span of spans) {\n if (!span || typeof span.spanId !== \"string\" || typeof span.name !== \"string\") continue;\n let startTimeMs: number;\n let durationMs: number;\n if (span.startTimeMs != null && span.durationMs != null) {\n startTimeMs = span.startTimeMs;\n durationMs = span.durationMs;\n } else if (span.startTimeUnixNano != null && span.endTimeUnixNano != null) {\n startTimeMs = span.startTimeUnixNano / 1e6;\n durationMs = (span.endTimeUnixNano - span.startTimeUnixNano) / 1e6;\n } else {\n continue;\n }\n durationMs = Math.max(0, durationMs);\n if (!isFinite(startTimeMs) || !isFinite(durationMs)) continue;\n out.push({\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n startTimeMs,\n durationMs,\n status: safeStatus(span.status),\n statusMessage: span.statusMessage,\n });\n }\n return out;\n}\n\n/** Flatten spans into rows in tree order with a depth, parent before children. */\nexport function toTraceRows(spans: readonly OtelSpan[]): TraceRow[] {\n const normalized = normalizeSpans(spans);\n if (normalized.length === 0) return [];\n\n interface Node {\n span: NormalizedSpan;\n children: Node[];\n depth: number;\n }\n const byId = new Map<string, Node>();\n for (const span of normalized) {\n let key = span.spanId;\n let suffix = 2;\n while (byId.has(key)) key = `${span.spanId}__dup${suffix++}`;\n byId.set(key, { span: { ...span, spanId: key }, children: [], depth: 0 });\n }\n\n const roots: Node[] = [];\n for (const node of byId.values()) {\n const parent = node.span.parentSpanId ? byId.get(node.span.parentSpanId) : undefined;\n if (parent && parent !== node) parent.children.push(node);\n else roots.push(node);\n }\n for (const node of byId.values()) node.children.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n\n const rows: TraceRow[] = [];\n const seen = new Set<string>();\n const walk = (node: Node, depth: number): void => {\n if (seen.has(node.span.spanId)) return;\n seen.add(node.span.spanId);\n rows.push({ ...node.span, depth });\n for (const child of node.children) walk(child, depth + 1);\n };\n for (const root of roots) walk(root, 0);\n // Orphans from cycles: promote to depth 0.\n for (const node of byId.values()) {\n if (!seen.has(node.span.spanId)) walk(node, 0);\n }\n return rows;\n}\n\nexport interface TraceWindow {\n minStartMs: number;\n totalMs: number;\n}\n\nexport function traceWindow(rows: readonly TraceRow[]): TraceWindow {\n let min = Infinity;\n let max = -Infinity;\n for (const r of rows) {\n min = Math.min(min, r.startTimeMs);\n max = Math.max(max, r.startTimeMs + r.durationMs);\n }\n const total = max - min;\n return { minStartMs: isFinite(min) ? min : 0, totalMs: total > 0 ? total : 1 };\n}\n","import type { OtelSpan } from \"executable-stories-core/types/otel\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { toTraceRows, traceWindow } from \"@/lib/trace\";\nimport { cn } from \"@/lib/utils\";\n\nconst BAR_COLOR: Record<string, string> = {\n ok: \"bg-pass\",\n error: \"bg-fail\",\n unset: \"bg-skip\",\n};\n\n/**\n * OTel trace waterfall. Collapsed by default (native <details>, no JS) so it\n * renders in both the static and interactive reports. Each span is a row with a\n * depth-indented name and a bar positioned/sized by its time window.\n */\nexport function ReportTrace({ spans }: { spans: readonly OtelSpan[] | undefined }) {\n if (!spans || spans.length === 0) return null;\n const rows = toTraceRows(spans);\n if (rows.length === 0) return null;\n const { minStartMs, totalMs } = traceWindow(rows);\n\n return (\n <details className=\"mt-3 rounded-md border border-border bg-muted/30\">\n <summary className=\"cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground\">\n Trace ({rows.length} span{rows.length === 1 ? \"\" : \"s\"}, {formatDuration(totalMs)})\n </summary>\n <ul className=\"flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]\">\n {rows.map((row, i) => {\n const leftPct = ((row.startTimeMs - minStartMs) / totalMs) * 100;\n const widthPct = Math.max((row.durationMs / totalMs) * 100, 0.5);\n return (\n <li key={`${row.spanId}-${i}`} className=\"flex items-center gap-2\">\n <span\n className=\"min-w-0 flex-1 truncate text-foreground\"\n style={{ paddingLeft: `${row.depth * 12}px` }}\n title={row.statusMessage ? `${row.name} — ${row.statusMessage}` : row.name}\n >\n {row.name}\n </span>\n <span className=\"relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40\">\n <span\n className={cn(\"absolute top-0 h-full rounded-sm\", BAR_COLOR[row.status])}\n style={{ left: `${leftPct}%`, width: `${widthPct}%` }}\n />\n </span>\n <span className=\"w-16 shrink-0 text-right text-muted-foreground\">\n {formatDuration(row.durationMs)}\n </span>\n </li>\n );\n })}\n </ul>\n </details>\n );\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { ScenarioHistoryMap } from \"../lib/run-history\";\n\n/**\n * Provided only inside <ReportInteractive> when the CLI embedded a run\n * history (--history-file). When null (the static <Report/> render,\n * Storybook, Astro), scenario cards simply omit the history strip.\n */\nconst ScenarioHistoryContext = createContext<ScenarioHistoryMap | null>(null);\n\nexport const ScenarioHistoryProvider = ScenarioHistoryContext.Provider;\n\nexport function useScenarioHistory(): ScenarioHistoryMap | null {\n return useContext(ScenarioHistoryContext);\n}\n","export type ScenarioRunStatus = \"passed\" | \"failed\" | \"skipped\" | \"pending\";\n\n/** One historical run of a scenario, oldest → newest in a history array. */\nexport interface ScenarioRunEvent {\n /** Epoch ms the run started. */\n timestamp: number;\n status: ScenarioRunStatus;\n runId?: string;\n durationMs?: number;\n commitSha?: string;\n branch?: string;\n}\n\n/** Recent run events keyed by ReportScenario.id. */\nexport type ScenarioHistoryMap = Record<string, ScenarioRunEvent[]>;\n\nexport interface RunStreak {\n status: ScenarioRunStatus;\n /** How many consecutive trailing runs share that status (≥1). */\n count: number;\n}\n\n/** The trailing same-status streak — \"passing for 5 runs\", \"failing for 2\". */\nexport function currentStreak(entries: readonly ScenarioRunEvent[]): RunStreak | undefined {\n const last = entries[entries.length - 1];\n if (!last) return undefined;\n let count = 0;\n for (let i = entries.length - 1; i >= 0 && entries[i]!.status === last.status; i--) count++;\n return { status: last.status, count };\n}\n\nconst STREAK_VERB: Record<ScenarioRunStatus, string> = {\n passed: \"Passing\",\n failed: \"Failing\",\n skipped: \"Skipped\",\n pending: \"Pending\",\n};\n\n/** Short human summary of a history window, used for the strip's tooltip. */\nexport function describeRunHistory(entries: readonly ScenarioRunEvent[]): string {\n const passed = entries.filter((e) => e.status === \"passed\").length;\n const base = `${passed}/${entries.length} runs passed`;\n const streak = currentStreak(entries);\n if (!streak || entries.length < 2) return base;\n return `${base} · ${STREAK_VERB[streak.status]} for the last ${streak.count === 1 ? \"run\" : `${streak.count} runs`}`;\n}\n\nexport type FlakinessLevel = \"stable\" | \"unstable\" | \"flaky\";\n\n/**\n * Below this many pass/fail samples a scenario is always \"stable\" — mirrors\n * MIN_FLAKINESS_SAMPLES in the formatters history module, which owns the\n * canonical thresholds. Keep the two in sync.\n */\nconst MIN_FLAKINESS_SAMPLES = 3;\n\n/**\n * Status-transition flakiness over a scenario's recent runs. Same\n * classification as the CLI history module (`calculateFlakiness`), ported so\n * the island stays self-sufficient on the embedded history JSON.\n */\nexport function flakinessOf(entries: readonly ScenarioRunEvent[]): FlakinessLevel {\n const countable = entries.filter((e) => e.status === \"passed\" || e.status === \"failed\");\n if (countable.length < MIN_FLAKINESS_SAMPLES) return \"stable\";\n\n let transitions = 0;\n for (let i = 1; i < countable.length; i++) {\n if (countable[i]!.status !== countable[i - 1]!.status) transitions++;\n }\n const transitionScore = transitions / (countable.length - 1);\n const failureRate = countable.filter((e) => e.status === \"failed\").length / countable.length;\n\n if (transitionScore > 0.5 || (transitionScore > 0.3 && failureRate > 0.2)) return \"flaky\";\n if (transitionScore > 0.2 || failureRate > 0.3) return \"unstable\";\n return \"stable\";\n}\n\nexport interface ScenarioRef {\n id: string;\n title: string;\n}\n\nexport interface LastRunDelta {\n /** Failed in this run, not failed in the previous one. */\n newlyFailing: ScenarioRef[];\n /** Passed in this run, failed in the previous one. */\n newlyPassing: ScenarioRef[];\n /** First appearance in the history window — no previous run to compare. */\n added: ScenarioRef[];\n}\n\n/**\n * What changed between the previous run and this one, for the report-header\n * strip. The history store appends the current run before the report is\n * generated, so each scenario's last entry IS this run and the entry before\n * it is the previous run. Returns undefined when no scenario has a previous\n * run to compare against (first run with history enabled).\n */\nexport function diffSinceLastRun(\n history: ScenarioHistoryMap,\n scenarios: readonly ScenarioRef[],\n): LastRunDelta | undefined {\n let hasPreviousRun = false;\n const delta: LastRunDelta = { newlyFailing: [], newlyPassing: [], added: [] };\n\n for (const scenario of scenarios) {\n const entries = history[scenario.id];\n if (!entries || entries.length === 0) continue;\n const last = entries[entries.length - 1]!;\n const prev = entries[entries.length - 2];\n if (!prev) {\n delta.added.push(scenario);\n continue;\n }\n hasPreviousRun = true;\n if (last.status === \"failed\" && prev.status !== \"failed\") delta.newlyFailing.push(scenario);\n else if (last.status === \"passed\" && prev.status === \"failed\") delta.newlyPassing.push(scenario);\n }\n\n return hasPreviousRun ? delta : undefined;\n}\n","import { useScenarioHistory } from \"../interactive/scenario-history-context\";\nimport { describeRunHistory, flakinessOf, type ScenarioRunEvent, type ScenarioRunStatus } from \"../lib/run-history\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/utils\";\n\n/** How many trailing runs the strip shows; older entries stay in the tooltip count. */\nconst MAX_DOTS = 10;\n\nconst DOT_COLOR: Record<ScenarioRunStatus, string> = {\n passed: \"bg-pass\",\n failed: \"bg-fail\",\n skipped: \"bg-skip\",\n pending: \"bg-pend\",\n};\n\nfunction dotTitle(e: ScenarioRunEvent): string {\n const parts = [new Date(e.timestamp).toLocaleString(), e.status];\n if (e.commitSha) parts.push(e.commitSha.slice(0, 8));\n return parts.join(\" · \");\n}\n\n/**\n * Compact run-over-run timeline for one scenario: a dot per recent run,\n * oldest → newest. Renders nothing outside <ReportInteractive> or when the\n * report was generated without --history-file — history is presentation-layer\n * data and never part of the StoryReport contract.\n */\nexport function ScenarioRunHistory({ scenarioId }: { scenarioId: string }) {\n const history = useScenarioHistory();\n const entries = history?.[scenarioId];\n if (!entries || entries.length < 2) return null; // one run = no timeline yet\n\n const recent = entries.slice(-MAX_DOTS);\n // Judge flakiness on the same window the dots show, so the badge never\n // contradicts the strip next to it.\n const flaky = flakinessOf(recent) === \"flaky\";\n const summary = flaky ? `${describeRunHistory(recent)} · Flaky` : describeRunHistory(recent);\n\n return (\n <>\n {flaky ? (\n <Badge variant=\"pending\" aria-label=\"Flaky: status flips between recent runs\" title={summary}>\n Flaky\n </Badge>\n ) : null}\n <span\n role=\"img\"\n aria-label={`Run history: ${summary}`}\n title={summary}\n className=\"flex shrink-0 items-center gap-[3px]\"\n >\n {recent.map((e, i) => (\n <span\n key={`${e.timestamp}-${i}`}\n aria-hidden\n title={dotTitle(e)}\n className={cn(\n \"inline-block size-1.5 rounded-full\",\n DOT_COLOR[e.status],\n // The newest run (rightmost dot) is the one the card's status\n // badge already describes; ring it so the timeline reads as\n // \"…leading up to now\".\n i === recent.length - 1 && \"ring-1 ring-border ring-offset-1 ring-offset-card\",\n )}\n />\n ))}\n </span>\n </>\n );\n}\n","\"use client\";\n\nimport { createContext, useCallback, useContext, useState } from \"react\";\n\nexport interface CollapseApi {\n isCollapsed: (id: string) => boolean;\n toggle: (id: string) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (the static <Report/>\n * render, Storybook, Astro), components render fully expanded with no toggle\n * affordance — so the static path and component-tier tests are unaffected.\n */\nconst CollapseContext = createContext<CollapseApi | null>(null);\n\nexport const CollapseProvider = CollapseContext.Provider;\n\nexport function useCollapse(): CollapseApi | null {\n return useContext(CollapseContext);\n}\n\nconst STORAGE_KEY = \"es-collapsed-ids\";\n\nfunction readPersisted(): Set<string> {\n if (typeof localStorage === \"undefined\") return new Set();\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n return raw ? new Set(JSON.parse(raw) as string[]) : new Set();\n } catch {\n return new Set();\n }\n}\n\nfunction persist(ids: Set<string>): void {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify([...ids]));\n } catch {\n /* quota / disabled — collapse still works for the session */\n }\n}\n\n/**\n * Collapse state for the interactive report: a persisted set of collapsed\n * feature/scenario ids, plus expand-all / collapse-all.\n */\nexport function useCollapseState() {\n const [collapsed, setCollapsed] = useState<Set<string>>(readPersisted);\n\n const isCollapsed = useCallback((id: string) => collapsed.has(id), [collapsed]);\n\n const toggle = useCallback((id: string) => {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n persist(next);\n return next;\n });\n }, []);\n\n const collapseAll = useCallback((ids: string[]) => {\n setCollapsed(() => {\n const next = new Set(ids);\n persist(next);\n return next;\n });\n }, []);\n\n const expandAll = useCallback(() => {\n setCollapsed(() => {\n const next = new Set<string>();\n persist(next);\n return next;\n });\n }, []);\n\n return { api: { isCollapsed, toggle } as CollapseApi, collapseAll, expandAll };\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { ReportScenario } from \"executable-stories-core\";\n\nexport interface ScenarioActions {\n copyLink: (scenario: ReportScenario) => void;\n copyMarkdown: (scenario: ReportScenario) => void;\n copyPrompt: (scenario: ReportScenario) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (static render), scenarios\n * show no per-scenario action buttons.\n */\nconst ScenarioActionsContext = createContext<ScenarioActions | null>(null);\nexport const ScenarioActionsProvider = ScenarioActionsContext.Provider;\nexport function useScenarioActions(): ScenarioActions | null {\n return useContext(ScenarioActionsContext);\n}\n\n/** A scenario rendered as Markdown — for pasting into PRs / issues / docs. */\nexport function scenarioToMarkdown(scenario: ReportScenario): string {\n const lines: string[] = [`## ${scenario.title} _(${scenario.status})_`, \"\"];\n for (const step of scenario.steps) {\n lines.push(`- **${step.keyword}** ${step.text}`);\n }\n if (scenario.errorMessage) {\n lines.push(\"\", \"```\", scenario.errorMessage.trim(), \"```\");\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * A failed scenario rendered as an investigation prompt for an AI agent — the\n * \"cheap to verify\" loop: hand the agent the failing behaviour + error verbatim.\n */\nexport function scenarioToPrompt(scenario: ReportScenario): string {\n const lines: string[] = [\n `A test scenario is ${scenario.status}. Investigate the likely cause and propose a fix.`,\n \"\",\n `Scenario: ${scenario.title}`,\n \"Steps:\",\n ];\n for (const step of scenario.steps) {\n const mark = step.status === \"failed\" ? \" ⟵ failed here\" : \"\";\n lines.push(` ${step.keyword} ${step.text}${mark}`);\n }\n if (scenario.errorMessage) {\n lines.push(\"\", \"Error:\", scenario.errorMessage.trim());\n }\n if (scenario.errorStack) {\n lines.push(\"\", \"Stack:\", scenario.errorStack.trim());\n }\n return lines.join(\"\\n\");\n}\n\n/** Absolute permalink to a scenario in the current document. */\nexport function scenarioPermalink(scenario: ReportScenario): string {\n if (typeof location === \"undefined\") return `#${scenario.id}`;\n return `${location.href.split(\"#\")[0]}#${scenario.id}`;\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card\"\n className={cn(\n \"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-6\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","import type { ReportScenario as ReportScenarioT } from \"executable-stories-core\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { ReportSteps } from \"./ReportSteps\";\nimport { ReportDocEntries } from \"./ReportDocEntries\";\nimport { ReportAttachments } from \"./ReportAttachments\";\nimport { ReportTrace } from \"./ReportTrace\";\nimport { ScenarioRunHistory } from \"./ScenarioRunHistory\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { useScenarioActions } from \"../interactive/scenario-actions\";\nimport { Card, CardContent, CardHeader } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportScenarioProps {\n scenario: ReportScenarioT;\n /**\n * Omit the card's own title row (status badge + tags still render). Use when\n * the surrounding page already shows the scenario title as its heading — e.g.\n * the Astro detail page, where Starlight renders the title as the page `h1`.\n */\n hideTitle?: boolean;\n}\n\ntype Status = ReportScenarioT[\"status\"];\n\nconst STATUS_LABEL: Record<Status, string> = {\n passed: \"Passed\",\n failed: \"Failed\",\n skipped: \"Skipped\",\n pending: \"Pending\",\n};\n\nconst STATUS_GLYPH: Record<Status, string> = {\n passed: \"✓\",\n failed: \"✗\",\n skipped: \"○\",\n pending: \"○\",\n};\n\nconst STATUS_GLYPH_COLOR: Record<Status, string> = {\n passed: \"text-pass\",\n failed: \"text-fail\",\n skipped: \"text-skip\",\n pending: \"text-pend\",\n};\n\nconst STATUS_BADGE: Record<Status, \"passed\" | \"failed\" | \"skipped\" | \"pending\"> = {\n passed: \"passed\",\n failed: \"failed\",\n skipped: \"skipped\",\n pending: \"pending\",\n};\n\nexport function ReportScenario({ scenario, hideTitle = false }: ReportScenarioProps) {\n const titleId = `${scenario.id}-title`;\n const bodyId = `${scenario.id}-body`;\n // A planned scenario (it.todo) is canonically \"pending\", but the reader\n // should see intent, not limbo.\n const label = scenario.planned ? \"Planned\" : STATUS_LABEL[scenario.status];\n const collapse = useCollapse();\n const collapsible = collapse !== null && !hideTitle;\n const collapsed = collapsible ? collapse!.isCollapsed(scenario.id) : false;\n const actions = useScenarioActions();\n return (\n <Card\n id={scenario.id}\n data-status={scenario.status}\n {...(hideTitle\n ? { \"aria-label\": `${scenario.title} — ${label}` }\n : { \"aria-labelledby\": titleId })}\n className=\"gap-0 py-0\"\n >\n <CardHeader className=\"px-4 py-3\">\n <div className={cn(\"flex items-start gap-4\", hideTitle ? \"justify-end\" : \"justify-between\")}>\n {hideTitle ? null : (\n <h3 id={titleId} className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n {collapsible ? (\n <button\n type=\"button\"\n onClick={() => collapse!.toggle(scenario.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n aria-label={`Toggle ${scenario.title}`}\n className=\"shrink-0 cursor-pointer text-muted-foreground hover:text-foreground\"\n >\n <span aria-hidden className={cn(\"inline-block text-xs transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n </button>\n ) : null}\n <span aria-hidden className={cn(\"text-sm leading-none\", STATUS_GLYPH_COLOR[scenario.status])}>\n {STATUS_GLYPH[scenario.status]}\n </span>\n <span>{scenario.title}</span>\n </h3>\n )}\n <div className=\"flex shrink-0 items-center gap-2\">\n <ScenarioRunHistory scenarioId={scenario.id} />\n {scenario.durationMs > 0 ? (\n <span className=\"whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(scenario.durationMs)}\n </span>\n ) : null}\n <Badge variant={STATUS_BADGE[scenario.status]} aria-label={`Status: ${label}`}>\n {label}\n </Badge>\n {actions ? (\n <div className=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n onClick={() => actions.copyLink(scenario)}\n aria-label={`Copy link to ${scenario.title}`}\n title=\"Copy permalink\"\n className=\"cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n link\n </button>\n <button\n type=\"button\"\n onClick={() => actions.copyMarkdown(scenario)}\n aria-label={`Copy ${scenario.title} as Markdown`}\n title=\"Copy as Markdown\"\n className=\"cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n md\n </button>\n <button\n type=\"button\"\n onClick={() => actions.copyPrompt(scenario)}\n aria-label={`Copy ${scenario.title} as an AI investigation prompt`}\n title=\"Copy as AI prompt\"\n className=\"cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n ai\n </button>\n </div>\n ) : null}\n </div>\n </div>\n {scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? (\n <ul aria-label=\"Tags and tickets\" className=\"flex flex-wrap gap-1.5\">\n {scenario.tags.map((t) => (\n <li key={`tag-${t}`}>\n <Badge variant=\"tag\">{t}</Badge>\n </li>\n ))}\n {(scenario.tickets ?? []).map((ticket) => (\n <li key={`ticket-${ticket.id}`}>\n {ticket.url ? (\n <a href={ticket.url} target=\"_blank\" rel=\"noreferrer noopener\">\n <Badge variant=\"outline\">{ticket.id}</Badge>\n </a>\n ) : (\n <Badge variant=\"outline\">{ticket.id}</Badge>\n )}\n </li>\n ))}\n </ul>\n ) : null}\n </CardHeader>\n <CardContent id={bodyId} hidden={collapsed} className=\"px-4 pt-0 pb-4\">\n {scenario.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mb-1 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {scenario.errorMessage}\n </pre>\n ) : null}\n <ReportSteps scenario={scenario} />\n {scenario.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-3\">\n <ReportDocEntries entries={scenario.docEntries} />\n </div>\n ) : null}\n <ReportAttachments attachments={scenario.attachments} />\n <ReportTrace spans={scenario.otelSpans} />\n </CardContent>\n </Card>\n );\n}\n","import type { ReportFeature } from \"executable-stories-core\";\nimport { ReportScenario } from \"./ReportScenario\";\n\nexport interface ReportScenarioListProps {\n feature: ReportFeature;\n}\n\nexport function ReportScenarioList({ feature }: ReportScenarioListProps) {\n return (\n <>\n {feature.scenarios.map((scenario) => (\n <ReportScenario key={scenario.id} scenario={scenario} />\n ))}\n </>\n );\n}\n","import type { ReportFeature as ReportFeatureT } from \"executable-stories-core\";\nimport { ReportScenarioList } from \"./ReportScenarioList\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportFeatureProps {\n feature: ReportFeatureT;\n}\n\n/**\n * Feature group — the report's `.feature` card: a header bar with the feature\n * title + mono source path and ✓/✗/○ status counts on the right, over a stack\n * of scenario cards. Kept a semantic <section> (a region), not a shadcn Card\n * div, so it stays a landmark and doesn't collide with the scenario cards'\n * `[data-slot=\"card\"]`.\n */\nexport function ReportFeature({ feature }: ReportFeatureProps) {\n const titleId = `${feature.id}-title`;\n const bodyId = `${feature.id}-body`;\n const s = feature.summary;\n const skipped = s.skipped + s.pending;\n const collapse = useCollapse();\n const collapsed = collapse?.isCollapsed(feature.id) ?? false;\n return (\n <section\n id={feature.id}\n data-slot=\"feature\"\n aria-labelledby={titleId}\n className=\"overflow-hidden rounded-xl border border-border bg-card shadow-sm\"\n >\n <div className=\"flex items-center justify-between gap-4 border-b border-border bg-muted/40 px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n {collapse ? (\n <button\n type=\"button\"\n onClick={() => collapse.toggle(feature.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n aria-label={`Toggle ${feature.title}`}\n className=\"shrink-0 cursor-pointer text-muted-foreground hover:text-foreground\"\n >\n <span aria-hidden className={cn(\"inline-block text-xs transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n </button>\n ) : null}\n <div className=\"min-w-0\">\n <h2 id={titleId} className=\"text-sm font-semibold tracking-tight text-foreground\">\n {feature.title}\n </h2>\n <p className=\"mt-0.5 truncate font-mono text-xs text-muted-foreground\">{feature.sourceFile}</p>\n </div>\n </div>\n <div\n role=\"img\"\n className=\"flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium\"\n aria-label={`${s.passed} passed, ${s.failed} failed, ${skipped} skipped`}\n >\n <span aria-hidden className=\"text-pass\">✓{s.passed}</span>\n <span aria-hidden className=\"text-fail\">✗{s.failed}</span>\n <span aria-hidden className=\"text-skip\">○{skipped}</span>\n </div>\n </div>\n <div id={bodyId} hidden={collapsed} className=\"flex flex-col gap-2 p-3\">\n <ReportScenarioList feature={feature} />\n </div>\n </section>\n );\n}\n","import { useReport } from \"../hooks/useReport\";\nimport { ReportFeature } from \"./ReportFeature\";\n\nexport function ReportFeatureList() {\n const report = useReport();\n return (\n <>\n {report.features.map((feature) => (\n <ReportFeature key={feature.id} feature={feature} />\n ))}\n </>\n );\n}\n","import { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Empty({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty\"\n className={cn(\n \"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-header\"\n className={cn(\n \"flex max-w-sm flex-col items-center gap-2 text-center\",\n className\n )}\n {...props}\n />\n )\n}\n\nconst emptyMediaVariants = cva(\n \"mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction EmptyMedia({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof emptyMediaVariants>) {\n return (\n <div\n data-slot=\"empty-icon\"\n data-variant={variant}\n className={cn(emptyMediaVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\nfunction EmptyTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-title\"\n className={cn(\"text-lg font-medium tracking-tight\", className)}\n {...props}\n />\n )\n}\n\nfunction EmptyDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <div\n data-slot=\"empty-description\"\n className={cn(\n \"text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-content\"\n className={cn(\n \"flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Empty,\n EmptyHeader,\n EmptyTitle,\n EmptyDescription,\n EmptyContent,\n EmptyMedia,\n}\n","import { Empty, EmptyHeader, EmptyTitle } from \"@/components/ui/empty\";\n\nexport interface ReportEmptyProps {\n message?: string;\n}\n\nexport function ReportEmpty({ message }: ReportEmptyProps) {\n return (\n <Empty aria-live=\"polite\" className=\"border\">\n <EmptyHeader>\n <EmptyTitle>{message ?? \"No scenarios in this report.\"}</EmptyTitle>\n </EmptyHeader>\n </Empty>\n );\n}\n","import type { ReportSummary as ReportSummaryT } from \"executable-stories-core\";\nimport { useReport } from \"../hooks/useReport\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportSummaryProps {\n className?: string;\n}\n\nexport function ReportSummary({ className }: ReportSummaryProps) {\n const report = useReport();\n return (\n <ReportSummaryView\n summary={report.summary}\n {...(className !== undefined && { className })}\n ariaLabel=\"Run summary\"\n />\n );\n}\n\nexport interface ReportSummaryViewProps {\n summary: ReportSummaryT;\n className?: string;\n ariaLabel?: string;\n}\n\nexport function ReportSummaryView({ summary, className, ariaLabel }: ReportSummaryViewProps) {\n return (\n <p className={cn(\"text-sm text-muted-foreground\", className)} aria-label={ariaLabel}>\n <span>\n <strong className=\"font-semibold text-foreground\">{summary.total}</strong> scenario\n {summary.total === 1 ? \"\" : \"s\"}\n </span>\n {\" · \"}\n <span data-status=\"passed\" className=\"text-pass\">{summary.passed} passed</span>\n {\" · \"}\n <span data-status=\"failed\" className=\"text-fail\">{summary.failed} failed</span>\n {summary.skipped > 0 ? (\n <>\n {\" · \"}\n <span data-status=\"skipped\" className=\"text-skip\">{summary.skipped} skipped</span>\n </>\n ) : null}\n {summary.pending > 0 ? (\n <>\n {\" · \"}\n <span data-status=\"pending\" className=\"text-pend\">{summary.pending} pending</span>\n </>\n ) : null}\n </p>\n );\n}\n","import type { StoryReport } from \"executable-stories-core\";\n\ntype ReportCI = NonNullable<StoryReport[\"ci\"]>;\n\n/**\n * Epoch ms of the run the report documents — the staleness reference.\n * Prefers finishedAtMs; falls back to startedAtMs for reports from adapters\n * that only stamp a start time.\n */\nexport function reportLastRunMs(\n report: Pick<StoryReport, \"startedAtMs\" | \"finishedAtMs\">,\n): number | undefined {\n if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;\n if (report.startedAtMs && report.startedAtMs > 0) return report.startedAtMs;\n return undefined;\n}\n\n/**\n * Human-readable age like \"just now\", \"5 minutes ago\", \"3 hours ago\",\n * \"12 days ago\". Clock skew (thenMs in the future) reads as \"just now\".\n */\nexport function formatRelativeAge(thenMs: number, nowMs: number): string {\n const deltaMs = Math.max(0, nowMs - thenMs);\n const minutes = Math.floor(deltaMs / 60_000);\n if (minutes < 1) return \"just now\";\n if (minutes < 60) return `${minutes} minute${minutes === 1 ? \"\" : \"s\"} ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours} hour${hours === 1 ? \"\" : \"s\"} ago`;\n const days = Math.floor(hours / 24);\n return `${days} day${days === 1 ? \"\" : \"s\"} ago`;\n}\n\n/**\n * A report is stale once its run is `staleAfterDays` or more days old.\n * A threshold of 0 (or negative) disables staleness entirely.\n */\nexport function isReportStale(\n lastRunMs: number | undefined,\n staleAfterDays: number,\n nowMs: number,\n): boolean {\n if (lastRunMs === undefined || staleAfterDays <= 0) return false;\n return nowMs - lastRunMs >= staleAfterDays * 86_400_000;\n}\n\n/**\n * StoryReport.ci.name carries the raw transport name — lowercase provider\n * keys (\"github\") from env detection, or a free-form string from older\n * adapters (\"GitHub Actions\"). Map the known keys to display names and pass\n * everything else through.\n */\nconst CI_DISPLAY_NAMES: Record<string, string> = {\n github: \"GitHub Actions\",\n gitlab: \"GitLab CI\",\n circleci: \"CircleCI\",\n jenkins: \"Jenkins\",\n azure: \"Azure DevOps\",\n buildkite: \"Buildkite\",\n travis: \"Travis CI\",\n ci: \"CI\",\n};\n\nexport function ciDisplayName(name: string): string {\n return CI_DISPLAY_NAMES[name] ?? name;\n}\n\n/**\n * Derive a browsable commit URL from the CI run URL, for the providers whose\n * URL structure makes that safe:\n * GitHub Actions …/owner/repo/actions/runs/123 -> …/owner/repo/commit/<sha>\n * GitLab CI …/group/project/-/pipelines/123 -> …/group/project/-/commit/<sha>\n * Other providers return undefined (a wrong link is worse than none).\n */\nexport function commitUrl(ci: ReportCI | undefined, sha: string | undefined): string | undefined {\n const commitSha = ci?.commitSha ?? sha;\n if (!ci?.url || !commitSha) return undefined;\n\n const github = ci.url.match(/^(https?:\\/\\/[^/]+\\/[^/]+\\/[^/]+)\\/actions\\/runs\\//);\n if (github) return `${github[1]}/commit/${commitSha}`;\n\n const gitlab = ci.url.match(/^(https?:\\/\\/.+)\\/-\\/pipelines\\//);\n if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;\n\n return undefined;\n}\n\n/**\n * Derive a pull-request URL for GitHub-shaped CI run URLs. GitLab and the\n * rest return undefined for the same wrong-link-is-worse-than-none reason.\n */\nexport function prUrl(ci: ReportCI | undefined): string | undefined {\n if (!ci?.url || !ci.prNumber) return undefined;\n const github = ci.url.match(/^(https?:\\/\\/[^/]+\\/[^/]+\\/[^/]+)\\/actions\\/runs\\//);\n if (github) return `${github[1]}/pull/${ci.prNumber}`;\n return undefined;\n}\n","import { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { useReport } from \"../hooks/useReport\";\nimport { ciDisplayName, commitUrl, prUrl } from \"../lib/provenance\";\n\n/**\n * Run metadata line (started, duration, version, branch, git SHA, CI, PR) —\n * the React equivalent of the report's `.meta-info` block. Reads the top-level\n * StoryReport fields from context. Commit and PR become links when the CI run\n * URL lets us derive them safely (GitHub/GitLab shapes only).\n */\nexport function ReportMeta() {\n const report = useReport();\n\n const items: Array<{ label: string; value: React.ReactNode }> = [];\n const linkClass = \"text-primary underline underline-offset-2\";\n\n if (report.startedAtMs) {\n items.push({ label: \"Started\", value: new Date(report.startedAtMs).toLocaleString() });\n }\n if (report.durationMs) {\n items.push({ label: \"Duration\", value: formatDuration(report.durationMs) });\n }\n if (report.packageVersion) {\n items.push({ label: \"Version\", value: report.packageVersion });\n }\n if (report.ci?.branch) {\n items.push({ label: \"Branch\", value: report.ci.branch });\n }\n const sha = report.ci?.commitSha ?? report.gitSha;\n if (sha) {\n const url = commitUrl(report.ci, report.gitSha);\n const short = sha.slice(0, 8);\n items.push({\n label: \"Commit\",\n value: url ? (\n <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {short}\n </a>\n ) : (\n short\n ),\n });\n }\n if (report.ci) {\n items.push({\n label: \"CI\",\n value: report.ci.url ? (\n <a href={report.ci.url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {ciDisplayName(report.ci.name)}\n {report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}\n </a>\n ) : (\n `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}`\n ),\n });\n }\n if (report.ci?.prNumber) {\n const url = prUrl(report.ci);\n const label = `#${report.ci.prNumber}`;\n items.push({\n label: \"PR\",\n value: url ? (\n <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {label}\n </a>\n ) : (\n label\n ),\n });\n }\n\n if (items.length === 0) return null;\n\n return (\n <dl aria-label=\"Run metadata\" className=\"flex flex-wrap gap-x-6 gap-y-1 text-xs text-muted-foreground\">\n {items.map((item) => (\n <div key={item.label} className=\"flex gap-1.5\">\n <dt className=\"font-medium\">{item.label}</dt>\n <dd className=\"font-mono text-foreground\">{item.value}</dd>\n </div>\n ))}\n </dl>\n );\n}\n","import type { ReportParseError } from \"../result\";\n\nexport interface ReportSchemaErrorProps {\n error: ReportParseError;\n}\n\nexport function ReportSchemaError({ error }: ReportSchemaErrorProps) {\n return (\n <section className=\"es-schema-error\" role=\"alert\" aria-live=\"assertive\">\n <p>\n <strong>Report could not be displayed.</strong>\n </p>\n <p>{error.message}</p>\n {error.code === \"SCHEMA_VERSION_MISMATCH\" ? (\n <p>\n The report bundle is newer than this version of <code>executable-stories-react</code>.\n Upgrade the package, or regenerate the report with an older formatters CLI.\n </p>\n ) : null}\n {error.issues && error.issues.length > 0 ? (\n <details>\n <summary>{error.issues.length} validation issue{error.issues.length === 1 ? \"\" : \"s\"}</summary>\n <pre>\n {error.issues\n .slice(0, 20)\n .map((i) => `${i.path}: ${i.message}`)\n .join(\"\\n\")}\n </pre>\n </details>\n ) : null}\n </section>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportParseError } from \"../result\";\nimport { cn } from \"../lib/utils\";\nimport { ReportSummary } from \"./ReportSummary\";\nimport { ReportMeta } from \"./ReportMeta\";\nimport { ReportSchemaError } from \"./ReportSchemaError\";\n\n/**\n * The report's title block — `<h1>` + summary + meta. Shared by the static\n * `Report` header and the interactive `ReportInteractive` header so the two\n * views can't drift on the no-JS fallback.\n */\nexport function ReportTitleBlock({ title }: { title?: string }) {\n return (\n <>\n <h1>{title ?? \"Story Report\"}</h1>\n <ReportSummary />\n <ReportMeta />\n </>\n );\n}\n\n/**\n * The `<main>` landmark shown when the report failed to parse. Both entrypoints\n * render the identical shell on a `Result` error, so it lives here once.\n */\nexport function ReportErrorShell({\n error,\n className,\n title,\n dataTheme,\n}: {\n error: ReportParseError;\n className?: string;\n title?: string;\n dataTheme?: \"light\" | \"dark\";\n}): ReactNode {\n return (\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <ReportSchemaError error={error} />\n </main>\n );\n}\n","import type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"../result\";\nimport { unwrapReport } from \"../result\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportRoot } from \"../context/ReportRoot\";\nimport { ReportFeatureList } from \"./ReportFeatureList\";\nimport { ReportEmpty } from \"./ReportEmpty\";\nimport { ReportTitleBlock, ReportErrorShell } from \"./ReportShell\";\nimport { cn } from \"../lib/utils\";\n\nexport interface ReportProps {\n /** A StoryReport, or a Result-wrapped one (e.g., from parseStoryReport). */\n report: StoryReport | Result<StoryReport>;\n /** Renderers keyed by `story.custom({ type })` strings. */\n customRenderers?: CustomRenderers;\n /** Optional overrides for the heavy built-ins (mermaid, code, section). */\n renderers?: BuiltinRenderers;\n /** Optional class on the <main> landmark for layout positioning. */\n className?: string;\n /** Optional override title. */\n title?: string;\n /** Optional theme attribute scope. Use to force \"light\" or \"dark\". */\n dataTheme?: \"light\" | \"dark\";\n}\n\nexport function Report(props: ReportProps) {\n const { report, customRenderers, renderers, className, title, dataTheme } = props;\n const result = unwrapReport(report);\n if (!result.ok) {\n return <ReportErrorShell error={result.error} className={className} title={title} dataTheme={dataTheme} />;\n }\n const data = result.data;\n const hasContent = data.features.length > 0;\n return (\n <ReportRoot report={data} customRenderers={customRenderers} renderers={renderers}>\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <header className=\"es-report-header\">\n <ReportTitleBlock title={title} />\n </header>\n {hasContent ? <ReportFeatureList /> : <ReportEmpty />}\n </main>\n </ReportRoot>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","EMPTY_CUSTOM","EMPTY_RENDERERS","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","React","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_class_variance_authority","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|