executable-stories-react 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@
2
2
 
3
3
  // src/interactive/ReportInteractive.tsx
4
4
  import { Monitor, Moon, Sun } from "lucide-react";
5
+ import { useTools } from "webmcpable/react";
5
6
  import {
6
7
  useCallback as useCallback5,
7
8
  useDeferredValue,
@@ -2068,9 +2069,69 @@ function listFailures(report) {
2068
2069
  return out;
2069
2070
  }
2070
2071
 
2072
+ // src/interactive/ReportAgentFilterNotice.tsx
2073
+ import { Bot, X } from "lucide-react";
2074
+ import { Fragment as Fragment11, jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
2075
+ function ReportAgentFilterNotice({
2076
+ applied,
2077
+ onReset,
2078
+ onDismiss
2079
+ }) {
2080
+ const terms = [];
2081
+ if (applied.search) terms.push(`matching \u201C${applied.search}\u201D`);
2082
+ if (applied.status !== "all") terms.push(applied.status);
2083
+ if (applied.tags.length > 0) terms.push(applied.tags.join(", "));
2084
+ return /* @__PURE__ */ jsxs25(
2085
+ "div",
2086
+ {
2087
+ role: "status",
2088
+ "aria-live": "polite",
2089
+ className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-md border border-primary/40 bg-primary/5 px-3 py-2 text-sm",
2090
+ children: [
2091
+ /* @__PURE__ */ jsx39(Bot, { "aria-hidden": true, className: "size-4 shrink-0 text-primary" }),
2092
+ /* @__PURE__ */ jsxs25("span", { className: "min-w-0 flex-1", children: [
2093
+ "An agent filtered this report",
2094
+ terms.length > 0 ? /* @__PURE__ */ jsxs25(Fragment11, { children: [
2095
+ " to ",
2096
+ terms.join(" \xB7 ")
2097
+ ] }) : null,
2098
+ " \u2014",
2099
+ " ",
2100
+ /* @__PURE__ */ jsxs25("span", { className: "tabular-nums", children: [
2101
+ applied.matched,
2102
+ " of ",
2103
+ applied.total,
2104
+ " scenarios"
2105
+ ] }),
2106
+ "."
2107
+ ] }),
2108
+ /* @__PURE__ */ jsx39(
2109
+ "button",
2110
+ {
2111
+ type: "button",
2112
+ onClick: onReset,
2113
+ className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs hover:bg-muted",
2114
+ children: "Show all"
2115
+ }
2116
+ ),
2117
+ /* @__PURE__ */ jsx39(
2118
+ "button",
2119
+ {
2120
+ type: "button",
2121
+ onClick: onDismiss,
2122
+ "aria-label": "Dismiss",
2123
+ className: "cursor-pointer rounded-md p-1 text-muted-foreground hover:text-foreground",
2124
+ children: /* @__PURE__ */ jsx39(X, { "aria-hidden": true, className: "size-4" })
2125
+ }
2126
+ )
2127
+ ]
2128
+ }
2129
+ );
2130
+ }
2131
+
2071
2132
  // src/interactive/ReportFailureBanner.tsx
2072
2133
  import { useCallback as useCallback2 } from "react";
2073
- import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
2134
+ import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
2074
2135
  function ReportFailureBanner({ failures }) {
2075
2136
  const first = failures[0];
2076
2137
  const jumpToFirst = useCallback2(() => {
@@ -2078,7 +2139,7 @@ function ReportFailureBanner({ failures }) {
2078
2139
  scrollToScenarioId(first.scenarioId);
2079
2140
  }, [first]);
2080
2141
  if (failures.length === 0) return null;
2081
- return /* @__PURE__ */ jsxs25(
2142
+ return /* @__PURE__ */ jsxs26(
2082
2143
  "div",
2083
2144
  {
2084
2145
  className: "es-failure-banner",
@@ -2086,13 +2147,13 @@ function ReportFailureBanner({ failures }) {
2086
2147
  "aria-live": "polite",
2087
2148
  "aria-label": "Failure summary",
2088
2149
  children: [
2089
- /* @__PURE__ */ jsxs25("span", { className: "es-failure-banner-text", children: [
2090
- /* @__PURE__ */ jsx39("strong", { children: failures.length }),
2150
+ /* @__PURE__ */ jsxs26("span", { className: "es-failure-banner-text", children: [
2151
+ /* @__PURE__ */ jsx40("strong", { children: failures.length }),
2091
2152
  " ",
2092
2153
  "failure",
2093
2154
  failures.length === 1 ? "" : "s"
2094
2155
  ] }),
2095
- /* @__PURE__ */ jsx39(
2156
+ /* @__PURE__ */ jsx40(
2096
2157
  "button",
2097
2158
  {
2098
2159
  type: "button",
@@ -2109,7 +2170,7 @@ function ReportFailureBanner({ failures }) {
2109
2170
 
2110
2171
  // src/interactive/ReportFilters.tsx
2111
2172
  import { useState as useState3 } from "react";
2112
- import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
2173
+ import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
2113
2174
  var TAG_LIMIT = 12;
2114
2175
  function ReportFilters({
2115
2176
  statuses,
@@ -2123,10 +2184,10 @@ function ReportFilters({
2123
2184
  if (statuses.length === 0 && tags.length === 0) return null;
2124
2185
  const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
2125
2186
  const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
2126
- return /* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2", children: [
2127
- statuses.length > 0 ? /* @__PURE__ */ jsx40("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2187
+ return /* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-2", children: [
2188
+ statuses.length > 0 ? /* @__PURE__ */ jsx41("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2128
2189
  const active = status === opt.key;
2129
- return /* @__PURE__ */ jsxs26(
2190
+ return /* @__PURE__ */ jsxs27(
2130
2191
  "button",
2131
2192
  {
2132
2193
  type: "button",
@@ -2138,23 +2199,23 @@ function ReportFilters({
2138
2199
  ),
2139
2200
  children: [
2140
2201
  opt.label,
2141
- /* @__PURE__ */ jsx40("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2202
+ /* @__PURE__ */ jsx41("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2142
2203
  ]
2143
2204
  },
2144
2205
  opt.key
2145
2206
  );
2146
2207
  }) }) : null,
2147
- tags.length > 0 ? /* @__PURE__ */ jsxs26("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2208
+ tags.length > 0 ? /* @__PURE__ */ jsxs27("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2148
2209
  visibleTags.map((tag) => {
2149
2210
  const active = activeTags.includes(tag);
2150
- return /* @__PURE__ */ jsx40("li", { children: /* @__PURE__ */ jsx40(
2211
+ return /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
2151
2212
  "button",
2152
2213
  {
2153
2214
  type: "button",
2154
2215
  "aria-pressed": active,
2155
2216
  onClick: () => onToggleTag(tag),
2156
2217
  className: "cursor-pointer",
2157
- children: /* @__PURE__ */ jsx40(
2218
+ children: /* @__PURE__ */ jsx41(
2158
2219
  Badge,
2159
2220
  {
2160
2221
  variant: "tag",
@@ -2167,7 +2228,7 @@ function ReportFilters({
2167
2228
  }
2168
2229
  ) }, tag);
2169
2230
  }),
2170
- tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx40("li", { children: /* @__PURE__ */ jsx40(
2231
+ tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
2171
2232
  "button",
2172
2233
  {
2173
2234
  type: "button",
@@ -2183,7 +2244,7 @@ function ReportFilters({
2183
2244
 
2184
2245
  // src/interactive/ReportFreshness.tsx
2185
2246
  import { useEffect as useEffect2, useState as useState4 } from "react";
2186
- import { Fragment as Fragment11, jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
2247
+ import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2187
2248
  function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2188
2249
  const [now, setNow] = useState4(nowMs);
2189
2250
  useEffect2(() => {
@@ -2191,7 +2252,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2191
2252
  }, [nowMs]);
2192
2253
  if (lastRunMs === void 0 || now === void 0) return null;
2193
2254
  const age = formatRelativeAge(lastRunMs, now);
2194
- const runLink = ciUrl ? /* @__PURE__ */ jsx41(
2255
+ const runLink = ciUrl ? /* @__PURE__ */ jsx42(
2195
2256
  "a",
2196
2257
  {
2197
2258
  href: ciUrl,
@@ -2202,9 +2263,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2202
2263
  }
2203
2264
  ) : null;
2204
2265
  if (isReportStale(lastRunMs, staleAfterDays, now)) {
2205
- return /* @__PURE__ */ jsxs27("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
2206
- /* @__PURE__ */ jsxs27("span", { children: [
2207
- /* @__PURE__ */ jsxs27("strong", { children: [
2266
+ return /* @__PURE__ */ jsxs28("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
2267
+ /* @__PURE__ */ jsxs28("span", { children: [
2268
+ /* @__PURE__ */ jsxs28("strong", { children: [
2208
2269
  "Last verified ",
2209
2270
  age,
2210
2271
  "."
@@ -2214,10 +2275,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2214
2275
  runLink
2215
2276
  ] });
2216
2277
  }
2217
- return /* @__PURE__ */ jsxs27("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
2278
+ return /* @__PURE__ */ jsxs28("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
2218
2279
  "Verified ",
2219
2280
  age,
2220
- runLink ? /* @__PURE__ */ jsxs27(Fragment11, { children: [
2281
+ runLink ? /* @__PURE__ */ jsxs28(Fragment12, { children: [
2221
2282
  " \xB7 ",
2222
2283
  runLink
2223
2284
  ] }) : null
@@ -2225,15 +2286,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2225
2286
  }
2226
2287
 
2227
2288
  // src/interactive/ReportLastRunDelta.tsx
2228
- import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2289
+ import { Fragment as Fragment13, jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
2229
2290
  var MAX_LINKS = 5;
2230
2291
  function ScenarioLinks({ scenarios, tone }) {
2231
- return /* @__PURE__ */ jsxs28(Fragment12, { children: [
2232
- scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs28("span", { children: [
2292
+ return /* @__PURE__ */ jsxs29(Fragment13, { children: [
2293
+ scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs29("span", { children: [
2233
2294
  i > 0 ? ", " : "",
2234
- /* @__PURE__ */ jsx42("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2295
+ /* @__PURE__ */ jsx43("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2235
2296
  ] }, s.id)),
2236
- scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs28("span", { children: [
2297
+ scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs29("span", { children: [
2237
2298
  " and ",
2238
2299
  scenarios.length - MAX_LINKS,
2239
2300
  " more"
@@ -2250,23 +2311,23 @@ function ReportLastRunDelta({
2250
2311
  if (!delta) return null;
2251
2312
  const { newlyFailing, newlyPassing, added } = delta;
2252
2313
  if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
2253
- return /* @__PURE__ */ jsx42("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
2314
+ return /* @__PURE__ */ jsx43("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
2254
2315
  }
2255
- return /* @__PURE__ */ jsxs28("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
2256
- /* @__PURE__ */ jsx42("span", { className: "font-medium text-foreground", children: "Since last run:" }),
2257
- newlyFailing.length > 0 ? /* @__PURE__ */ jsxs28("span", { className: "ml-2 text-fail", children: [
2316
+ return /* @__PURE__ */ jsxs29("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
2317
+ /* @__PURE__ */ jsx43("span", { className: "font-medium text-foreground", children: "Since last run:" }),
2318
+ newlyFailing.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2 text-fail", children: [
2258
2319
  newlyFailing.length,
2259
2320
  " newly failing (",
2260
- /* @__PURE__ */ jsx42(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
2321
+ /* @__PURE__ */ jsx43(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
2261
2322
  ")"
2262
2323
  ] }) : null,
2263
- newlyPassing.length > 0 ? /* @__PURE__ */ jsxs28("span", { className: "ml-2 text-pass", children: [
2324
+ newlyPassing.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2 text-pass", children: [
2264
2325
  newlyPassing.length,
2265
2326
  " fixed (",
2266
- /* @__PURE__ */ jsx42(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
2327
+ /* @__PURE__ */ jsx43(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
2267
2328
  ")"
2268
2329
  ] }) : null,
2269
- added.length > 0 ? /* @__PURE__ */ jsxs28("span", { className: "ml-2", children: [
2330
+ added.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2", children: [
2270
2331
  added.length,
2271
2332
  " new"
2272
2333
  ] }) : null
@@ -2282,9 +2343,9 @@ import { Search } from "lucide-react";
2282
2343
 
2283
2344
  // src/components/ui/input.tsx
2284
2345
  import "react";
2285
- import { jsx as jsx43 } from "react/jsx-runtime";
2346
+ import { jsx as jsx44 } from "react/jsx-runtime";
2286
2347
  function Input({ className, type, ...props }) {
2287
- return /* @__PURE__ */ jsx43(
2348
+ return /* @__PURE__ */ jsx44(
2288
2349
  "input",
2289
2350
  {
2290
2351
  type,
@@ -2301,7 +2362,7 @@ function Input({ className, type, ...props }) {
2301
2362
  }
2302
2363
 
2303
2364
  // src/interactive/ReportSearch.tsx
2304
- import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2365
+ import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
2305
2366
  var ReportSearch = forwardRef(
2306
2367
  function ReportSearch2(props, ref) {
2307
2368
  const {
@@ -2323,17 +2384,17 @@ var ReportSearch = forwardRef(
2323
2384
  e.preventDefault();
2324
2385
  }
2325
2386
  }
2326
- return /* @__PURE__ */ jsxs29("div", { className: cn("es-search flex flex-col gap-1", className), children: [
2327
- /* @__PURE__ */ jsx44("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
2328
- /* @__PURE__ */ jsxs29("div", { className: "relative w-full sm:w-72", children: [
2329
- /* @__PURE__ */ jsx44(
2387
+ return /* @__PURE__ */ jsxs30("div", { className: cn("es-search flex flex-col gap-1", className), children: [
2388
+ /* @__PURE__ */ jsx45("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
2389
+ /* @__PURE__ */ jsxs30("div", { className: "relative w-full sm:w-72", children: [
2390
+ /* @__PURE__ */ jsx45(
2330
2391
  Search,
2331
2392
  {
2332
2393
  "aria-hidden": true,
2333
2394
  className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
2334
2395
  }
2335
2396
  ),
2336
- /* @__PURE__ */ jsx44(
2397
+ /* @__PURE__ */ jsx45(
2337
2398
  Input,
2338
2399
  {
2339
2400
  ref,
@@ -2350,7 +2411,7 @@ var ReportSearch = forwardRef(
2350
2411
  }
2351
2412
  )
2352
2413
  ] }),
2353
- showCounts ? /* @__PURE__ */ jsxs29(
2414
+ showCounts ? /* @__PURE__ */ jsxs30(
2354
2415
  "span",
2355
2416
  {
2356
2417
  className: "text-xs tabular-nums text-muted-foreground",
@@ -2424,7 +2485,7 @@ function Button({
2424
2485
  }
2425
2486
 
2426
2487
  // src/interactive/ReportShortcutsHelp.tsx
2427
- import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
2488
+ import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2428
2489
  var SHORTCUTS = [
2429
2490
  { keys: "/", description: "Focus search" },
2430
2491
  { keys: "f", description: "Jump to next failure" },
@@ -2436,9 +2497,9 @@ var SHORTCUTS = [
2436
2497
  ];
2437
2498
  function Keys({ keys }) {
2438
2499
  const parts = keys.split(" ");
2439
- return /* @__PURE__ */ jsx45("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs30("span", { className: "inline-flex items-center gap-1", children: [
2440
- i > 0 ? /* @__PURE__ */ jsx45("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2441
- /* @__PURE__ */ jsx45("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2500
+ return /* @__PURE__ */ jsx46("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs31("span", { className: "inline-flex items-center gap-1", children: [
2501
+ i > 0 ? /* @__PURE__ */ jsx46("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2502
+ /* @__PURE__ */ jsx46("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2442
2503
  ] }, k)) });
2443
2504
  }
2444
2505
  function ReportShortcutsHelp({ open, onClose }) {
@@ -2449,7 +2510,7 @@ function ReportShortcutsHelp({ open, onClose }) {
2449
2510
  if (open && !dialog.open) dialog.showModal();
2450
2511
  else if (!open && dialog.open) dialog.close();
2451
2512
  }, [open]);
2452
- return /* @__PURE__ */ jsxs30(
2513
+ return /* @__PURE__ */ jsxs31(
2453
2514
  "dialog",
2454
2515
  {
2455
2516
  ref: dialogRef,
@@ -2457,12 +2518,12 @@ function ReportShortcutsHelp({ open, onClose }) {
2457
2518
  "aria-label": "Keyboard shortcuts",
2458
2519
  onClose,
2459
2520
  children: [
2460
- /* @__PURE__ */ jsx45("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2461
- /* @__PURE__ */ jsx45("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs30("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2462
- /* @__PURE__ */ jsx45("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx45(Keys, { keys: s.keys }) }),
2463
- /* @__PURE__ */ jsx45("dd", { className: "text-sm text-muted-foreground", children: s.description })
2521
+ /* @__PURE__ */ jsx46("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2522
+ /* @__PURE__ */ jsx46("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs31("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2523
+ /* @__PURE__ */ jsx46("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx46(Keys, { keys: s.keys }) }),
2524
+ /* @__PURE__ */ jsx46("dd", { className: "text-sm text-muted-foreground", children: s.description })
2464
2525
  ] }, s.keys)) }),
2465
- /* @__PURE__ */ jsx45("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx45(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2526
+ /* @__PURE__ */ jsx46("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx46(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2466
2527
  ]
2467
2528
  }
2468
2529
  );
@@ -2470,7 +2531,7 @@ function ReportShortcutsHelp({ open, onClose }) {
2470
2531
 
2471
2532
  // src/interactive/ReportToc.tsx
2472
2533
  import { useEffect as useEffect4, useMemo as useMemo2, useState as useState5 } from "react";
2473
- import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2534
+ import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2474
2535
  var DOT = {
2475
2536
  passed: "bg-pass",
2476
2537
  failed: "bg-fail",
@@ -2499,11 +2560,11 @@ function TocContent({ onNavigate }) {
2499
2560
  return () => observer.disconnect();
2500
2561
  }, [scenarioIds]);
2501
2562
  if (report.features.length === 0) return null;
2502
- return /* @__PURE__ */ jsx46("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs31("li", { children: [
2503
- /* @__PURE__ */ jsx46("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2504
- /* @__PURE__ */ jsx46("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2563
+ return /* @__PURE__ */ jsx47("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs32("li", { children: [
2564
+ /* @__PURE__ */ jsx47("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2565
+ /* @__PURE__ */ jsx47("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2505
2566
  const active = activeId === scenario.id;
2506
- return /* @__PURE__ */ jsx46("li", { children: /* @__PURE__ */ jsxs31(
2567
+ return /* @__PURE__ */ jsx47("li", { children: /* @__PURE__ */ jsxs32(
2507
2568
  "a",
2508
2569
  {
2509
2570
  href: `#${scenario.id}`,
@@ -2518,14 +2579,14 @@ function TocContent({ onNavigate }) {
2518
2579
  active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
2519
2580
  ),
2520
2581
  children: [
2521
- /* @__PURE__ */ jsx46(
2582
+ /* @__PURE__ */ jsx47(
2522
2583
  "span",
2523
2584
  {
2524
2585
  "aria-hidden": true,
2525
2586
  className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
2526
2587
  }
2527
2588
  ),
2528
- /* @__PURE__ */ jsx46("span", { className: "break-words", children: scenario.title })
2589
+ /* @__PURE__ */ jsx47("span", { className: "break-words", children: scenario.title })
2529
2590
  ]
2530
2591
  }
2531
2592
  ) }, scenario.id);
@@ -2535,14 +2596,14 @@ function TocContent({ onNavigate }) {
2535
2596
  function ReportToc() {
2536
2597
  const report = useReport();
2537
2598
  if (report.features.length === 0) return null;
2538
- return /* @__PURE__ */ jsxs31(
2599
+ return /* @__PURE__ */ jsxs32(
2539
2600
  "nav",
2540
2601
  {
2541
2602
  "aria-label": "Table of contents",
2542
2603
  className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
2543
2604
  children: [
2544
- /* @__PURE__ */ jsx46("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2545
- /* @__PURE__ */ jsx46(TocContent, {})
2605
+ /* @__PURE__ */ jsx47("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2606
+ /* @__PURE__ */ jsx47(TocContent, {})
2546
2607
  ]
2547
2608
  }
2548
2609
  );
@@ -2552,31 +2613,31 @@ function ReportToc() {
2552
2613
  import { useState as useState6 } from "react";
2553
2614
  import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
2554
2615
  import { ListIcon, XIcon } from "lucide-react";
2555
- import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2616
+ import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2556
2617
  function ReportTocDrawer() {
2557
2618
  const report = useReport();
2558
2619
  const [open, setOpen] = useState6(false);
2559
2620
  if (report.features.length === 0) return null;
2560
- return /* @__PURE__ */ jsxs32(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
2561
- /* @__PURE__ */ jsxs32(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2562
- /* @__PURE__ */ jsx47(ListIcon, { "aria-hidden": true }),
2621
+ return /* @__PURE__ */ jsxs33(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
2622
+ /* @__PURE__ */ jsxs33(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2623
+ /* @__PURE__ */ jsx48(ListIcon, { "aria-hidden": true }),
2563
2624
  " Contents"
2564
2625
  ] }),
2565
- /* @__PURE__ */ jsxs32(DialogPrimitive.Portal, { children: [
2566
- /* @__PURE__ */ jsx47(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2567
- /* @__PURE__ */ jsxs32(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2568
- /* @__PURE__ */ jsxs32("div", { className: "flex items-center justify-between", children: [
2569
- /* @__PURE__ */ jsx47(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2570
- /* @__PURE__ */ jsx47(
2626
+ /* @__PURE__ */ jsxs33(DialogPrimitive.Portal, { children: [
2627
+ /* @__PURE__ */ jsx48(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2628
+ /* @__PURE__ */ jsxs33(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2629
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between", children: [
2630
+ /* @__PURE__ */ jsx48(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2631
+ /* @__PURE__ */ jsx48(
2571
2632
  DialogPrimitive.Close,
2572
2633
  {
2573
2634
  "aria-label": "Close contents",
2574
2635
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
2575
- children: /* @__PURE__ */ jsx47(XIcon, { "aria-hidden": true })
2636
+ children: /* @__PURE__ */ jsx48(XIcon, { "aria-hidden": true })
2576
2637
  }
2577
2638
  )
2578
2639
  ] }),
2579
- /* @__PURE__ */ jsx47(TocContent, { onNavigate: () => setOpen(false) })
2640
+ /* @__PURE__ */ jsx48(TocContent, { onNavigate: () => setOpen(false) })
2580
2641
  ] })
2581
2642
  ] })
2582
2643
  ] });
@@ -2759,13 +2820,233 @@ function useUrlState() {
2759
2820
  return [state, update];
2760
2821
  }
2761
2822
 
2823
+ // src/interactive/webmcp-tools.ts
2824
+ import {
2825
+ getFeatureSummary,
2826
+ getScenario,
2827
+ listScenarioSummaries,
2828
+ runProvenance,
2829
+ toScenarioSummary
2830
+ } from "executable-stories-core/report-queries";
2831
+ var STATUSES2 = [
2832
+ "passed",
2833
+ "failed",
2834
+ "skipped",
2835
+ "pending"
2836
+ ];
2837
+ var VIEW_STATUSES = ["all", ...STATUSES2];
2838
+ var ToolArgumentError = class extends Error {
2839
+ };
2840
+ function asRecord(input) {
2841
+ return typeof input === "object" && input !== null ? input : {};
2842
+ }
2843
+ function readString(input, key) {
2844
+ const value = input[key];
2845
+ if (value === void 0 || value === null) return void 0;
2846
+ if (typeof value !== "string") {
2847
+ throw new ToolArgumentError(`"${key}" must be a string, received ${typeof value}.`);
2848
+ }
2849
+ return value;
2850
+ }
2851
+ function readStringArray(input, key) {
2852
+ const value = input[key];
2853
+ if (value === void 0 || value === null) return void 0;
2854
+ if (typeof value === "string") return [value];
2855
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
2856
+ throw new ToolArgumentError(`"${key}" must be an array of strings.`);
2857
+ }
2858
+ return value;
2859
+ }
2860
+ function readEnum(input, key, allowed) {
2861
+ const value = readString(input, key);
2862
+ if (value === void 0) return void 0;
2863
+ if (!allowed.includes(value)) {
2864
+ throw new ToolArgumentError(
2865
+ `"${key}" must be one of: ${allowed.join(", ")}. Received "${value}".`
2866
+ );
2867
+ }
2868
+ return value;
2869
+ }
2870
+ function readStatuses(input) {
2871
+ const values = readStringArray(input, "statuses");
2872
+ if (values === void 0) return void 0;
2873
+ const invalid = values.filter((v) => !STATUSES2.includes(v));
2874
+ if (invalid.length > 0) {
2875
+ throw new ToolArgumentError(
2876
+ `"statuses" must contain only: ${STATUSES2.join(", ")}. Received "${invalid.join('", "')}".`
2877
+ );
2878
+ }
2879
+ return values;
2880
+ }
2881
+ function guarded(run) {
2882
+ try {
2883
+ return run();
2884
+ } catch (error) {
2885
+ if (error instanceof ToolArgumentError) return `Invalid input \u2014 ${error.message}`;
2886
+ throw error;
2887
+ }
2888
+ }
2889
+ var scenarioListSchema = {
2890
+ type: "object",
2891
+ properties: {
2892
+ statuses: {
2893
+ type: "array",
2894
+ items: { type: "string", enum: [...STATUSES2] },
2895
+ description: "Keep only scenarios with any of these statuses."
2896
+ },
2897
+ tags: {
2898
+ type: "array",
2899
+ items: { type: "string" },
2900
+ description: "Keep only scenarios carrying any of these tags."
2901
+ },
2902
+ sourceFiles: {
2903
+ type: "array",
2904
+ items: { type: "string" },
2905
+ description: "Keep only scenarios whose source file path contains any of these."
2906
+ }
2907
+ }
2908
+ };
2909
+ var READ_ONLY = { readOnlyHint: true, untrustedContentHint: true };
2910
+ function reportTools(deps) {
2911
+ const { report, setView, onAgentFilter } = deps;
2912
+ const now = deps.now ?? Date.now;
2913
+ const provenance = () => ({ run: runProvenance(report, now()) });
2914
+ const list = (filters) => {
2915
+ const scenarios = listScenarioSummaries(report, filters);
2916
+ return { ...provenance(), total: scenarios.length, scenarios };
2917
+ };
2918
+ return {
2919
+ list_scenarios: {
2920
+ title: "List scenarios",
2921
+ description: "List the behaviour scenarios in this report, optionally filtered by status, tag, or source file. Returns each scenario with its steps, tags, timing and failure message.",
2922
+ annotations: READ_ONLY,
2923
+ input: scenarioListSchema,
2924
+ execute: (input) => guarded(() => {
2925
+ const args = asRecord(input);
2926
+ const filters = {};
2927
+ const statuses = readStatuses(args);
2928
+ const tags = readStringArray(args, "tags");
2929
+ const sourceFiles = readStringArray(args, "sourceFiles");
2930
+ if (statuses) filters.statuses = statuses;
2931
+ if (tags) filters.tags = tags;
2932
+ if (sourceFiles) filters.sourceFiles = sourceFiles;
2933
+ return list(filters);
2934
+ })
2935
+ },
2936
+ get_failing_scenarios: {
2937
+ title: "Get failing scenarios",
2938
+ description: "List only the scenarios that failed in this run, each with the step that failed and its error message. Use this first when asked what is broken.",
2939
+ annotations: READ_ONLY,
2940
+ execute: () => list({ statuses: ["failed"] })
2941
+ },
2942
+ get_feature_summary: {
2943
+ title: "Get feature summary",
2944
+ description: 'Summarise each feature in the report with its scenario counts by status. Use this for "how are we doing" questions rather than listing every scenario.',
2945
+ annotations: READ_ONLY,
2946
+ execute: () => ({
2947
+ ...provenance(),
2948
+ summary: report.summary,
2949
+ features: getFeatureSummary(report)
2950
+ })
2951
+ },
2952
+ get_scenario: {
2953
+ title: "Get scenario",
2954
+ description: "Get one scenario by its id or its exact title, with every step and any failure detail. Attachment and document bodies are omitted \u2014 `docKinds` names what the page shows.",
2955
+ annotations: READ_ONLY,
2956
+ input: {
2957
+ type: "object",
2958
+ properties: {
2959
+ idOrTitle: {
2960
+ type: "string",
2961
+ description: "The scenario id, or its exact title as shown in the report."
2962
+ }
2963
+ },
2964
+ required: ["idOrTitle"]
2965
+ },
2966
+ execute: (input) => guarded(() => {
2967
+ const idOrTitle = readString(asRecord(input), "idOrTitle") ?? "";
2968
+ const found = getScenario(report, idOrTitle);
2969
+ if (!found) {
2970
+ return {
2971
+ ...provenance(),
2972
+ error: `No scenario found with id or title "${idOrTitle}". Call list_scenarios to see what this report contains.`
2973
+ };
2974
+ }
2975
+ return {
2976
+ ...provenance(),
2977
+ feature: {
2978
+ id: found.feature.id,
2979
+ title: found.feature.title,
2980
+ sourceFile: found.feature.sourceFile
2981
+ },
2982
+ // The summary projection, not the raw scenario: doc entry bodies and
2983
+ // base64 attachments are unbounded, and this payload goes straight
2984
+ // into a model's context window.
2985
+ scenario: toScenarioSummary(found.feature, found.scenario)
2986
+ };
2987
+ })
2988
+ },
2989
+ filter_scenarios: {
2990
+ title: "Filter the report",
2991
+ description: `Change what the reader is looking at: set the report's search text, status filter and tag filter. Omitted fields are left as they are; pass an empty string, "all", or an empty array to clear one.`,
2992
+ input: {
2993
+ type: "object",
2994
+ properties: {
2995
+ search: {
2996
+ type: "string",
2997
+ description: "Free text matched against scenario titles, tags and step text. Empty string clears it."
2998
+ },
2999
+ status: {
3000
+ type: "string",
3001
+ enum: [...VIEW_STATUSES],
3002
+ description: 'Show only scenarios with this status. "all" clears the filter.'
3003
+ },
3004
+ tags: {
3005
+ type: "array",
3006
+ items: { type: "string" },
3007
+ description: "Show only scenarios carrying any of these tags. Empty array clears the filter."
3008
+ }
3009
+ }
3010
+ },
3011
+ execute: (input) => guarded(() => {
3012
+ const args = asRecord(input);
3013
+ const search = readString(args, "search");
3014
+ const status = readEnum(args, "status", VIEW_STATUSES);
3015
+ const tags = readStringArray(args, "tags");
3016
+ const applied = {
3017
+ search: search ?? deps.view.query,
3018
+ status: status ?? deps.view.status,
3019
+ tags: tags ?? deps.view.tags
3020
+ };
3021
+ const patch = {};
3022
+ if (search !== void 0) patch.query = search;
3023
+ if (status !== void 0) patch.status = status;
3024
+ if (tags !== void 0) patch.tags = tags;
3025
+ setView(patch);
3026
+ const matched = filterReport(report, {
3027
+ query: applied.search,
3028
+ status: applied.status,
3029
+ tags: applied.tags
3030
+ }).summary.total;
3031
+ const result = {
3032
+ ...applied,
3033
+ matched,
3034
+ total: report.summary.total
3035
+ };
3036
+ onAgentFilter?.(result);
3037
+ return { ...provenance(), applied: result };
3038
+ })
3039
+ }
3040
+ };
3041
+ }
3042
+
2762
3043
  // src/interactive/ReportInteractive.tsx
2763
- import { Fragment as Fragment13, jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
3044
+ import { Fragment as Fragment14, jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2764
3045
  function ReportInteractive(props) {
2765
3046
  const { report, className, title, dataTheme } = props;
2766
3047
  const result = unwrapReport(report);
2767
3048
  if (!result.ok) {
2768
- return /* @__PURE__ */ jsx48(
3049
+ return /* @__PURE__ */ jsx49(
2769
3050
  ReportErrorShell,
2770
3051
  {
2771
3052
  error: result.error,
@@ -2775,7 +3056,7 @@ function ReportInteractive(props) {
2775
3056
  }
2776
3057
  );
2777
3058
  }
2778
- return /* @__PURE__ */ jsx48(ReportInteractiveView, { ...props, report: result.data });
3059
+ return /* @__PURE__ */ jsx49(ReportInteractiveView, { ...props, report: result.data });
2779
3060
  }
2780
3061
  var THEME_OPTIONS = [
2781
3062
  { value: "light", label: "Light", Icon: Sun },
@@ -2786,7 +3067,7 @@ function ThemeSegment({
2786
3067
  pref,
2787
3068
  onPref
2788
3069
  }) {
2789
- return /* @__PURE__ */ jsx48(
3070
+ return /* @__PURE__ */ jsx49(
2790
3071
  ToggleGroup,
2791
3072
  {
2792
3073
  size: "sm",
@@ -2796,14 +3077,14 @@ function ThemeSegment({
2796
3077
  if (next) onPref(next);
2797
3078
  },
2798
3079
  "aria-label": "Color theme",
2799
- children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx48(
3080
+ children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx49(
2800
3081
  ToggleGroupItem,
2801
3082
  {
2802
3083
  value,
2803
3084
  "aria-label": label,
2804
3085
  title: label,
2805
3086
  className: "px-2",
2806
- children: /* @__PURE__ */ jsx48(Icon, {})
3087
+ children: /* @__PURE__ */ jsx49(Icon, {})
2807
3088
  },
2808
3089
  value
2809
3090
  ))
@@ -2932,6 +3213,20 @@ function ReportInteractiveView({
2932
3213
  },
2933
3214
  [collapse, collapseAll]
2934
3215
  );
3216
+ const [agentFilter, setAgentFilter] = useState9(null);
3217
+ useTools(
3218
+ reportTools({
3219
+ report,
3220
+ view: urlState,
3221
+ setView: setUrlState,
3222
+ onAgentFilter: setAgentFilter
3223
+ })
3224
+ );
3225
+ const showAgentFilter = agentFilter !== null && agentFilter.search === query && agentFilter.status === statusFilter && agentFilter.tags.length === activeTags.length && agentFilter.tags.every((tag) => activeTags.includes(tag));
3226
+ const clearFilters = useCallback5(
3227
+ () => setUrlState({ query: "", status: "all", tags: [] }),
3228
+ [setUrlState]
3229
+ );
2935
3230
  const focusSearch = useCallback5(() => {
2936
3231
  searchRef.current?.focus();
2937
3232
  }, []);
@@ -2965,13 +3260,13 @@ function ReportInteractiveView({
2965
3260
  const totalScenarios = report.summary.total;
2966
3261
  const matchedScenarios = filtered.summary.total;
2967
3262
  const showToc = !hideToc && totalScenarios > 3;
2968
- return /* @__PURE__ */ jsx48(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ jsx48(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx48(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx48(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ jsx48(
3263
+ return /* @__PURE__ */ jsx49(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ jsx49(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx49(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx49(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ jsx49(
2969
3264
  ReportRoot,
2970
3265
  {
2971
3266
  report: filtered,
2972
3267
  customRenderers,
2973
3268
  renderers,
2974
- children: /* @__PURE__ */ jsxs33(
3269
+ children: /* @__PURE__ */ jsxs34(
2975
3270
  "main",
2976
3271
  {
2977
3272
  className: cn("es-report", "es-report-interactive", className),
@@ -2980,8 +3275,8 @@ function ReportInteractiveView({
2980
3275
  "data-theme": dataTheme,
2981
3276
  "data-detail-level": detail,
2982
3277
  children: [
2983
- /* @__PURE__ */ jsxs33("header", { className: "es-report-header", children: [
2984
- /* @__PURE__ */ jsxs33(
3278
+ /* @__PURE__ */ jsxs34("header", { className: "es-report-header", children: [
3279
+ /* @__PURE__ */ jsxs34(
2985
3280
  "div",
2986
3281
  {
2987
3282
  "data-es-navbar": true,
@@ -2990,9 +3285,9 @@ function ReportInteractiveView({
2990
3285
  hideHeader ? "justify-end" : "justify-between"
2991
3286
  ),
2992
3287
  children: [
2993
- hideHeader ? null : /* @__PURE__ */ jsx48("h1", { className: "min-w-0", children: title ?? "Story Report" }),
2994
- /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", children: [
2995
- /* @__PURE__ */ jsx48(
3288
+ hideHeader ? null : /* @__PURE__ */ jsx49("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3289
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", children: [
3290
+ /* @__PURE__ */ jsx49(
2996
3291
  ReportSearch,
2997
3292
  {
2998
3293
  ref: searchRef,
@@ -3002,16 +3297,16 @@ function ReportInteractiveView({
3002
3297
  totalCount: totalScenarios
3003
3298
  }
3004
3299
  ),
3005
- /* @__PURE__ */ jsx48(ThemeSegment, { pref: themePref, onPref: setThemePref })
3300
+ /* @__PURE__ */ jsx49(ThemeSegment, { pref: themePref, onPref: setThemePref })
3006
3301
  ] })
3007
3302
  ]
3008
3303
  }
3009
3304
  ),
3010
- hideHeader ? null : /* @__PURE__ */ jsxs33(Fragment13, { children: [
3011
- /* @__PURE__ */ jsx48(ReportSummary, {}),
3012
- /* @__PURE__ */ jsx48(ReportMeta, {})
3305
+ hideHeader ? null : /* @__PURE__ */ jsxs34(Fragment14, { children: [
3306
+ /* @__PURE__ */ jsx49(ReportSummary, {}),
3307
+ /* @__PURE__ */ jsx49(ReportMeta, {})
3013
3308
  ] }),
3014
- /* @__PURE__ */ jsx48(
3309
+ /* @__PURE__ */ jsx49(
3015
3310
  ReportFreshness,
3016
3311
  {
3017
3312
  lastRunMs: reportLastRunMs(report),
@@ -3019,14 +3314,14 @@ function ReportInteractiveView({
3019
3314
  staleAfterDays
3020
3315
  }
3021
3316
  ),
3022
- /* @__PURE__ */ jsx48(
3317
+ /* @__PURE__ */ jsx49(
3023
3318
  ReportLastRunDelta,
3024
3319
  {
3025
3320
  history: scenarioHistory,
3026
3321
  report
3027
3322
  }
3028
3323
  ),
3029
- /* @__PURE__ */ jsx48(
3324
+ /* @__PURE__ */ jsx49(
3030
3325
  ReportFilters,
3031
3326
  {
3032
3327
  statuses: statusOptions,
@@ -3037,10 +3332,10 @@ function ReportInteractiveView({
3037
3332
  onToggleTag: toggleTag
3038
3333
  }
3039
3334
  ),
3040
- /* @__PURE__ */ jsxs33("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3041
- showToc ? /* @__PURE__ */ jsx48(ReportTocDrawer, {}) : null,
3042
- /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", children: [
3043
- /* @__PURE__ */ jsx48(
3335
+ /* @__PURE__ */ jsxs34("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3336
+ showToc ? /* @__PURE__ */ jsx49(ReportTocDrawer, {}) : null,
3337
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", children: [
3338
+ /* @__PURE__ */ jsx49(
3044
3339
  Switch,
3045
3340
  {
3046
3341
  id: expandId,
@@ -3048,7 +3343,7 @@ function ReportInteractiveView({
3048
3343
  onCheckedChange: setExpanded
3049
3344
  }
3050
3345
  ),
3051
- /* @__PURE__ */ jsx48(
3346
+ /* @__PURE__ */ jsx49(
3052
3347
  "label",
3053
3348
  {
3054
3349
  htmlFor: expandId,
@@ -3057,8 +3352,8 @@ function ReportInteractiveView({
3057
3352
  }
3058
3353
  )
3059
3354
  ] }),
3060
- /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", children: [
3061
- /* @__PURE__ */ jsx48(
3355
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", children: [
3356
+ /* @__PURE__ */ jsx49(
3062
3357
  Switch,
3063
3358
  {
3064
3359
  id: docsId,
@@ -3066,7 +3361,7 @@ function ReportInteractiveView({
3066
3361
  onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
3067
3362
  }
3068
3363
  ),
3069
- /* @__PURE__ */ jsx48(
3364
+ /* @__PURE__ */ jsx49(
3070
3365
  "label",
3071
3366
  {
3072
3367
  htmlFor: docsId,
@@ -3077,17 +3372,25 @@ function ReportInteractiveView({
3077
3372
  ] })
3078
3373
  ] })
3079
3374
  ] }),
3080
- /* @__PURE__ */ jsx48(ReportFailureBanner, { failures }),
3081
- hasContent ? showToc ? /* @__PURE__ */ jsxs33("div", { className: "flex gap-6", children: [
3082
- /* @__PURE__ */ jsx48(ReportToc, {}),
3083
- /* @__PURE__ */ jsx48("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx48(ReportFeatureList, {}) })
3084
- ] }) : /* @__PURE__ */ jsx48("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx48(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx48(
3375
+ showAgentFilter ? /* @__PURE__ */ jsx49(
3376
+ ReportAgentFilterNotice,
3377
+ {
3378
+ applied: agentFilter,
3379
+ onReset: clearFilters,
3380
+ onDismiss: () => setAgentFilter(null)
3381
+ }
3382
+ ) : null,
3383
+ /* @__PURE__ */ jsx49(ReportFailureBanner, { failures }),
3384
+ hasContent ? showToc ? /* @__PURE__ */ jsxs34("div", { className: "flex gap-6", children: [
3385
+ /* @__PURE__ */ jsx49(ReportToc, {}),
3386
+ /* @__PURE__ */ jsx49("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx49(ReportFeatureList, {}) })
3387
+ ] }) : /* @__PURE__ */ jsx49("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx49(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx49(
3085
3388
  ReportEmpty,
3086
3389
  {
3087
3390
  message: query ? "No scenarios match the search." : void 0
3088
3391
  }
3089
3392
  ),
3090
- /* @__PURE__ */ jsx48(
3393
+ /* @__PURE__ */ jsx49(
3091
3394
  "button",
3092
3395
  {
3093
3396
  type: "button",
@@ -3098,14 +3401,14 @@ function ReportInteractiveView({
3098
3401
  children: "?"
3099
3402
  }
3100
3403
  ),
3101
- /* @__PURE__ */ jsx48(
3404
+ /* @__PURE__ */ jsx49(
3102
3405
  ReportShortcutsHelp,
3103
3406
  {
3104
3407
  open: helpOpen,
3105
3408
  onClose: () => setHelpOpen(false)
3106
3409
  }
3107
3410
  ),
3108
- toast ? /* @__PURE__ */ jsx48(
3411
+ toast ? /* @__PURE__ */ jsx49(
3109
3412
  "div",
3110
3413
  {
3111
3414
  role: "status",
@@ -3129,7 +3432,7 @@ import { createElement, useEffect as useEffect10, useState as useState11 } from
3129
3432
 
3130
3433
  // src/components/doc/MermaidView.tsx
3131
3434
  import { useEffect as useEffect9, useRef as useRef6, useState as useState10 } from "react";
3132
- import { Fragment as Fragment14, jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
3435
+ import { Fragment as Fragment15, jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
3133
3436
  function prefersDark(el) {
3134
3437
  const themed = el?.closest("[data-theme]");
3135
3438
  if (themed?.dataset.theme === "dark") return true;
@@ -3183,9 +3486,9 @@ function MermaidView({ entry, load }) {
3183
3486
  };
3184
3487
  }, [entry.code, load]);
3185
3488
  if (svg) {
3186
- return /* @__PURE__ */ jsxs34("figure", { ref, className: "my-3", children: [
3187
- entry.title ? /* @__PURE__ */ jsx49("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3188
- /* @__PURE__ */ jsx49(
3489
+ return /* @__PURE__ */ jsxs35("figure", { ref, className: "my-3", children: [
3490
+ entry.title ? /* @__PURE__ */ jsx50("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3491
+ /* @__PURE__ */ jsx50(
3189
3492
  "div",
3190
3493
  {
3191
3494
  role: "img",
@@ -3196,8 +3499,8 @@ function MermaidView({ entry, load }) {
3196
3499
  )
3197
3500
  ] });
3198
3501
  }
3199
- return /* @__PURE__ */ jsxs34(Fragment14, { children: [
3200
- error ? /* @__PURE__ */ jsxs34(
3502
+ return /* @__PURE__ */ jsxs35(Fragment15, { children: [
3503
+ error ? /* @__PURE__ */ jsxs35(
3201
3504
  "p",
3202
3505
  {
3203
3506
  role: "alert",
@@ -3209,12 +3512,12 @@ function MermaidView({ entry, load }) {
3209
3512
  ]
3210
3513
  }
3211
3514
  ) : null,
3212
- /* @__PURE__ */ jsx49(MermaidSource, { entry, ref })
3515
+ /* @__PURE__ */ jsx50(MermaidSource, { entry, ref })
3213
3516
  ] });
3214
3517
  }
3215
3518
 
3216
3519
  // src/interactive/island-renderers.tsx
3217
- import { jsx as jsx50 } from "react/jsx-runtime";
3520
+ import { jsx as jsx51 } from "react/jsx-runtime";
3218
3521
  var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
3219
3522
  var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
3220
3523
  function cachedCdnModule(url) {
@@ -3248,13 +3551,13 @@ function CdnHighlightedCode({ entry }) {
3248
3551
  cancelled = true;
3249
3552
  };
3250
3553
  }, [entry.content, entry.lang]);
3251
- return /* @__PURE__ */ jsx50(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx50(
3554
+ return /* @__PURE__ */ jsx51(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx51(
3252
3555
  "code",
3253
3556
  {
3254
3557
  className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
3255
3558
  dangerouslySetInnerHTML: { __html: html }
3256
3559
  }
3257
- ) : /* @__PURE__ */ jsx50("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3560
+ ) : /* @__PURE__ */ jsx51("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3258
3561
  }
3259
3562
  function buildIslandRenderers(opts) {
3260
3563
  const renderers = {};
@@ -3268,7 +3571,7 @@ function buildIslandRenderers(opts) {
3268
3571
  }
3269
3572
 
3270
3573
  // src/interactive/ReportInteractiveIsland.tsx
3271
- import { jsx as jsx51 } from "react/jsx-runtime";
3574
+ import { jsx as jsx52 } from "react/jsx-runtime";
3272
3575
  function ReportInteractiveIsland({
3273
3576
  report,
3274
3577
  title,
@@ -3282,7 +3585,7 @@ function ReportInteractiveIsland({
3282
3585
  () => buildIslandRenderers({ syntaxHighlighting, mermaid }),
3283
3586
  [syntaxHighlighting, mermaid]
3284
3587
  );
3285
- return /* @__PURE__ */ jsx51(
3588
+ return /* @__PURE__ */ jsx52(
3286
3589
  ReportInteractive,
3287
3590
  {
3288
3591
  report,