@tonyclaw/agent-inspector 2.0.30 → 2.0.32

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.
Files changed (41) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-BDzfRSt1.js → CompareDrawer-Dgi0hhg5.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-4dG0nLRp.js +115 -0
  4. package/.output/public/assets/{ReplayDialog-p-5TKg75.js → ReplayDialog-BL6BwDuI.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-G0dV8-D_.js → RequestAnatomy-DZMmiIiD.js} +1 -1
  6. package/.output/public/assets/{ResponseView-D2wE6lD-.js → ResponseView-DJLOiTYq.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-D8JRK-j_.js → StreamingChunkSequence--SxZ5cxc.js} +1 -1
  8. package/.output/public/assets/_sessionId-C4z6gu9i.js +1 -0
  9. package/.output/public/assets/index-Drpb2qR5.js +1 -0
  10. package/.output/public/assets/index-fUUi8iQF.css +1 -0
  11. package/.output/public/assets/{main-XHHZsOBK.js → main-CbRIHhJ5.js} +2 -2
  12. package/.output/server/_libs/lucide-react.mjs +160 -135
  13. package/.output/server/{_sessionId-CK9QEhkB.mjs → _sessionId-DNfumR8F.mjs} +2 -2
  14. package/.output/server/_ssr/{CompareDrawer-BJVPFMIx.mjs → CompareDrawer-CzgjhnUa.mjs} +3 -3
  15. package/.output/server/_ssr/{ProxyViewerContainer-DhbmJ2zj.mjs → ProxyViewerContainer-BqOcZ7en.mjs} +737 -17
  16. package/.output/server/_ssr/{ReplayDialog-DXRj95Gj.mjs → ReplayDialog-DmEknIL8.mjs} +4 -4
  17. package/.output/server/_ssr/{RequestAnatomy-CrYJTXdJ.mjs → RequestAnatomy-DNoiMudY.mjs} +3 -3
  18. package/.output/server/_ssr/{ResponseView-4ESqSITr.mjs → ResponseView-C_cRrleT.mjs} +3 -3
  19. package/.output/server/_ssr/{StreamingChunkSequence-Czdko5n_.mjs → StreamingChunkSequence-DHZ9Q_dL.mjs} +3 -3
  20. package/.output/server/_ssr/{index-bei0I7qL.mjs → index-coYS9XyS.mjs} +2 -2
  21. package/.output/server/_ssr/index.mjs +2 -2
  22. package/.output/server/_ssr/{router-sQh4Gk8J.mjs → router-DUb5lKw1.mjs} +174 -40
  23. package/.output/server/{_tanstack-start-manifest_v-C0fdSWnA.mjs → _tanstack-start-manifest_v-xcG1o8Vt.mjs} +1 -1
  24. package/.output/server/index.mjs +60 -60
  25. package/package.json +1 -1
  26. package/src/components/ProxyViewer.tsx +9 -2
  27. package/src/components/groups/GroupsDialog.tsx +945 -0
  28. package/src/lib/groupContract.ts +24 -2
  29. package/src/lib/runContract.ts +2 -0
  30. package/src/lib/useGroupEvidence.ts +33 -0
  31. package/src/lib/useGroups.ts +28 -0
  32. package/src/mcp/server.ts +20 -1
  33. package/src/mcp/toolHandlers.ts +22 -0
  34. package/src/proxy/groupEvidenceExporter.ts +13 -0
  35. package/src/proxy/groupStore.ts +52 -2
  36. package/src/routes/api/groups.$groupId.evidence.ts +14 -2
  37. package/src/routes/api/groups.$groupId.ts +38 -1
  38. package/.output/public/assets/ProxyViewerContainer-NtOD8Ex_.js +0 -115
  39. package/.output/public/assets/_sessionId-zimzVrJE.js +0 -1
  40. package/.output/public/assets/index-Cv5vPgpr.js +0 -1
  41. package/.output/public/assets/index-CwlHPmgL.css +0 -1
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, d as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, j as createPendingProviderTestResults, k as ProviderTestResultsSchema, l as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, n as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, h as providerHasContextMetadata, i as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, o as resolveProviderContextWindow, K as KnowledgeCandidateSchema, f as stripClaudeCodeBillingHeader, q as isPlainRecord } from "./router-sQh4Gk8J.mjs";
2
+ import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, v as packageJson, h as GroupEvidenceExportResultSchema, i as DeleteInspectorGroupResponseSchema, d as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, l as createPendingProviderTestResults, n as ProviderTestResultsSchema, o as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, q as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, j as providerHasContextMetadata, k as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, t as resolveProviderContextWindow, K as KnowledgeCandidateSchema, f as stripClaudeCodeBillingHeader, u as isPlainRecord, G as GroupEvidenceReadResponseSchema$1, I as InspectorGroupsListResponseSchema } from "./router-DUb5lKw1.mjs";
3
3
  import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
4
4
  import { J as JSZip } from "../_libs/jszip.mjs";
5
5
  import { c as clsx } from "../_libs/clsx.mjs";
@@ -9,12 +9,12 @@ import { R as Root, T as Trigger$2, C as Content, a as Close, b as Title, P as P
9
9
  import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
10
10
  import { u as useWindowVirtualizer, a as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
11
11
  import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
12
- import { C as Check, X, P as Plus, D as Download, S as Settings, A as ArrowLeft, a as Copy, b as ChevronDown, U as Upload, c as Scan, d as CircleAlert, T as Terminal, e as ChevronUp, E as EyeOff, f as Eye, g as ExternalLink, R as RotateCw, h as Clock, i as ChevronRight, j as Pencil, k as Trash2, L as LoaderCircle, l as ArrowUpRight, m as ArrowDownRight, n as User, M as MessageSquare, Z as Zap, W as Wrench, o as TriangleAlert, B as Brain, p as Minus, q as CircleCheckBig, r as CircleX, s as ShieldCheck, t as RefreshCw, u as Save, F as FileSearch, v as CircleCheck, w as CloudUpload, O as OctagonAlert, x as Radio, G as Gauge, y as Globe, z as FileTerminal, H as ChevronsUp, I as ChevronsDown, J as FileDiff, K as History, N as RotateCcw, Q as Search, V as GitCompareArrows, Y as CircleQuestionMark, _ as Server, $ as Lock, a0 as Wifi, a1 as WifiOff, a2 as ArrowUp, a3 as ArrowDown, a4 as Ellipsis, a5 as CodeXml, a6 as Blocks, a7 as MousePointerClick, a8 as FileText, a9 as Rows3, aa as Columns2 } from "../_libs/lucide-react.mjs";
12
+ import { C as Check, X, P as Plus, D as Download, L as Layers, a as LoaderCircle, R as RefreshCw, S as Settings, A as ArrowLeft, b as Copy, c as ChevronDown, T as Trash2, U as Upload, d as Scan, e as CircleAlert, f as Terminal, g as ChevronUp, E as EyeOff, h as Eye, i as ExternalLink, j as RotateCw, k as Clock, l as ChevronRight, m as Pencil, n as ArrowUpRight, o as ArrowDownRight, p as User, M as MessageSquare, Z as Zap, W as Wrench, q as TriangleAlert, B as Brain, r as Minus, s as CircleCheckBig, t as CircleX, u as ShieldCheck, v as Save, F as FileSearch, w as CircleCheck, x as CloudUpload, O as OctagonAlert, y as Radio, G as Gauge, z as Globe, H as FileTerminal, I as ChevronsUp, J as ChevronsDown, K as FileDiff, N as History, Q as RotateCcw, V as Search, Y as GitCompareArrows, _ as CircleQuestionMark, $ as Server, a0 as Lock, a1 as Wifi, a2 as WifiOff, a3 as ArrowUp, a4 as ArrowDown, a5 as Ellipsis, a6 as CodeXml, a7 as Blocks, a8 as MousePointerClick, a9 as FileText, aa as Rows3, ab as Columns2 } from "../_libs/lucide-react.mjs";
13
13
  import { M as Markdown } from "../_libs/react-markdown.mjs";
14
14
  import { u as union, d as object, a as array, l as literal, b as string, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
15
15
  import { P as Provider, R as Root3, T as Trigger$1, a as Portal$1, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
16
- import { R as Root2$1, L as List, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
17
16
  import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
17
+ import { R as Root2$1, L as List, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
18
18
  import { R as Root$1, C as CollapsibleContent$1, a as CollapsibleTrigger$1 } from "../_libs/radix-ui__react-collapsible.mjs";
19
19
  import { R as Root$2, V as Viewport$1, C as Corner, S as ScrollAreaScrollbar, a as ScrollAreaThumb } from "../_libs/radix-ui__react-scroll-area.mjs";
20
20
  const ApiErrorSchema = object({
@@ -414,7 +414,7 @@ async function exportLogsAsZip(logs, mode = "redacted") {
414
414
  URL.revokeObjectURL(url);
415
415
  return { ok: true };
416
416
  }
417
- function formatTimestamp(iso, format) {
417
+ function formatTimestamp$1(iso, format) {
418
418
  switch (format) {
419
419
  case "full":
420
420
  return iso;
@@ -427,7 +427,7 @@ function formatTimestamp(iso, format) {
427
427
  }
428
428
  }
429
429
  function formatTimestampRange(startedAt, endedAt, format) {
430
- return `${formatTimestamp(startedAt, format)} - ${formatTimestamp(endedAt, format)}`;
430
+ return `${formatTimestamp$1(startedAt, format)} - ${formatTimestamp$1(endedAt, format)}`;
431
431
  }
432
432
  function cn(...inputs) {
433
433
  return twMerge(clsx(inputs));
@@ -515,10 +515,6 @@ function useProviders() {
515
515
  mutate: response.mutate
516
516
  };
517
517
  }
518
- const version = "2.0.30";
519
- const packageJson = {
520
- version
521
- };
522
518
  const badgeVariants = cva(
523
519
  "inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
524
520
  {
@@ -1576,19 +1572,19 @@ function useCopyFeedback(text) {
1576
1572
  return { copied, copy };
1577
1573
  }
1578
1574
  const LazyCompareDrawer = reactExports.lazy(
1579
- () => import("./CompareDrawer-BJVPFMIx.mjs").then((m) => ({ default: m.CompareDrawer }))
1575
+ () => import("./CompareDrawer-CzgjhnUa.mjs").then((m) => ({ default: m.CompareDrawer }))
1580
1576
  );
1581
1577
  const LazyReplayDialog = reactExports.lazy(
1582
- () => import("./ReplayDialog-DXRj95Gj.mjs").then((m) => ({ default: m.ReplayDialog }))
1578
+ () => import("./ReplayDialog-DmEknIL8.mjs").then((m) => ({ default: m.ReplayDialog }))
1583
1579
  );
1584
1580
  const LazyRequestAnatomy = reactExports.lazy(
1585
- () => import("./RequestAnatomy-CrYJTXdJ.mjs").then((m) => ({ default: m.RequestAnatomy }))
1581
+ () => import("./RequestAnatomy-DNoiMudY.mjs").then((m) => ({ default: m.RequestAnatomy }))
1586
1582
  );
1587
1583
  const LazyResponseView = reactExports.lazy(
1588
- () => import("./ResponseView-4ESqSITr.mjs").then((m) => ({ default: m.ResponseView }))
1584
+ () => import("./ResponseView-C_cRrleT.mjs").then((m) => ({ default: m.ResponseView }))
1589
1585
  );
1590
1586
  const LazyStreamingChunkSequence = reactExports.lazy(
1591
- () => import("./StreamingChunkSequence-Czdko5n_.mjs").then((m) => ({
1587
+ () => import("./StreamingChunkSequence-DHZ9Q_dL.mjs").then((m) => ({
1592
1588
  default: m.StreamingChunkSequence
1593
1589
  }))
1594
1590
  );
@@ -2059,7 +2055,7 @@ const LogEntryHeader = reactExports.memo(function({
2059
2055
  ] }),
2060
2056
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
2061
2057
  /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
2062
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", title: log.timestamp, children: formatTimestamp(log.timestamp, timeDisplayFormat) })
2058
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", title: log.timestamp, children: formatTimestamp$1(log.timestamp, timeDisplayFormat) })
2063
2059
  ] }),
2064
2060
  log.model !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2065
2061
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderLogo, { provider: detectProvider(log.model), className: "size-4" }) }) }),
@@ -5431,6 +5427,723 @@ function SelectScrollDownButton({
5431
5427
  }
5432
5428
  );
5433
5429
  }
5430
+ function evidenceKey(group) {
5431
+ if (group === null || group.evidence === null) return null;
5432
+ return `/api/groups/${encodeURIComponent(group.id)}/evidence`;
5433
+ }
5434
+ function useGroupEvidence(group) {
5435
+ const response = useSWR(evidenceKey(group), (url) => fetchJson(url, GroupEvidenceReadResponseSchema$1));
5436
+ return {
5437
+ evidenceResponse: response.data ?? null,
5438
+ isLoading: response.isLoading,
5439
+ error: response.error,
5440
+ mutate: response.mutate
5441
+ };
5442
+ }
5443
+ function useGroups() {
5444
+ const response = useSWR("/api/groups", (url) => fetchJson(url, InspectorGroupsListResponseSchema));
5445
+ return {
5446
+ groups: response.data?.groups ?? [],
5447
+ isLoading: response.isLoading,
5448
+ error: response.error,
5449
+ mutate: response.mutate
5450
+ };
5451
+ }
5452
+ function groupDeletePath(groupId, deleteEvidence) {
5453
+ const path = `/api/groups/${encodeURIComponent(groupId)}`;
5454
+ return deleteEvidence ? `${path}?deleteEvidence=1` : path;
5455
+ }
5456
+ function summarizeGroup(group) {
5457
+ let completedMembers = 0;
5458
+ let failedMembers = 0;
5459
+ let runningMembers = 0;
5460
+ let missingStatusMembers = 0;
5461
+ for (const member of group.members) {
5462
+ switch (member.status) {
5463
+ case "completed":
5464
+ completedMembers += 1;
5465
+ break;
5466
+ case "failed":
5467
+ case "cancelled":
5468
+ failedMembers += 1;
5469
+ break;
5470
+ case "running":
5471
+ runningMembers += 1;
5472
+ break;
5473
+ case "created":
5474
+ break;
5475
+ case null:
5476
+ missingStatusMembers += 1;
5477
+ break;
5478
+ }
5479
+ }
5480
+ return {
5481
+ memberCount: group.members.length,
5482
+ completedMembers,
5483
+ failedMembers,
5484
+ runningMembers,
5485
+ missingStatusMembers
5486
+ };
5487
+ }
5488
+ function buildGroupMemberRows(group, exportResult) {
5489
+ if (exportResult !== null && exportResult.group.id === group.id) {
5490
+ return exportResult.members.map((exportMember) => ({
5491
+ member: exportMember.member,
5492
+ exportMember
5493
+ }));
5494
+ }
5495
+ return group.members.map((member) => ({ member, exportMember: null }));
5496
+ }
5497
+ function statusClassName(status) {
5498
+ switch (status) {
5499
+ case "completed":
5500
+ return "border-emerald-200 bg-emerald-50 text-emerald-700";
5501
+ case "failed":
5502
+ case "cancelled":
5503
+ return "border-red-200 bg-red-50 text-red-700";
5504
+ case "running":
5505
+ return "border-sky-200 bg-sky-50 text-sky-700";
5506
+ case "created":
5507
+ return "border-zinc-200 bg-zinc-50 text-zinc-600";
5508
+ case null:
5509
+ return "border-zinc-200 bg-zinc-50 text-zinc-500";
5510
+ }
5511
+ }
5512
+ function statusLabel(status) {
5513
+ return status ?? "unknown";
5514
+ }
5515
+ function reportStatusClassName(status) {
5516
+ switch (status) {
5517
+ case "PASS":
5518
+ return "border-emerald-200 bg-emerald-50 text-emerald-700";
5519
+ case "FAIL":
5520
+ return "border-red-200 bg-red-50 text-red-700";
5521
+ case "RUNNING":
5522
+ return "border-sky-200 bg-sky-50 text-sky-700";
5523
+ case "UNKNOWN":
5524
+ return "border-zinc-200 bg-zinc-50 text-zinc-600";
5525
+ }
5526
+ }
5527
+ function displayText(value) {
5528
+ if (value === null || value.trim().length === 0) return "-";
5529
+ return value;
5530
+ }
5531
+ function formatNumber(value) {
5532
+ return value.toLocaleString();
5533
+ }
5534
+ function formatMs(value) {
5535
+ if (value === null || value === void 0) return "-";
5536
+ if (value < 1e3) return `${formatNumber(value)} ms`;
5537
+ return `${(value / 1e3).toFixed(1)} s`;
5538
+ }
5539
+ function formatTimestamp(value) {
5540
+ const millis = Date.parse(value);
5541
+ if (!Number.isFinite(millis)) return value;
5542
+ return new Intl.DateTimeFormat(void 0, {
5543
+ month: "short",
5544
+ day: "2-digit",
5545
+ hour: "2-digit",
5546
+ minute: "2-digit",
5547
+ hour12: false
5548
+ }).format(new Date(millis));
5549
+ }
5550
+ function firstNonEmpty(...values) {
5551
+ for (const value of values) {
5552
+ if (value !== null && value.trim().length > 0) return value;
5553
+ }
5554
+ return "-";
5555
+ }
5556
+ function providerModel(member) {
5557
+ const provider = member.provider;
5558
+ const model = member.model;
5559
+ if (provider !== null && provider.length > 0 && model !== null && model.length > 0) {
5560
+ return `${provider} / ${model}`;
5561
+ }
5562
+ return firstNonEmpty(provider, model);
5563
+ }
5564
+ function selectedGroupFrom(groups, selectedGroupId) {
5565
+ if (selectedGroupId !== null) {
5566
+ const selected = groups.find((group) => group.id === selectedGroupId);
5567
+ if (selected !== void 0) return selected;
5568
+ }
5569
+ return groups[0] ?? null;
5570
+ }
5571
+ function latestLog(row) {
5572
+ const logs = row.exportMember?.session?.latestLogs ?? [];
5573
+ return logs[0] ?? null;
5574
+ }
5575
+ function evidenceFor(group, exportResult) {
5576
+ if (exportResult !== null && exportResult.group.id === group.id) return exportResult.evidence;
5577
+ return group.evidence;
5578
+ }
5579
+ function exportSummaryFor(group, exportResult, evidenceResponse) {
5580
+ if (exportResult !== null && exportResult.group.id === group.id) return exportResult.summary;
5581
+ if (evidenceResponse !== null && evidenceResponse.group.id === group.id) {
5582
+ return evidenceResponse.summary;
5583
+ }
5584
+ return null;
5585
+ }
5586
+ function evidenceReportFor(group, exportResult, evidenceResponse) {
5587
+ if (exportResult !== null && exportResult.group.id === group.id) {
5588
+ return exportResult.jenkinsReport;
5589
+ }
5590
+ if (evidenceResponse !== null && evidenceResponse.group.id === group.id) {
5591
+ return evidenceResponse.report;
5592
+ }
5593
+ return null;
5594
+ }
5595
+ function GroupsDialog() {
5596
+ const [open, setOpen] = reactExports.useState(false);
5597
+ const [selectedGroupId, setSelectedGroupId] = reactExports.useState(null);
5598
+ const [exportingGroupId, setExportingGroupId] = reactExports.useState(null);
5599
+ const [exportError, setExportError] = reactExports.useState(null);
5600
+ const [exportResult, setExportResult] = reactExports.useState(null);
5601
+ const [deleteTarget, setDeleteTarget] = reactExports.useState(null);
5602
+ const [deleteEvidence, setDeleteEvidence] = reactExports.useState(false);
5603
+ const [deletingGroupId, setDeletingGroupId] = reactExports.useState(null);
5604
+ const [deleteError, setDeleteError] = reactExports.useState(null);
5605
+ const { groups, isLoading, error, mutate } = useGroups();
5606
+ const selectedGroup = reactExports.useMemo(
5607
+ () => selectedGroupFrom(groups, selectedGroupId),
5608
+ [groups, selectedGroupId]
5609
+ );
5610
+ reactExports.useEffect(() => {
5611
+ if (!open) return;
5612
+ const hasSelected = selectedGroupId !== null && groups.some((group) => group.id === selectedGroupId);
5613
+ if (hasSelected) return;
5614
+ setSelectedGroupId(groups[0]?.id ?? null);
5615
+ }, [groups, open, selectedGroupId]);
5616
+ const selectedExportResult = selectedGroup !== null && exportResult !== null && exportResult.group.id === selectedGroup.id ? exportResult : null;
5617
+ const {
5618
+ evidenceResponse,
5619
+ isLoading: evidenceLoading,
5620
+ error: evidenceError,
5621
+ mutate: mutateEvidence
5622
+ } = useGroupEvidence(selectedGroup);
5623
+ const handleRefresh = reactExports.useCallback(() => {
5624
+ void mutate();
5625
+ }, [mutate]);
5626
+ const handleExport = reactExports.useCallback(
5627
+ async (group) => {
5628
+ setExportingGroupId(group.id);
5629
+ setExportError(null);
5630
+ try {
5631
+ const response = await fetch(`/api/groups/${encodeURIComponent(group.id)}/evidence`, {
5632
+ method: "POST",
5633
+ headers: { "content-type": "application/json" },
5634
+ body: JSON.stringify({ latestLogLimit: 10 })
5635
+ });
5636
+ if (!response.ok) {
5637
+ setExportError(
5638
+ await readApiError(response, `Export failed with status ${String(response.status)}`)
5639
+ );
5640
+ return;
5641
+ }
5642
+ const parsed = await parseJsonResponse$1(response, GroupEvidenceExportResultSchema);
5643
+ setExportResult(parsed);
5644
+ await mutate();
5645
+ await mutateEvidence();
5646
+ } catch (err) {
5647
+ setExportError(err instanceof Error ? err.message : String(err));
5648
+ } finally {
5649
+ setExportingGroupId(null);
5650
+ }
5651
+ },
5652
+ [mutate, mutateEvidence]
5653
+ );
5654
+ const handleRequestDelete = reactExports.useCallback((group) => {
5655
+ setDeleteTarget(group);
5656
+ setDeleteEvidence(false);
5657
+ setDeleteError(null);
5658
+ }, []);
5659
+ const handleDeleteDialogOpenChange = reactExports.useCallback(
5660
+ (nextOpen) => {
5661
+ if (nextOpen || deletingGroupId !== null) return;
5662
+ setDeleteTarget(null);
5663
+ setDeleteEvidence(false);
5664
+ setDeleteError(null);
5665
+ },
5666
+ [deletingGroupId]
5667
+ );
5668
+ const handleDelete = reactExports.useCallback(async () => {
5669
+ const group = deleteTarget;
5670
+ if (group === null) return;
5671
+ setDeletingGroupId(group.id);
5672
+ setDeleteError(null);
5673
+ try {
5674
+ const response = await fetch(groupDeletePath(group.id, deleteEvidence), {
5675
+ method: "DELETE"
5676
+ });
5677
+ if (!response.ok) {
5678
+ setDeleteError(
5679
+ await readApiError(response, `Delete failed with status ${String(response.status)}`)
5680
+ );
5681
+ return;
5682
+ }
5683
+ await parseJsonResponse$1(response, DeleteInspectorGroupResponseSchema);
5684
+ setExportResult(
5685
+ (current) => current !== null && current.group.id === group.id ? null : current
5686
+ );
5687
+ setSelectedGroupId((current) => current === group.id ? null : current);
5688
+ setDeleteTarget(null);
5689
+ setDeleteEvidence(false);
5690
+ await mutate();
5691
+ await mutateEvidence();
5692
+ } catch (err) {
5693
+ setDeleteError(err instanceof Error ? err.message : String(err));
5694
+ } finally {
5695
+ setDeletingGroupId(null);
5696
+ }
5697
+ }, [deleteEvidence, deleteTarget, mutate, mutateEvidence]);
5698
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
5699
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Dialog, { open, onOpenChange: setOpen, children: [
5700
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
5701
+ Button,
5702
+ {
5703
+ type: "button",
5704
+ variant: "ghost",
5705
+ size: "icon",
5706
+ className: "relative size-8",
5707
+ "aria-label": "Evaluation groups",
5708
+ title: "Evaluation groups",
5709
+ children: [
5710
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { className: "size-4" }),
5711
+ isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "absolute -right-0.5 -top-0.5 size-3 animate-spin text-muted-foreground" }) : groups.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute -right-1 -top-1 min-w-4 rounded-full bg-primary px-1 text-[10px] leading-4 text-primary-foreground", children: groups.length }) : null,
5712
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Evaluation groups" })
5713
+ ]
5714
+ }
5715
+ ) }),
5716
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "flex max-h-[85vh] max-w-5xl flex-col overflow-hidden", children: [
5717
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogTitle, { className: "flex items-center gap-2 pr-8", children: [
5718
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { className: "size-5 text-muted-foreground" }),
5719
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Groups" }),
5720
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", children: formatNumber(groups.length) })
5721
+ ] }) }),
5722
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-h-0 items-center justify-between gap-3 border-b border-border pb-3", children: [
5723
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Evaluation batches, model runs, and exported evidence packs." }),
5724
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
5725
+ Button,
5726
+ {
5727
+ type: "button",
5728
+ variant: "outline",
5729
+ size: "sm",
5730
+ className: "shrink-0",
5731
+ onClick: handleRefresh,
5732
+ children: [
5733
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "size-3.5" }),
5734
+ "Refresh"
5735
+ ]
5736
+ }
5737
+ )
5738
+ ] }),
5739
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid min-h-0 flex-1 gap-4 md:grid-cols-[260px_minmax(0,1fr)]", children: [
5740
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5741
+ GroupList,
5742
+ {
5743
+ groups,
5744
+ selectedGroupId: selectedGroup?.id ?? null,
5745
+ isLoading,
5746
+ error,
5747
+ onSelect: setSelectedGroupId
5748
+ }
5749
+ ),
5750
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5751
+ GroupDetails,
5752
+ {
5753
+ group: selectedGroup,
5754
+ exportResult: selectedExportResult,
5755
+ evidenceResponse,
5756
+ evidenceLoading,
5757
+ evidenceError,
5758
+ exportError,
5759
+ deleteError,
5760
+ exportingGroupId,
5761
+ deletingGroupId,
5762
+ onExport: handleExport,
5763
+ onRequestDelete: handleRequestDelete
5764
+ }
5765
+ )
5766
+ ] })
5767
+ ] })
5768
+ ] }),
5769
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5770
+ DeleteGroupDialog,
5771
+ {
5772
+ group: deleteTarget,
5773
+ open: deleteTarget !== null,
5774
+ deleteEvidence,
5775
+ isDeleting: deleteTarget !== null && deletingGroupId === deleteTarget.id,
5776
+ error: deleteError,
5777
+ onDeleteEvidenceChange: setDeleteEvidence,
5778
+ onOpenChange: handleDeleteDialogOpenChange,
5779
+ onConfirm: () => void handleDelete()
5780
+ }
5781
+ )
5782
+ ] });
5783
+ }
5784
+ function GroupList({
5785
+ groups,
5786
+ selectedGroupId,
5787
+ isLoading,
5788
+ error,
5789
+ onSelect
5790
+ }) {
5791
+ if (isLoading) {
5792
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-h-48 items-center justify-center rounded-md border border-dashed border-border text-xs text-muted-foreground", children: "Loading groups..." });
5793
+ }
5794
+ if (error !== void 0) {
5795
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700", children: error.message });
5796
+ }
5797
+ if (groups.length === 0) {
5798
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-dashed border-border px-3 py-8 text-center text-xs text-muted-foreground", children: "No groups yet." });
5799
+ }
5800
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-0 overflow-y-auto pr-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: groups.map((group) => {
5801
+ const summary = summarizeGroup(group);
5802
+ const selected = selectedGroupId === group.id;
5803
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
5804
+ "button",
5805
+ {
5806
+ type: "button",
5807
+ onClick: () => onSelect(group.id),
5808
+ className: cn(
5809
+ "w-full rounded-md border px-3 py-2 text-left text-xs transition-colors",
5810
+ selected ? "border-primary bg-primary/5" : "border-border bg-background hover:bg-muted/50"
5811
+ ),
5812
+ children: [
5813
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center justify-between gap-2", children: [
5814
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate text-sm font-medium", children: group.title }),
5815
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: statusClassName(group.status), children: statusLabel(group.status) })
5816
+ ] }),
5817
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex items-center gap-2 text-muted-foreground", children: [
5818
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
5819
+ summary.memberCount,
5820
+ " sessions"
5821
+ ] }),
5822
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: formatTimestamp(group.updatedAt) })
5823
+ ] })
5824
+ ]
5825
+ },
5826
+ group.id
5827
+ );
5828
+ }) }) });
5829
+ }
5830
+ function GroupDetails({
5831
+ group,
5832
+ exportResult,
5833
+ evidenceResponse,
5834
+ evidenceLoading,
5835
+ evidenceError,
5836
+ exportError,
5837
+ deleteError,
5838
+ exportingGroupId,
5839
+ deletingGroupId,
5840
+ onExport,
5841
+ onRequestDelete
5842
+ }) {
5843
+ if (group === null) {
5844
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-h-48 items-center justify-center rounded-md border border-dashed border-border text-xs text-muted-foreground", children: "Select a group to inspect." });
5845
+ }
5846
+ const summary = summarizeGroup(group);
5847
+ const exportedSummary = exportSummaryFor(group, exportResult, evidenceResponse);
5848
+ const evidenceReport = evidenceReportFor(group, exportResult, evidenceResponse);
5849
+ const evidence = evidenceFor(group, exportResult);
5850
+ const rows = buildGroupMemberRows(group, exportResult);
5851
+ const isExporting = exportingGroupId === group.id;
5852
+ const isDeleting = deletingGroupId === group.id;
5853
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-0 overflow-y-auto pr-1", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
5854
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", children: [
5855
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 space-y-1", children: [
5856
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [
5857
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "min-w-0 truncate text-base font-semibold", children: group.title }),
5858
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: statusClassName(group.status), children: statusLabel(group.status) }),
5859
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", children: group.kind })
5860
+ ] }),
5861
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-muted-foreground", children: [
5862
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: displayText(group.project) }),
5863
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
5864
+ "updated ",
5865
+ formatTimestamp(group.updatedAt)
5866
+ ] })
5867
+ ] })
5868
+ ] }),
5869
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
5870
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5871
+ Button,
5872
+ {
5873
+ type: "button",
5874
+ variant: "outline",
5875
+ size: "icon",
5876
+ className: "size-8 text-red-600 hover:text-red-700",
5877
+ "aria-label": "Delete group",
5878
+ title: "Delete group",
5879
+ disabled: isDeleting,
5880
+ onClick: () => onRequestDelete(group),
5881
+ children: isDeleting ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" })
5882
+ }
5883
+ ),
5884
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
5885
+ Button,
5886
+ {
5887
+ type: "button",
5888
+ variant: "default",
5889
+ size: "sm",
5890
+ className: "shrink-0",
5891
+ disabled: isExporting || isDeleting,
5892
+ onClick: () => void onExport(group),
5893
+ children: [
5894
+ isExporting ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3.5" }),
5895
+ "Export evidence"
5896
+ ]
5897
+ }
5898
+ )
5899
+ ] })
5900
+ ] }),
5901
+ group.task !== null && group.task.trim().length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "rounded-md border border-border bg-muted/20 px-3 py-2 text-xs text-muted-foreground", children: group.task }),
5902
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2 sm:grid-cols-4", children: [
5903
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Members", value: summary.memberCount }),
5904
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Done", value: summary.completedMembers }),
5905
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Failed", value: summary.failedMembers }),
5906
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Running", value: summary.runningMembers })
5907
+ ] }),
5908
+ exportedSummary !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2 sm:grid-cols-4", children: [
5909
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Requests", value: exportedSummary.requestCount }),
5910
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Errors", value: exportedSummary.errorCount }),
5911
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Tokens", value: exportedSummary.tokenUsage.total }),
5912
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SummaryStat, { label: "Missing", value: exportedSummary.missingSessions })
5913
+ ] }),
5914
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5915
+ EvidenceReportCard,
5916
+ {
5917
+ report: evidenceReport,
5918
+ loading: evidenceLoading,
5919
+ error: evidenceError,
5920
+ hasEvidence: evidence !== null
5921
+ }
5922
+ ),
5923
+ /* @__PURE__ */ jsxRuntimeExports.jsx(EvidencePaths, { evidence }),
5924
+ exportError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700", children: exportError }),
5925
+ deleteError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700", children: deleteError }),
5926
+ /* @__PURE__ */ jsxRuntimeExports.jsx(MemberTable, { rows })
5927
+ ] }) });
5928
+ }
5929
+ function DeleteGroupDialog({
5930
+ group,
5931
+ open,
5932
+ deleteEvidence,
5933
+ isDeleting,
5934
+ error,
5935
+ onDeleteEvidenceChange,
5936
+ onOpenChange,
5937
+ onConfirm
5938
+ }) {
5939
+ const title = group?.title ?? "this group";
5940
+ const hasEvidence = group?.evidence !== null && group?.evidence !== void 0;
5941
+ const evidencePath = group?.evidence?.markdownPath ?? "No evidence pack exported.";
5942
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "max-w-md", children: [
5943
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogTitle, { className: "flex items-center gap-2 pr-8", children: [
5944
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-5 text-red-600" }),
5945
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Delete group" })
5946
+ ] }) }),
5947
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
5948
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-sm text-muted-foreground", children: [
5949
+ "Delete ",
5950
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium text-foreground", children: title }),
5951
+ "? Session logs and run records stay intact."
5952
+ ] }),
5953
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
5954
+ "label",
5955
+ {
5956
+ className: cn(
5957
+ "flex items-start gap-3 rounded-md border border-border bg-muted/20 px-3 py-2 text-sm",
5958
+ hasEvidence ? "cursor-pointer" : "opacity-60"
5959
+ ),
5960
+ children: [
5961
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5962
+ "input",
5963
+ {
5964
+ type: "checkbox",
5965
+ className: "mt-0.5 size-4",
5966
+ checked: deleteEvidence,
5967
+ disabled: !hasEvidence || isDeleting,
5968
+ onChange: (event) => onDeleteEvidenceChange(event.currentTarget.checked)
5969
+ }
5970
+ ),
5971
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "min-w-0", children: [
5972
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block font-medium", children: "Also delete exported evidence files" }),
5973
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "mt-1 block truncate font-mono text-[11px] text-muted-foreground", children: evidencePath })
5974
+ ] })
5975
+ ]
5976
+ }
5977
+ ),
5978
+ error !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700", children: error })
5979
+ ] }),
5980
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 pt-1", children: [
5981
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5982
+ Button,
5983
+ {
5984
+ type: "button",
5985
+ variant: "outline",
5986
+ size: "sm",
5987
+ disabled: isDeleting,
5988
+ onClick: () => onOpenChange(false),
5989
+ children: "Cancel"
5990
+ }
5991
+ ),
5992
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
5993
+ Button,
5994
+ {
5995
+ type: "button",
5996
+ variant: "destructive",
5997
+ size: "sm",
5998
+ disabled: isDeleting || group === null,
5999
+ onClick: onConfirm,
6000
+ children: [
6001
+ isDeleting ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
6002
+ "Delete"
6003
+ ]
6004
+ }
6005
+ )
6006
+ ] })
6007
+ ] }) });
6008
+ }
6009
+ function SummaryStat({ label, value }) {
6010
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2", children: [
6011
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] font-medium uppercase text-muted-foreground", children: label }),
6012
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 font-mono text-sm font-semibold", children: formatNumber(value) })
6013
+ ] });
6014
+ }
6015
+ function EvidenceReportCard({
6016
+ report,
6017
+ loading,
6018
+ error,
6019
+ hasEvidence
6020
+ }) {
6021
+ const { copied, copy } = useCopyFeedback(report?.markdown ?? null);
6022
+ if (report === null && !loading && error === void 0) return null;
6023
+ if (loading) {
6024
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 rounded-md border border-border bg-muted/20 px-3 py-2 text-xs text-muted-foreground", children: [
6025
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 animate-spin" }),
6026
+ "Loading evidence report..."
6027
+ ] });
6028
+ }
6029
+ if (error !== void 0 && hasEvidence) {
6030
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700", children: [
6031
+ "Failed to load evidence report: ",
6032
+ error.message
6033
+ ] });
6034
+ }
6035
+ if (report === null) return null;
6036
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2", children: [
6037
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center justify-between gap-2", children: [
6038
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
6039
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold", children: "Evidence report" }),
6040
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: reportStatusClassName(report.status), children: report.status })
6041
+ ] }),
6042
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
6043
+ Button,
6044
+ {
6045
+ type: "button",
6046
+ variant: "ghost",
6047
+ size: "icon",
6048
+ className: "size-7 shrink-0",
6049
+ "aria-label": copied ? "Copied evidence report" : "Copy evidence report",
6050
+ onClick: copy,
6051
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
6052
+ }
6053
+ )
6054
+ ] }),
6055
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: report.summary })
6056
+ ] });
6057
+ }
6058
+ function EvidencePaths({ evidence }) {
6059
+ if (evidence === null) {
6060
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-dashed border-border px-3 py-2 text-xs text-muted-foreground", children: "No evidence pack exported yet." });
6061
+ }
6062
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 rounded-md border border-border bg-muted/20 px-3 py-2", children: [
6063
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
6064
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold", children: "Evidence paths" }),
6065
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-muted-foreground", children: formatTimestamp(evidence.exportedAt) })
6066
+ ] }),
6067
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2", children: [
6068
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CopyPathRow, { label: "JSON", value: evidence.jsonPath }),
6069
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CopyPathRow, { label: "Markdown", value: evidence.markdownPath }),
6070
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CopyPathRow, { label: "HTML", value: evidence.htmlPath })
6071
+ ] })
6072
+ ] });
6073
+ }
6074
+ function CopyPathRow({ label, value }) {
6075
+ const { copied, copy } = useCopyFeedback(value);
6076
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2 rounded-md border border-border bg-background px-2 py-1.5", children: [
6077
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-16 shrink-0 text-[11px] font-medium text-muted-foreground", children: label }),
6078
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: value }),
6079
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
6080
+ Button,
6081
+ {
6082
+ type: "button",
6083
+ variant: "ghost",
6084
+ size: "icon",
6085
+ className: "size-7 shrink-0",
6086
+ "aria-label": copied ? `Copied ${label} path` : `Copy ${label} path`,
6087
+ onClick: copy,
6088
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
6089
+ }
6090
+ )
6091
+ ] });
6092
+ }
6093
+ function MemberTable({ rows }) {
6094
+ if (rows.length === 0) {
6095
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-md border border-dashed border-border px-3 py-8 text-center text-xs text-muted-foreground", children: "No sessions attached." });
6096
+ }
6097
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow-hidden rounded-md border border-border", children: [
6098
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-b border-border bg-muted/30 px-3 py-2 text-xs font-semibold", children: "Members" }),
6099
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full min-w-[760px] text-left text-xs", children: [
6100
+ /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { className: "border-b border-border bg-muted/20 text-muted-foreground", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { children: [
6101
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-3 py-2 font-medium", children: "Session" }),
6102
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-3 py-2 font-medium", children: "Provider / Model" }),
6103
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-3 py-2 font-medium", children: "Status" }),
6104
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-3 py-2 font-medium", children: "Requests" }),
6105
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-3 py-2 font-medium", children: "Errors" }),
6106
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-3 py-2 font-medium", children: "First chunk" }),
6107
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-3 py-2 font-medium", children: "Tokens" })
6108
+ ] }) }),
6109
+ /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxRuntimeExports.jsx(MemberRow, { row }, row.member.id)) })
6110
+ ] }) })
6111
+ ] });
6112
+ }
6113
+ function MemberRow({ row }) {
6114
+ const member = row.member;
6115
+ const session = row.exportMember?.session ?? null;
6116
+ const log = latestLog(row);
6117
+ const sessionPath = session?.inspectorPath ?? getSessionPath(member.sessionId);
6118
+ const requests = session?.requestCount ?? null;
6119
+ const errors = session?.errorCount ?? null;
6120
+ const tokens = session?.tokenUsage.total ?? null;
6121
+ const firstChunkMs = log?.firstChunkMs ?? null;
6122
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border last:border-0", children: [
6123
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("td", { className: "max-w-56 px-3 py-2", children: [
6124
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
6125
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
6126
+ "a",
6127
+ {
6128
+ href: sessionPath,
6129
+ target: "_blank",
6130
+ rel: "noreferrer",
6131
+ className: "min-w-0 truncate font-mono text-xs text-primary hover:underline",
6132
+ children: firstNonEmpty(member.label, member.sessionId)
6133
+ }
6134
+ ),
6135
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3 shrink-0 text-muted-foreground" })
6136
+ ] }),
6137
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 truncate text-[11px] text-muted-foreground", children: displayText(member.agent) })
6138
+ ] }),
6139
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "max-w-52 px-3 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block truncate", children: providerModel(member) }) }),
6140
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: statusClassName(member.status), children: statusLabel(member.status) }) }),
6141
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-3 py-2 font-mono", children: requests === null ? "-" : formatNumber(requests) }),
6142
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-3 py-2 font-mono", children: errors === null ? "-" : formatNumber(errors) }),
6143
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-3 py-2 font-mono", children: formatMs(firstChunkMs) }),
6144
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-3 py-2 font-mono", children: tokens === null ? "-" : formatNumber(tokens) })
6145
+ ] });
6146
+ }
5434
6147
  function ClaudeCodeIcon() {
5435
6148
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
5436
6149
  "svg",
@@ -9215,6 +9928,9 @@ function truncateSessionId(id) {
9215
9928
  if (id.length <= 30) return id;
9216
9929
  return `${id.slice(0, 12)}...${id.slice(-12)}`;
9217
9930
  }
9931
+ function shouldShowRawExport(captureMode) {
9932
+ return captureMode === "full";
9933
+ }
9218
9934
  function computeTokenSummary(logs) {
9219
9935
  let totalIn = 0;
9220
9936
  let totalOut = 0;
@@ -9784,6 +10500,7 @@ function ProxyViewer({
9784
10500
  );
9785
10501
  const cacheTrends = reactExports.useMemo(() => computeCacheTrends(groups), [groups]);
9786
10502
  const comparisonPredecessors = reactExports.useMemo(() => buildValidPredecessors(groups), [groups]);
10503
+ const showRawExport = shouldShowRawExport(captureMode);
9787
10504
  const handleCompareWithPrevious = reactExports.useCallback(
9788
10505
  (log) => {
9789
10506
  const predecessor = comparisonPredecessors.get(log.id);
@@ -9848,7 +10565,10 @@ function ProxyViewer({
9848
10565
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "max-w-[calc(100vw-7rem)] text-sm font-semibold text-muted-foreground", children: "Local First. Evidence First." }),
9849
10566
  /* @__PURE__ */ jsxRuntimeExports.jsx(McpReadyBadge, {})
9850
10567
  ] }),
9851
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "justify-self-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {}) })
10568
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "justify-self-end flex items-center gap-1", children: [
10569
+ /* @__PURE__ */ jsxRuntimeExports.jsx(GroupsDialog, {}),
10570
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {})
10571
+ ] })
9852
10572
  ] }),
9853
10573
  hasSessionContext && sessionContextScope !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
9854
10574
  SessionContextBar,
@@ -9904,7 +10624,7 @@ function ProxyViewer({
9904
10624
  logs.length !== 1 ? "s" : "",
9905
10625
  totalIn > 0 || totalOut > 0 ? ` - ${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out` : ""
9906
10626
  ] }),
9907
- logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
10627
+ logs.length > 0 && showRawExport && /* @__PURE__ */ jsxRuntimeExports.jsx(
9908
10628
  "button",
9909
10629
  {
9910
10630
  type: "button",